本人想用 Vite+vue3+ts 写一个组件库,想着顺便生成类型文件便于引用该库的项目使用,看了一圈,感觉 vite-plugin-dts 插件很不错,故开始了探索之路

版本

版本
Vue^3.3.4
Vite^4.4.11
TypeScript~5.2.0
vite-plugin-dts^3.6.3
@vue/tsconfig^0.4.0

分析与解决

以下写下了我对于该问题的排查思路,解决办法可直接查看最下面

1.发现现象

当我根据官方文档在项目中引用后,发现生成的类型文件只有 index.d.ts ,这明显是不对的,我的组件和类型文件都没有生成,如下:
在这里插入图片描述
我反复检查了我的 tsconfig.app.json 文件:

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "packages/**/*", "packages/**/*.vue", "packages/**/*.ts", "packages/**/*.tsx"],
  "exclude": ["src/**/__tests__/*", "node_modules"],
  "compilerOptions": {
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

以及 tsconfig.json 文件:

{
  "files": [],
  "references": [
    {
      "path": "./tsconfig.node.json"
    },
    {
      "path": "./tsconfig.app.json"
    }
  ]
}

以及 vite.config.ts 文件:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import dts from 'vite-plugin-dts'
import { resolve } from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    dts(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    outDir: 'statics',
    lib: {
      // Could also be a dictionary or array of multiple entry points
      entry: resolve(__dirname, 'packages/index.ts'),
      name: 'Package',
      // the proper extensions will be added
      fileName: 'index',
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['vue'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})

没有任何问题,且配置文件中内容都是脚手架默认生成的配置,插件官网也没有任何需要修改的地方,但是就是无法生成

2.找到症结

翻阅了 Github 中的issue,虽然类似的问题看见不少,但貌似都不是我这种现象,且类似问题出现的版本都比较低,开发者已在新版进行了修复

当我仔细尝试后发现,不管我在 packages 目录下新建 Vue 文件还是 TS 文件都无法生成,此时感觉并不是无法生成类型文件,感觉更像是 tsconfig 中的 include 作用域并没有生效,这是为什么呢?

翻阅 dts() 相关属性时,我发现了该属性:
在这里插入图片描述
翻译人话就是:指定 tsconfig 文件的路径并去处理 includeexclude

细心的人可能一开始也注意到了——我贴出的 tsconfig 配置的所在文件是 tsconfig.app.json ,不妨设置一下该属性看看?嘿,您猜怎么着,成了!
在这里插入图片描述

既然这样,不妨看看该插件中如何处理的,在该插件的源码中的 plugin.ts 文件中有这么一段:

async buildStart() {
	...
	configPath = tsconfigPath
        ? ensureAbsolute(tsconfigPath, root)
        : ts.findConfigFile(root, ts.sys.fileExists)
    const content = configPath
        ? createParsedCommandLine(ts as any, ts.sys, configPath)
        : undefined
    ...
    ...
    ...
    include = computeGlobs(options.include, content?.raw.include, '**/*')
    exclude = computeGlobs(options.exclude, content?.raw.exclude, 'node_modules/**')
    ...
}

上面代码主要就是用于判断是否获取指定的 tsconfig 中的路径来加载配置文件,既然这样我们去除配置并在 node_modules 中修改下代码打印一下此时的配置内容是什么,打印如下:

{
  options: {
    configFilePath: 'E:/Package/tsconfig.json',
    outDir: undefined
  },
  watchOptions: undefined,
  fileNames: [],
  projectReferences: [
    {
      path: 'E:/Package/tsconfig.node.json',
      originalPath: './tsconfig.node.json',
      prepend: undefined,
      circular: undefined
    },
    {
      path: 'E:/Package/tsconfig.app.json',
      originalPath: './tsconfig.app.json',
      prepend: undefined,
      circular: undefined
    }
  ],
  typeAcquisition: { enable: false, include: [], exclude: [] },
  // 注意这一行
  raw: { files: [], references: [ [Object], [Object] ] },
  errors: [],
  wildcardDirectories: {},
  compileOnSave: false,
  vueOptions: { target: 3.3 }
}

好嘛,原因找到了,这里插件读取的是 tsconfig.json 中的数据,并没有 includeexclude 相关配置,因此无法生成对应目录下的类型文件

3.原因探明

因为今年才开始从 vue-cli 转向 vite ,所以我深刻的记得原来的 Vite 项目中是没有 tsconfig.app.json 文件的,但是 Vite 打包是没有问题的,那说明它是可以正常加载到该配置文件的

一开始我以为是 Vite 的锅,但一想不对,Vite 这么大的体量不应该出现这个问题,这样岂不是相关插件都会受到相关影响吗

最终我把目标瞄向了 Vue,毕竟是基于 Vite 生成的 Vue 项目模板,那会不会是 Vue 模板生成的问题呢?

create-vue 项目的issue中注意到了这么一点:
在这里插入图片描述
根据这里提供的链接跳转到 tsconfig 对应的issue 发现在0.3版本之后将配置文件进行了拆分:
在这里插入图片描述
这就能解释 tsconfig.app.json 文件是如何出现的了,基于此基本可以定位是属于该改动导致的插件读取的 tsconfig 配置不正确导致无法正常的生成对应的类型文件

4.解决办法

很难说这个应该是 create-vue 的问题还是 vite-plugin-dts 插件的问题,但解决办法也是很显然的,只要给当前插件指定正确的 tsconfig 配置文件即可,即:

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    dts({
    	// 指定 tsconfig 文件
        tsconfigPath: 'tsconfig.app.json'
    }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
})
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐