Vite 打包项目(三) : 打包 TS 类型声明文件

8,642 阅读3分钟

Vite 打包 TS 类型声明文件目前没有可用的 plugin。有人在 issue 中提出希望 Vite 内部支持在库模式打包时导出声明文件,但 Vite 官方表示不希望因此增加维护的负担和结构的复杂性

因此在 Vite 开发中,我们要想一些其他办法来生成声明文件

必要的配置

不管使用什么方法,生成类型声明文件,最根本的还是通过 TypeScript 本身的特性及配置项去提取 .d.ts 文件,再使用一些手段将文件写到打包路径下

需要设置 declaration, emitDeclarationOnlytrue

新建 tsconfig.types.json 文件,写入以下内容,这个配置文件仅用来提取类型声明文件时使用

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "declaration": true,
    "emitDeclarationOnly": true,
  },
  "include": ["src"]
}

几种思路

  1. 使用 ts compiler 编译出来
  2. 使用 Rollup.js 生成 .d.ts 文件
  3. 使用 Gulp.js 生成 .d.ts 文件
  4. 使用 ts-morph 生成 .d.ts 文件 最终选择了使用 ts-morph 生成 .d.ts 文件

原因在于 Rollup.jsGulp.js 都是很好的、相当强大的工具,但是正因为其五脏俱全,我们不选择它

我们要做的事情就是提取类型声明文件,没有其他,而 ts-morph 只做了这件事,很好的满足这一点

使用 ts compile 直接编译

tsc -p ./tsconfig.types.json'

直接使用 tsc 无疑是一种很便捷的方式。但是会带来一个问题是如果你在打包时改变了项目的目录结构,或者想要做到按需引入,这个时候 tsc 就没法满足我们的需求了。

与此同时,我们没有机会体验工程化带来的便利。 比如,我们可能需要在项目 package.json 下新加

build:types: "tsc -p ./tsconfig.types.json"

这样以便其能够参与到项目的持续构建、集成中去

使用 Rollup.js 生成 .d.ts 文件

在开发 rollup 插件时,我们主要借助一些插件:如 rollup-plugin-typescript2rollup-plugin-dts 等,来实现根据源码生成 .d.ts 声明文件

yarn add rollup-plugin-typescript2 typescript tslib --dev
// rollup.config.js
import typescript from 'rollup-plugin-typescript2'

...
export default {
  input: './main.ts',
  plugins: [
    typescript({ 
      compilerOptions: {
        declaration: true,
        emitDeclarationOnly: true
      }
    })
  ]
}

经过尝试,vite 内置 rollup,但是其 rollupOptions 配置项只支持单配置项。在前面文章中我们已经使用 rollup 来实现库按需打包。所以没法使用 rollup 插件

使用 Gulp.js 生成 .d.ts 文件

Gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务。Gulp.js 是基于 Node.js 构建的,利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作

yarn global add gulp-cli

then

yarn add gulp@4 --dev
yarn add gulp-typescript typescript --dev
const gulp = require('gulp');
const ts = require('gulp-typescript');

...
gulp.task('declaration', function () {
  const tsProject = ts.createProject('tsconfig.types.json');
  return tsProject.src().pipe(tsProject()).pipe(gulp.dest('lib/'));
});

exports.default = gulp.series('cjs', 'es', 'declaration');

使用 ts-morph 生成 .d.ts 文件

ts-morph 是一个 TypeScript 编译器 API 包装器。提供一种更简单的方式来以编程方式导航和操作 TypeScript 和 JavaScript 代码

直接开撸,新建 buildTypes.ts 文件

const path = require('path')
// https://www.npmjs.com/package/ts-morph
const { Project } = require('ts-morph')

const outDir = 'lib/es'

const main = async () => {
  // 这部分内容具体可以查阅 ts-morph 的文档
  // 这里仅需要知道这是用来处理 ts 文件并生成类型声明文件即可
  const project = new Project({
    tsConfigFilePath: path.resolve(__dirname, 'tsconfig.types.json'),
  })

  const diagnostics = project.getPreEmitDiagnostics()

  // 输出解析过程中的错误信息
  console.log(project.formatDiagnosticsWithColorAndContext(diagnostics))

  // 将解析完的文件写到打包路径
  project.emit()

  // 将解析完的文件写到内存中,便于读取文件路径
  const result = project.emitToMemory()

  // 将文件路径打印到控制台
  console.log(
    result._files.map((file) => file.filePath.slice(file.filePath.indexOf(outDir)))
  )
  console.info(
    `\nSuccess emit declaration file!\n
    The project has generate ${result._files.length} typescript declaration files\n`
  )
}

main()

在项目 packages.json 中新增以下配置

  "types": "lib/es/index.d.ts",
  "scripts": {
    "build:types": "ts-node buildTypes.ts",
  }

这样,我们就可以在引用项目时,根据引用进行对应的类型提示了

参考文档

Rollup.js 官方文档
Gulp.js 中文官方文档
rollup-plugin-typescript2
rollup-plugin-dts
ts-morph