airi 构建工具链实践:从 tsup 迁移到 tsdown 的完整指南
本篇基于 airi 仓库内置的迁移指南 guide-migrate-from-tsup.md,系统讲解如何把 TypeScript 库的打包工具从 tsup 切换到基于 Rolldown 的 tsdown。读完你可以掌握 tsdown-migrate 自动迁移工具的使用方式、两者的默认值与选项差异、常见配置迁移模式,并能参考 airi 这个大型 pnpm + Turbo monorepo 中 30 个包的实际 tsdown 配置,完成一次可落地、可验证的构建工具切换。
概览:为什么可以迁移
迁移指南的开篇给出了核心理由:tsdown 构建在 Rolldown(Rust 实现)之上,而 tsup 基于 esbuild,tsdown 在保持兼容性的同时提供更快的打包速度和更强的能力。这份指南位于仓库的 Agent 技能参考目录 .agents/skills/tsdown/references/guide-migrate-from-tsup.md,是 tsdown 技能文档体系 SKILL.md 中的迁移章节,与 CLI 参考、入门指南 等文档互为补充。
airi 仓库本身正是 tsdown 的用户:根目录 package.json 将 tsdown 作为 catalog 依赖("tsdown": "catalog:"),并以 turbo run build 驱动各包构建;仓库中 packages、plugins、server/packages、services、integrations 等目录下共有 30 个包的 build 脚本直接写为 tsdown。换言之,airi 的库层构建链路已经整体跑在 tsdown 上,本文的迁移路径与仓库现状完全一致。
自动迁移:tsdown-migrate 工具
指南推荐的第一选择是运行自动迁移工具,它会自动改写配置文件。
单包迁移
npx tsdown-migrate
Monorepo 批量迁移
# 使用 glob 模式
npx tsdown-migrate packages/*
# 多个目录
npx tsdown-migrate packages/foo packages/bar
迁移选项
| 选项 | 说明 |
|---|---|
[...dirs] |
要迁移的目录,支持 glob 模式 |
--dry-run / -d |
预览变更而不实际修改文件 |
重要前提:运行迁移前务必先提交(Commit)你的改动,这样出问题时才能用版本控制快速回退。
关键差异:默认值与选项重命名
迁移后行为变化主要来自默认值调整,这是最容易产生“隐性差异”的地方。
默认值变化
| 选项 | tsup | tsdown |
|---|---|---|
format |
['cjs'] |
['esm'] |
clean |
false |
true |
dts |
false |
若 package.json 中存在 types/typings 字段则自动启用 |
target |
需手动指定 | 自动从 package.json 的 engines.node 读取 |
四个变化中影响最大的通常是 format 与 clean:迁移后产物默认 ESM 优先,且输出目录会被默认清理,若你的 CI 或发布流程依赖旧的 CJS 单格式输出,需要在配置中显式补上 format: ['cjs']。
选项重命名
| tsup | tsdown |
|---|---|
outExtension |
outExtensions |
输出文件名差异
对于 IIFE 构建,tsdown 产出 [name].iife.js,而 tsup 常见产出是 [name].global.js。outExtensions 只能自定义扩展名或后缀,无法去掉 .iife 或 .umd 段;如果必须保留旧的 IIFE 文件名,指南给出的做法是通过输出选项覆盖入口文件名:
export default defineConfig({
entry: ['src/index.ts'],
format: ['iife'],
outputOptions: {
entryFileNames: '[name].global.js',
},
})
tsdown 的新特性
Node 协议控制
tsup 没有对应能力,tsdown 新增 nodeProtocol 选项,用于统一 Node.js 内置模块的 node: 前缀:
export default defineConfig({
nodeProtocol: true, // 添加 node: 前缀(fs → node:fs)
nodeProtocol: 'strip', // 移除 node: 前缀(node:fs → fs)
nodeProtocol: false, // 保持原样(默认)
})
更好的 Workspace 支持
在 monorepo 中可以直接用 glob 让一次构建覆盖所有包,无需逐个包配置:
export default defineConfig({
workspace: 'packages/*', // 构建所有匹配的包
})
这一点对 airi 这类把 packages/**、plugins/**、integrations/** 等全部纳入 workspaces 的仓库尤为契合(见根 package.json 的 workspaces 字段)。
迁移检查清单
指南给出的六步清单,建议逐条执行:
- 备份代码 —— 提交所有改动;
- 运行迁移工具 ——
npx tsdown-migrate; - 审查变更 —— 检查被修改的配置文件;
- 更新 scripts —— 把 package.json 中的
tsup改成tsdown; - 测试构建 —— 运行
pnpm build验证(airi 根目录即通过turbo run build触发各包构建); - 调整配置 —— 根据实际产物微调。
常见迁移模式
基础库
迁移前(tsup):
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
})
迁移后(tsdown):
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'], // ESM 现在是默认项
dts: true,
clean: true, // 现在默认开启
})
带自定义 Target
迁移前(tsup):
export default defineConfig({
entry: ['src/index.ts'],
target: 'es2020',
})
迁移后(tsdown):
export default defineConfig({
entry: ['src/index.ts'],
// target 会自动从 package.json 的 engines.node 读取
// 也可以显式覆盖:
target: 'es2020',
})
CLI 构建脚本
迁移前(package.json):
{
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
}
}
迁移后(package.json):
{
"scripts": {
"build": "tsdown",
"dev": "tsdown --watch"
}
}
这正是 airi 仓库中 30 个包当前采用的形式,例如 packages/i18n/package.json、packages/audio/package.json 的 build 脚本均为 tsdown。
airi 仓库中的真实配置对照
结合仓库源码可以看到迁移后的配置实际长什么样,它们与上文差异表一一对应:
-
packages/core-agent/tsdown.config.ts:多入口 +
dts: true,未显式写format——按新默认值即为 ESM 输出:export default defineConfig({ entry: [ 'src/index.ts', 'src/agents/spark-notify/index.ts', ], dts: true, }) -
packages/plugin-sdk/tsdown.config.ts:显式锁定
format: 'esm',并配置了 4 个入口,对应指南中“多入口点”支持项。 -
packages/electron-eventa/tsdown.config.ts:同样是 ESM 单格式 +
dts: true的库包写法。 -
packages/audio/tsdown.config.ts:展示了对象形式入口、
unbundle: true(保留目录结构)与external白名单的组合用法:export default defineConfig({ entry: { 'index': 'src/index.ts', 'audio-context/index': 'src/audio-context/index.ts', 'audio-context/processor.worklet': 'src/audio-context/processor.worklet.ts', 'encoding/index': 'src/encoding/index.ts', }, unbundle: true, external: [ '@alexanderolsen/libsamplerate-js/dist/libsamplerate.worklet.js?worker&url', './processor.worklet?worker&url', ], })注意该配置没有
dts: true——是否生成声明文件在 airi 各包间是按需开启的,这与指南中“dts 默认依据 package.json 是否有types/typings字段自动启用”的规则一致。
这些配置与 CLI 参考 中的 --dts、--unbundle、--format 等开关可以互相印证:CLI 标志与配置项一一对应,且 CLI 优先级更高。
功能兼容性
已支持的 tsup 特性
指南确认以下 tsup 能力在 tsdown 中均可用:
- 多入口(Multiple entry points)
- 多格式输出(ESM、CJS、IIFE、UMD)
- TypeScript 声明文件
- Source maps
- 压缩(Minification)
- Watch 模式
- External 依赖
- Tree shaking
- Shims
- 插件(Rollup 兼容)
暂缺特性
部分 tsup 特性尚未提供。指南建议到 tsdown 项目的 Issue 跟踪状态并提需求(此处不贴外部链接,可查 guide-migrate-from-tsup.md 原文获取入口)。
故障排查
迁移后构建失败
- 检查 Node.js 版本 —— 运行 tsdown 本身要求 Node.js 22.18.0+(仅构建时要求);产物仍可通过
target指向更低的 Node 版本。若要支持 Node.js 18 / 20,推荐在 CI 中用 Node.js 22+ 构建,再把产物(或打包后的 tarball)放到低版本 Node 上验证。 - 安装 TypeScript —— 生成 DTS 时必需。
- 复查配置变更 —— 确认
format与各选项正确。 - 检查依赖 —— 确认所有依赖已安装。
产物不同
- 格式顺序 —— tsdown 默认 ESM 优先;
- Clean 行为 —— tsdown 默认清理 outDir;
- Target —— tsdown 会从 package.json 自动检测。
性能问题
tsdown 理应比 tsup 更快,如果不符合预期,指南给出三个方向:
- 为更快的 DTS 生成启用
isolatedDeclarations; - 检查是否有大型依赖被意外打包;
- 按需使用
skipNodeModulesBundle。
资源与致谢
本指南是 tsdown 文档的一部分,完整的选项与 CLI 参考可在仓库内查阅:入门指南、CLI 参考、技能索引。tsdown 大量借鉴了 tsup 并吸收了其部分代码库,指南最后向 tsup 作者及社区致谢。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00