Make tsyringe decorators works with Vite

449 views Asked by At

I am writing a Vue application and I want to use tsyringe. Currently I am stuck with an error saying : "Error: TypeInfo not known for "ListService". This happens every time I want to resolve a service that has at least one parameter in its constructor.

Here is my setup :

  • Node v20.10.0 / NPM v10.2.3
  • Vite 5.0.2
  • Vue 3.3.9
  • Tsyringe 4.8.0
  • Typescript 5.3.2

Things I have done :

  • I have imported "reflect-metadata" in my main.js file
  • I have tried resolving a service that doesn't have any parameter in its constructor, and it works without throwing an error !
  • I thought this might have something to do with the decorators as I have had problems with them in the past. Thus I tried the following :
    • Use the @rollup/plugin-typescript plugin (I recalled it solved some problems in another project). It didn't have an effect on my problem
    • Use SWC instead of esbuild, but I couldn't make it work. I may have done it incorrectly...
    • Use @abraham/reflection instead of reflect-metadata
    • Use the @anatine/esbuild-decorators plugin, but it didn't have an effect. I am not sure if I set this up correctly, as there isn't really a doc for this use case.

If you have any idea on how I can make it work, I will gladly take the suggestion, as I am kinda out of ideas. If you have made tsyringe work with vue, I am curious to see how you did (and where I messed up) !

My code (simplified)

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    /* Own settings */
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "paths": {
      "@/*": ["./src/*"]
    },
    "types": ["element-plus/global"]
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

package.json

{
  "type": "module",
  "dependencies": {
    "tsyringe": "^4.8.0",
    "vue": "^3.3.8",
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.5.0",
    "reflect-metadata": "^0.1.13",
    "typescript": "^5.2.2",
    "vite": "^5.0.0",
    "vue-tsc": "^1.8.22"
  }
}

vite.config.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [
    vue({ template: { transformAssetUrls } }),
  ],
});

main.ts

import { createApp } from "vue";
import { container } from "tsyringe";
import { Database, ListService } from "./services";

import App from "./App.vue";

container.registerSingleton(Database); // No dependencies
container.registerSingleton(ListService); // Depends on Database

console.log(container.resolve(Database)); // works;
console.log(container.resolve(ListService)); // fails;

const app = createApp(App);
app.mount("#app");
1

There are 1 answers

0
Billuc On BEST ANSWER

Alright, I got this working !!! @rollup/plugin-typescript was the solution to my problem once again ! My mistake was the order of my plugins. I placed it in the last position and somehow, that didn't work. When I tried again, I placed the plugin right after the vue plugin (second place then), and it worked !!!