A Vite Plugin That Renames v-model to v-mortal — and Why That's a Compile-Time Win
Compile-time directive rewriting shows how teams can adopt internal DSLs or naming conventions without forking Vue or paying a runtime tax. The same AST-plus-MagicString pattern applies to any SFC transformation — linting, injecting defaults, or polyfilling missing props — and keeps the production bundle untouched.
A developer named his custom directive `v-mortal` after his own English name and built a Vite plugin that rewrites it to `v-model` at compile time. The plugin hooks into the `transform` phase with `enforce: 'pre'`, parses each `.vue` file with `vue/compiler-sfc`, walks the template AST to locate every `v-mortal` directive, and overwrites just the directive name using MagicString. Because the substitution happens before Vue's own compiler sees the code, there is no runtime overhead and no need to teach Vue about a new directive.
A companion TypeScript declaration file (`v-mortal.d.ts`) augments Vue's `GlobalDirectives` interface so that IDEs offer autocomplete for `v-mortal` exactly as they do for `v-model`. The whole setup is a compact demonstration of moving syntax sugar into the build toolchain rather than into the framework runtime.
The author explicitly warns against using this in production — it's a teaching example — but the underlying principle generalizes: push complexity into the compiler and toolchain to keep the runtime lean.
The technique decouples developer-facing syntax from framework-facing syntax — a team could use `v-myprop` everywhere and compile it to standard Vue directives, keeping code familiar without framework changes.
AST-based rewriting inside Vite's `transform` hook is underused for SFC conventions; this pattern works for any deterministic template transform (default props, accessibility attributes, lint auto-fixes) and leaves the runtime untouched.
The TypeScript declaration trick is the quiet enabler here: without it, the custom directive would compile correctly but feel broken in the editor, which is where most developers would reject it.
The only substantive exchange questions the plugin's premise: if the build step simply swaps v-mortal back to v-model, using v-model directly seems more straightforward. The reply acknowledges the question without resolving it.
Since v-mortal gets replaced with v-model at build time, why not just use v-model directly?
Good question [look]