27

I followed the vite documentation for using library mode and I am able to produce a working component library.
I created the project with the vue-ts preset and in my component I have defined props with their types, and used some interfaces. But when I build the library, there are no types included.

How do I add types for the final build, either inferred from components automatically or manually with definition files?

More information Here is some more information on my files:
tsconfig.json

{
  "name": "@mneelansh/test-lib",
  "private": false,
  "version": "0.0.2",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview"
  },
  "emitDeclarationOnly": true, // testing
  "declaration": true, // testing
  "main": "./dist/lib.umd.js",
  "module": "./dist/lib.es.js",
  "types": "./dist/main.d.ts",
  "exports": {
    ".": {
      "import": "./dist/lib.es.js",
      "require": "./dist/lib.umd.js"
    },
    "./dist/style.css": "./dist/style.css"
  },
  "files": [
    "dist"
  ],
  "dependencies": {
    "@types/node": "^17.0.25",
    "vue": "^3.2.25"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^2.3.1",
    "typescript": "^4.5.4",
    "vite": "^2.9.5",
    "vue-tsc": "^0.34.7"
  }
}

I added the emitDeclarationOnly and declaration properties but that didn't help.

My vite.config.ts:

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

const path = require("path");

// https://vitejs.dev/config/
export default defineConfig({
  build: {
    lib: {
      entry: path.resolve(__dirname, "src/index.ts"),
      name: "Button",
      fileName: (format) => `lib.${format}.js`,
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
  plugins: [vue()],
});

Neelansh Mathur
  • 516
  • 1
  • 5
  • 10

4 Answers4

27

You can use vite-plugin-dts

import dts from "vite-plugin-dts";

export default defineConfig({
  plugins: [
    dts({
      insertTypesEntry: true,
    }),
  ],
Julien Kode
  • 5,010
  • 21
  • 36
  • 1
    Tried a few things now. This was the only thing that really did the Job, Thanks :) – Mirko t. Aug 26 '22 at 13:59
  • 1
    note, this is slow. build is faster with `rollup` and `rollup-plugin-typescript2`, about 4x faster in my case. there is also [vite-dts](https://github.com/alloc/vite-dts) but its broken. alternative: `npx tsup src/index.ts --format cjs,esm --dts` - faster than rollup, 80% of time is needed for dts – milahu Dec 27 '22 at 17:21
  • 1
    The way this plugin handles types is different from `vue-tsc`, so it may report some strange bugs.... – ipcjs Mar 23 '23 at 09:30
  • 1
    vite-plugin-dts has issue as of now. it doesn't generate types in dev mode and deletes types on every alternative run. – Saurabh Nemade Jun 13 '23 at 17:12
5

Personally I think a nicer way to do it is with vue-tsc:

vue-tsc --declaration --emitDeclarationOnly

See https://stackoverflow.com/a/70343443/398287

BaronVonKaneHoffen
  • 1,902
  • 1
  • 21
  • 29
  • Thanks for the input. Vite-plugin-dts actually works very nicely. Have to try vue-tsc with Vite to see how well it would work – Neelansh Mathur Nov 17 '22 at 10:25
  • @NeelanshMathur does vite-plugin-dts show typescript errors for you? I see it has some advantages but even if i put something like `const a:number = "string"` in my code, it wouldn't show any error. ....which was a problem. – BaronVonKaneHoffen Nov 21 '22 at 12:25
  • 1
    The plugin purely produces declaration files. Errors depend on your environment. If you need an example, you can see my published library https://github.com/neelansh15/vue-connect-wallet – Neelansh Mathur Nov 24 '22 at 19:26
1

Usually with vite and typescript project you need add type checking before build, because vite doesn't do it by himself. Here I'm also using vite-plugin-dts as in post from Julien Kode, and for type checking rollup-plugin-typescript2.

Finally my vite.config.js:

import { defineConfig } from 'vite';
import Vue from '@vitejs/plugin-vue2';
import dts from 'vite-plugin-dts';
import rollupTs from 'rollup-plugin-typescript2';

export default defineConfig({
    plugins: [
        Vue(),
        dts({ insertTypesEntry: true }),
        // only for type checking
        {
            ...rollupTs({
                check: true,
                tsconfig: './tsconfig.json',
                tsconfigOverride: {
                    noEmits: true,
                },
            }),
            // run before build
            enforce: 'pre',
        },
    ],
    build: {
        sourcemap: true,
        lib: {
            entry: './src/index.ts',
            fileName: 'index',
        },
        rollupOptions: {
            // make sure to externalize deps that shouldn't be bundled
            // into your library
            external: [
                'vue',
                'vue-class-component',
                'vue-property-decorator',
                'vuex',
                'vuex-class',
            ],
            output: {
                // Provide global variables to use in the UMD build
                // for externalized deps
                globals: {
                    vue: 'Vue',
                },
            },
        },
    },
});
Joyful
  • 813
  • 8
  • 15
1

You could write your own Vite plugin to leverage tsc at the buildEnd step to accomplish this. As other answers have suggested, you can use the flag emitDeclarationOnly.

See this simple example:

import { type Plugin } from 'vite';
import { exec } from 'child_process';

const dts: Plugin = {
  name: 'dts-generator',
  buildEnd: (error?: Error) => {
    if (!error) {
      return new Promise((res, rej) => {
        exec('tsc --emitDeclarationOnly', (err) => (err ? rej(err) : res()));
      });
    }
  },
};

Then add to your plugins field of your vite config

Regan Karlewicz
  • 176
  • 2
  • 10