Replies: 5 comments 2 replies
|
Oxc (which replaced esbuild in Vite 8) does not support lowering TC39 Stage 3 decorators. Legacy TS decorators ( The workaround from the Vite 8 migration guide: use import babel from "@rolldown/plugin-babel"
export default defineConfig({
plugins: [
babel({
presets: [{
preset: () => ({ plugins: [["@babel/plugin-proposal-decorators", { version: "2023-11" }]] }),
rolldown: { filter: { code: "@" } },
}],
}),
],
})SWC is also an option via |
|
We hit the same issue with Stage 3 decorators after upgrading to Vite 8. Current workaround is import { defineConfig } from "vite";
import babel from "@rolldown/plugin-babel";
function decoratorPreset(options: Record<string, unknown>) {
return {
preset: () => ({
plugins: [["@babel/plugin-proposal-decorators", options]],
}),
rolldown: {
filter: { code: "@" },
},
};
}
export default defineConfig({
plugins: [
babel({
presets: [decoratorPreset({ version: "2023-11" })],
}),
],
});npm install -D @rolldown/plugin-babel @babel/plugin-proposal-decorators
|
|
None of the proposed solutions work when the class' name is used by the decorator: Babels strips names and SWC generates assignment to class' |
|
Downgrade your tsconfig target to es2023 instead of esnext like so Then use esbuild' transform feature as an in-between plugin. Then add it to your plugin list in vite config You can safely re-install esbuild. Don't worry, vite still won't use it, only this plugin does. |
|
To summarize the current state since several partial answers have been posted: The core issue Oxc (which replaced esbuild in Vite 8/Rolldown) does not support lowering TC39 Stage 3 (2023-11 spec) decorators. There's no timeline on the upstream fix: oxc-project/oxc#9170. Legacy TypeScript Working solutions today Option 1 — Babel plugin (recommended for most cases) From the Vite 8 migration guide: npm install -D @rolldown/plugin-babel @babel/plugin-proposal-decorators// vite.config.ts
import { defineConfig } from "vite";
import babel from "@rolldown/plugin-babel";
export default defineConfig({
plugins: [
babel({
presets: [{
preset: () => ({
plugins: [["@babel/plugin-proposal-decorators", { version: "2023-11" }]]
}),
rolldown: { filter: { code: "@" } }, // only run on files with decorators
}],
}),
],
});The Option 2 — esbuild as a pre-transform plugin (handles the class-name issue) If you hit // vite.config.ts
import { transform } from "esbuild";
import type { Plugin } from "vite";
const DECORATOR_RE = /(?:^|\n)\s*@[A-Za-z_$][\w$]*(?:\s|\.|\()/;
const TS_RE = /\.(?:[cm]?ts|tsx)(?:\?|$)/;
function stage3DecoratorTransform(): Plugin {
return {
name: "stage3-decorator-compat",
enforce: "pre",
transform: {
filter: { moduleType: ["js", "jsx", "ts", "tsx"], id: TS_RE, code: DECORATOR_RE },
async handler(code, id) {
const cleanId = id.split("?", 1)[0];
const result = await transform(code, {
loader: cleanId.endsWith("x") ? "tsx" : "ts",
target: "es2023",
format: "esm",
jsx: "preserve",
sourcefile: cleanId,
sourcemap: true,
});
return { code: result.code, map: result.map };
},
},
};
}
export default defineConfig({
plugins: [stage3DecoratorTransform(), /* other plugins */],
});You can Option 3 — Fall back to legacy decorators (not recommended if you're targeting ECMAScript standard) Set Vitest note Both Options 1 and 2 work with Vitest when you extend the same Vite config. Option 2's esbuild approach is synchronous and has no config overlap with Vitest's runner. TL;DR: Use Option 1 unless you're hitting the class-name issue, then use Option 2. Option 4 — SWC as a Rolldown pluginIf you prefer SWC over Babel or esbuild, you can use the SWC plugin for Rolldown to handle the decorator transformation. Example configuration (thanks to @TechQuery): import { defineConfig } from "vite";
import swc from "unplugin-swc";
export default defineConfig({
plugins: [
swc.vite({
jsc: {
parser: {
syntax: "typescript",
decorators: true,
},
transform: {
legacyDecorator: false,
decoratorMetadata: true,
},
},
}),
],
}); |
Uh oh!
There was an error while loading. Please reload this page.
In our organization we're using stage 3 decorators quite a lot: in some internal libraries, but also with this open source library. Our main rationale is to move towards ECMAScript standards instead of keeping legacy TypeScript decorators "alive".
This worked fine with Vite 7:
However, with Vite 8 we now have a big problem: since it's dropping
esbuildin favor of Rolldown (with oxc), we're gettingNow our whole tool chain breaks down — since, we're also using Vitest.
Is there a workaround? Or should we rewrite all our libraries to use the legacy TypeScript decorators instead?
All reactions