Why can't reflect-metadata be used in vite
Asked Answered
Z

3

10
import "reflect-metadata"

function validate(target: any) {
  let paramtypes = Reflect.getMetadata("design:paramtypes", target);
  console.log(paramtypes);  // undefined
}

@validate
class Log {
  constructor(public readonly xx: string) {}
}

Hit me to start the server, and when I opened the webpage, I found that paramtypes was undefined

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["./src"]
}
Zebapda answered 29/7, 2021 at 5:28 Comment(0)
R
14

Vite uses ESBuild which doesn't support "emitDecoratorMetadata" in tsconfig, since ESBuild doesn't have its own type system implemented. Refer to this vitejs/vite#788 for more details on this topic.

However, there are workarounds to this issue. One approach I took was explicitly disabling ESBuild and used SWC instead. You can find more details regarding that on this demo. Here is its vite config file:

import typescript from "@rollup/plugin-typescript";
import swc from "rollup-plugin-swc";

// import typescript from "rollup-plugin-typescript2";

export default defineConfig({
    plugins: [
        swc({
            jsc: {
                parser: {
                    syntax: "typescript",
                    // tsx: true, // If you use react
                    dynamicImport: true,
                    decorators: true,
                },
                target: "es2021",
                transform: {
                    decoratorMetadata: true,
                },
            },
        }),
    ],
    esbuild: false,
});

SWC is a fast alternative to ESBuild, having implemented its own type system, it can emit decorator metadata without any issue.

Rimskykorsakov answered 29/7, 2021 at 6:3 Comment(8)
This solution is feasibleZebapda
It doesn't seem to resolve css/less files correctly.Pacification
@红了樱桃绿了吧唧 I dont see how this relates to css/less files, please elaborate.Rimskykorsakov
Doesn't work on my end, tested using vite 2.9.9.Levity
this does not work anymore/has never workedIndividuate
@Individuate This worked last time I checked my demo repo with vite version 2.4.0. I have no interest in updating my answer for newer vite versions since I don't use or recommend the usage of decorators anymore, so you might need to figure out your own solutions.Rimskykorsakov
This doesn't work: error when starting dev server: TypeError: swc is not a functionSuzette
@Suzette Like I said, I have no interest in updating my answer for newer vite/ts versions. Additionally, with Typescript 5.0, and its implementation for Decorator, reflect-metadata will only work with the legacy decorator implementation --experimentalDecorators. As for the swc plugin, refer to this for its usage.Rimskykorsakov
B
0

Using SWC is feasible solution, but if you want to stay closer to the original setup I've found the right configuration.

It's true that esbuild does not support decorator metadata, but! there is a community plugin for that - @anatine/esbuild-decorators.

I've added it to the optimizeBuild configuration and it Just Works™️.

From my understanding it shouldn't have worked after build (because from the docs vite does not use esbuild when building for prod), but it does work!

Here is an example repo with vite 4 & tsyringe that uses reflect-metadata https://stackblitz.com/edit/vitejs-vite-hzkjj3?file=vite.config.ts

Ballast answered 25/3, 2023 at 11:52 Comment(1)
Thank you for providing this StackBlitz example. Do you know why error TS2322 is thrown in its vite.config.ts file?Necessarian
V
0

If your having issues with vitest and reflect-metadata, there is an easy solution to this by introducing a setup file for the vitest and adding the import 'reflect-metadata'.

vite.config.ts

/// <reference types="vitest" />
import { defineConfig } from 'vite' 

export default defineConfig({
 test: {
  setupFiles: ["./setupFile.ts"],
 },
...rest of your config
})

setupFile.ts

import 'reflect-metadata'

...rest of your setup
Valueless answered 18/4 at 9:59 Comment(2)
This does not address the issue reported by OP. OP refers to the lack of support of emitDecoratorMetadata in esbuild. What you're talking about is how to avoid importing reflect-metadata in every the test file, which comes originally from github.com/inversify/InversifyJS/issues/1189Dollarfish
for me it solved the problem I googled and that the title more or less says.Adapter

© 2022 - 2024 — McMap. All rights reserved.