@ttsc/unplugin

@ttsc/unpluginpackages/unplugin)把 ttsc 插件接进 unplugin 支持的打包器:Vite、Rollup、Rolldown、esbuild、Webpack、Rspack、Next.js、Farm、Bun。当打包器拥有你的构建时,用它在打包器里跑 ttsc 插件(typia 等)。

设计:一个 transform hook

@ttsc/unplugin 的核心是一个 unplugin factory(src/core/index.ts:38),它在每个 TypeScript/JSX 模块上调 ttsc 的 transform,把结果交回打包器:

factory(unpluginFactorysrc/core/index.ts:38):解析一次 raw options、建 per-build transform 缓存、经 vite.configResolved hook 捕获 Vite alias 配置(转发进生成的 tsconfig overlay)。缓存在每次 buildStart 清,避免 watch 重建跨次陈旧。

enforce: "pre" 让 ttsc transform 在打包器自己的 TS 处理前跑。transformInclude + isTransformTargetsrc/core/index.ts:100)排除虚拟模块(NUL 前缀)、.d.tsnode_modules

各打包器适配

src/
├── core/
│   ├── index.ts          # unplugin factory (统一实例 + 各适配器)
│   ├── transform.ts      # transformTtsc + 缓存 (~870 LOC)
│   ├── options.ts        # 选项解析
│   └── tsconfigPaths.ts  # alias -> tsconfig paths overlay
├── vite.ts  rollup.ts  rolldown.ts  esbuild.ts
├── webpack.ts  rspack.ts  next.ts  turbopack.ts  bun.ts  farm.ts

src/index.ts 导出统一 unplugin 实例(带命名适配器 .vite/.rollup/…)与裸 factory。各 per-bundler 入口(@ttsc/unplugin/vite 等)直接 re-export 对应适配器,让 bundler 特定构建精简。

transform 缓存(性能核心)

src/core/transform.ts(~870 LOC)的 TtscCachedProjectTransformtransform.ts:53)按项目输入文件的 SHA-256 哈希缓存整个编译结果:

  • inputHashes:每个项目相对输入路径在 transform 时的 SHA-256。
  • 后续 transform 重哈希项目、与 inputHashes 比,mismatch 触发完整重转换。

注释(transform.ts:48)记录一个真实 bug:两侧必须哈希同一组文件(项目目录 walk),只在一侧 key 编译器的 out-of-walk 输出路径会让缓存每个模块都 miss。

alias 转发

打包器(尤其 Vite/webpack/Rspack)有自己的路径 alias。tsconfigPaths.ts 把它们转成生成 tsconfig 的 paths overlay,让 ttsc 的 transform(建在 tsgo Program 上)也认识这些 alias。TtscTransformAliastransform.ts:35)归一化 Vite 数组 alias 与 webpack/Rspack 对象 alias 成 { find, replacement }

watch 依赖注册

transform hook(src/core/index.ts:65)把插件报告的 dependencies(transform 信封的 dependencies 列表,见 transform 派发)经 this.addWatchFile 注册——type-only 输入变化时让该模块在 watch 模式失效。因为打包器会从自己的模块图里抹掉 type-only import,否则会服务陈旧的生成代码。

与 metro 的关系

@ttsc/unplugin 覆盖 unplugin 生态的打包器;React Native/Expo 用 Metro 打包,unplugin 够不着,由 @ttsc/metro 单独覆盖(见 @ttsc/metro)。两者都依赖 ttsc 包的 TtscCompiler/TtscService

不变量

  • transform 在打包器 TS 处理前跑(enforce: "pre")。
  • 缓存两侧哈希同一文件组(项目 walk),否则每模块 miss。
  • 排除虚拟模块、.d.tsnode_modules
  • type-only 依赖经 addWatchFile 注册,防 watch 陈旧。

维护者提示

  • 加打包器适配 = 加 src/<bundler>.ts re-export 对应适配器,core 逻辑不动。
  • 改缓存 key 时记住两侧文件组对称这个坑。
  • alias 转发是 ttsc transform 认识打包器 alias 的唯一途径,改它影响所有打包器。

接下来