tsup
基于 esbuild 的零配置 TypeScript 库打包工具——最快将 TypeScript 项目打包发布为 npm 包的方案之一。
tsup 是基于 esbuild 的零配置 TypeScript 库打包工具,一条命令即可完成 ESM + CJS 双格式输出和 .d.ts 类型声明生成,是 TypeScript 库打包领域最受欢迎的工具之一。
tsup
基于 esbuild 的零配置 TypeScript 库打包工具——最快将 TypeScript 项目打包发布为 npm 包的方案之一。
技术简介说明
tsup 是由 EGOIST(egoist)开发的一款专注于 TypeScript 库打包的构建工具。它底层基于 esbuild(使用 Go 语言编写的超高速 JavaScript/TypeScript 打包器),为开发者提供了"零配置"的打包体验。tsup 的核心设计目标只有一个:让你用最简单、最快的方式将 TypeScript 库打包并发布到 npm。
与 Webpack、Rollup 这类通用型打包工具不同,tsup 专门为库(library)开发者设计。它开箱即支持 ESM 和 CJS 双格式输出、自动 .d.ts 类型声明文件生成、代码拆分(code splitting)、Tree Shaking、Source Map、Watch 模式等现代库开发所需的全部能力。开发者只需一条命令、甚至不需要任何配置文件,就能完成从 TypeScript 源码到可发布 npm 包的全流程。
tsup 自发布以来迅速成为 TypeScript 库打包领域最受欢迎的工具之一,周下载量超过 560 万次,GitHub 星标超过 11,300 个。包括 shadcn/ui CLI、novel.sh 等知名开源项目都采用了 tsup 作为其构建工具。然而,2025 年下半年,作者宣布该项目不再活跃维护,并推荐使用继任者 tsdown(基于 Rolldown/Rust 构建)。
基本信息
- 官网:https://tsup.egoist.dev/
- GitHub:https://github.com/egoist/tsup
- License:MIT
- 最新版本:v8.5.1(2025 年 11 月 12 日发布)
- 主要维护者/公司:EGOIST(egoist)——独立开发者,同时也是 Vue.js 生态中多个知名工具的作者
- npm 周下载量:约 560 万次(截至 2026 年初)
- GitHub Stars:约 11,300+
- 语言构成:98.8% TypeScript
快速上手
安装
推荐使用本地安装方式(作为开发依赖),不建议全局安装:
# npm
npm install tsup -D
# yarn
yarn add tsup -D
# pnpm(推荐)
pnpm add tsup -D同时需要确保项目中已安装 TypeScript:
pnpm add typescript -D基础配置
tsup 的核心理念是"零配置",但也可以通过配置文件或 CLI 参数自定义行为。
CLI 方式(最简使用):
# 直接打包,输出到 ./dist 目录
npx tsup src/index.ts
# 同时打包多个入口
npx tsup src/index.ts src/cli.ts
# 指定输出格式
npx tsup src/index.ts --format esm,cjs,iife
# 开启类型声明文件生成
npx tsup src/index.ts --dts
# 监听模式
npx tsup src/index.ts --watch
# 代码压缩
npx tsup src/index.ts --minify
# 清理输出目录
npx tsup src/index.ts --clean配置文件方式(推荐用于项目):
在项目根目录创建 tsup.config.ts(也支持 tsup.config.js、tsup.config.cts、tsup.config.mts):
import { defineConfig } from 'tsup'
export default defineConfig({
// 入口文件
entry: ['src/index.ts'],
// 输出格式
format: ['esm', 'cjs'],
// 生成 .d.ts 类型声明文件
dts: true,
// 代码拆分
splitting: true,
// 代码压缩
minify: false,
// Source Map
sourcemap: true,
// 清理输出目录
clean: true,
// 目标环境
target: 'es2020',
// 外部依赖(不打包)
external: ['react', 'react-dom'],
// 输出目录,默认 dist
outDir: 'dist',
})package.json 配置:
{
"name": "my-awesome-lib",
"version": "1.0.0",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.mts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"files": ["dist"],
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
},
"devDependencies": {
"tsup": "^8.5.1",
"typescript": "^5.5.0"
}
}tsconfig.json 推荐配置:
{
"compilerOptions": {
"strict": true,
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"declaration": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}最小示例
以下是一个最简单的完整示例:
src/index.ts:
export function greet(name: string): string {
return `Hello, ${name}!`
}
export const VERSION = '1.0.0'执行打包:
npx tsup src/index.ts --format esm,cjs --dts输出结果(dist/ 目录):
dist/
├── index.js # ESM 格式
├── index.cjs # CJS 格式
├── index.d.ts # 类型声明
└── index.d.cts # CJS 类型声明
就是这么简单——无需任何配置文件,一条命令即可完成双格式输出 + 类型声明。
核心概念与架构
架构设计
tsup 的架构可以概括为三层:
┌─────────────────────────────────────┐
│ tsup CLI / API │ ← 用户接口层
├─────────────────────────────────────┤
│ tsup 核心编排层 │ ← 配置解析、任务编排、DTS 生成
├─────────────────────────────────────┤
│ esbuild │ ← 底层打包引擎(Go)
└─────────────────────────────────────┘
- 用户接口层:提供 CLI 命令和 Node.js API 两种调用方式
- 核心编排层:负责解析配置、管理多格式输出、调度 DTS 生成(通过 worker 线程)、文件监听等
- 底层引擎层:实际的文件解析、转换、打包由 esbuild 完成
工作原理
- 入口解析:根据
entry配置确定打包入口文件 - 依赖图构建:esbuild 解析所有 import/require,构建完整依赖图
- 代码转换:通过 esbuild 将 TypeScript/JSX 等转换为 JavaScript
- Tree Shaking:移除未使用的代码(dead code elimination)
- 格式输出:根据
format配置输出对应格式(ESM/CJS/IIFE) - DTS 生成:通过独立 worker 线程调用 TypeScript 编译器生成类型声明
- 后处理:可选的压缩、Source Map、清理输出目录等
DTS 生成机制
tsup 的类型声明文件生成是一个值得特别说明的机制。它有两种模式:
- 默认模式(
dts: true):使用 TypeScript 编译器 API 在独立 worker 线程中生成.d.ts文件,不影响主打包流程速度 - 实验性 DTS 模式(
experimentalDts: true,v8.0.0+):使用@microsoft/api-extractor生成更精确的合并类型声明,减少重复类型导出
核心特性
- 🚀 极速打包:底层使用 esbuild(Go 实现),比传统基于 Rollup/Webpack 的方案快 10-100 倍。50 个文件打包约 2.5 秒
- ⚙️ 零配置启动:无需配置文件即可打包 TypeScript 项目,开箱即用
- 📦 双格式输出:同时输出 ESM 和 CJS 格式,满足所有消费端需求
- 📝 类型声明生成:通过
dts: true自动生成.d.ts文件,无需单独运行tsc - 🌳 Tree Shaking:自动移除未使用代码,减小包体积
- 💻 代码拆分:支持 code splitting,将共享模块提取为独立 chunk
- 👁️ Watch 模式:内建文件监听,修改源码后自动重新构建
- 🗺️ Source Map:支持生成 Source Map,方便调试
- 🎨 CSS 支持:实验性 CSS 打包支持(v8.4.0+ 升级了 CSS 编译器)
- 🔌 插件系统:支持 esbuild 插件生态,可通过
esbuildPlugins扩展能力 - 🏷️ 多入口打包:支持多个入口文件同时打包
- 📋 JSON Schema:提供配置文件的 JSON Schema,支持编辑器自动补全和语法校验
- 🎯 灵活的目标环境:支持
es5~es2024、node10~node22等多种 target
生态图
核心依赖
| 依赖 | 作用 |
|---|---|
| esbuild | 底层打包引擎,提供超高速 JavaScript/TypeScript 转换 |
| typescript | 用于生成 .d.ts 类型声明文件 |
| bundle-require | 用于加载 tsup.config.ts 配置文件 |
| sucrase | 辅助处理某些 TypeScript 特性 |
| globby | 入口文件 glob 匹配 |
| @microsoft/api-extractor | experimentalDts 模式下的类型合并工具 |
相关插件/扩展
tsup 的插件系统基于 esbuild 插件,可以直接使用 esbuild 生态中的插件:
import { defineConfig } from 'tsup'
import somePlugin from 'some-esbuild-plugin'
export default defineConfig({
entry: ['src/index.ts'],
esbuildPlugins: [somePlugin()],
})常用 esbuild 插件示例:
esbuild-fix-imports-plugin:修复文件扩展名、路径别名和目录导入esbuild-plugin-less:Less 预处理器支持esbuild-sass-plugin:Sass 预处理器支持esbuild-style-plugin:CSS Modules 支持
社区生态
- 知名用户:shadcn/ui CLI、novel.sh、MSW(Mock Service Worker)等
- 模板/脚手架:社区提供了多种 tsup 项目模板
- 教程生态:LogRocket、DEV Community、Built In 等技术社区有大量教程
- 迁移工具:tsdown 提供
npx tsdown-migrate一键迁移工具
继任者:tsdown
2025 年底,EGOIST 推荐迁移到 tsdown——一个基于 Rolldown(Vite 团队用 Rust 开发的新一代打包器)的继任工具。tsdown 几乎 100% 兼容 tsup 的配置,但提供更好的性能和更多功能。
适用场景
- npm 库/包开发与发布:tsup 最核心的场景——快速将 TypeScript 库打包为 ESM + CJS 双格式并发布到 npm。零配置 + 极速构建让库开发体验极佳
- CLI 工具打包:适合打包命令行工具,支持 shebang、多入口、target 指定等。shadcn/ui CLI 就是典型案例
- Monorepo 中的子包构建:轻量快速,适合 monorepo 中需要独立构建的子包。搭配
--watch模式可实现开发时实时构建 - 快速原型/小工具开发:需要快速将 TypeScript 转换为可分发的 JavaScript 包时,tsup 是最省事的选择
- UI 组件库(轻量场景):对于不需要复杂 CSS 管线和主题系统的轻量 UI 组件库,tsup 足够胜任
- 教学与开源项目:配置简单、文档清晰,非常适合教学场景和中小型开源项目的构建
- Serverless/Edge 函数打包:快速打包独立函数,配合 target 指定运行环境
开发与工程化
开发流程
# 开发模式(监听文件变化)
pnpm dev # 等同于 tsup --watch
# 生产构建
pnpm build # 等同于 tsup
# 类型检查(tsup 不做类型检查,需单独运行)
pnpm typecheck # tsc --noEmit
# 测试
pnpm test重要提示:tsup 只负责代码转换和打包,不做类型检查。类型检查需要单独运行
tsc --noEmit。
构建部署
典型 CI/CD 集成(GitHub Actions 示例):
name: Build & Publish
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm build
- run: npx publint # 验证包发布配置
- run: pnpm publish --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}工程化最佳实践
- 使用
publint验证发布配置:在 CI 中集成publint检查exports字段和类型路径是否正确 - 使用
are-the-types-wrong:验证发布的类型声明是否能被各种消费端正确解析 peerDependencies必须标记为external:避免将 React、Vue 等框架依赖打包进库中- 添加
sideEffects字段:在package.json中正确声明,帮助消费端的打包工具做 Tree Shaking - 分离类型检查与打包:tsup 只做转换,类型检查用
tsc --noEmit - 使用
--clean标志:生产构建时清理旧的输出文件
性能与安全
性能特点
| 指标 | 表现 |
|---|---|
| 打包速度(50 文件) | ~2.5 秒 |
| 引擎 | esbuild(Go 多线程) |
| DTS 生成 | 独立 worker 线程,不阻塞主流程 |
| Watch 模式 | esbuild 原生增量编译,极快 |
| Monorepo 构建(26 包) | ~7 秒(tsup)→ ~3.5 秒(tsdown,快 49%) |
性能优化建议:
- 将不需要打包的依赖标记为
external - 使用
--no-splitting关闭代码拆分(对于简单库可减少开销) - 开发时使用
--watch而非每次重新构建 - DTS 生成是整体构建中最慢的环节,可考虑在开发时关闭
dts
安全注意事项
根据 Snyk 安全数据库信息:
- tsup v8.5.1(最新版本)无已知安全问题
- v8.2.2 ~ v8.5.0 存在一个中等严重性缺陷
- 建议使用最新版本并定期运行
npm audit - 由于 tsup 是构建时工具(开发依赖),安全风险相对较低——不直接影响运行时
已知安全关注点:
- esbuild 依赖链中的间接依赖可能存在风险
onSuccess回调执行外部命令时需注意命令注入风险- 加载
tsup.config.ts时通过bundle-require执行任意 TypeScript 代码
已知性能瓶颈
- DTS 生成速度慢:这是所有基于 TypeScript 编译器的类型生成方案的共同瓶颈,与打包引擎无关
- Node.js 启动开销:对于小型项目,Node.js 的启动时间可能比打包本身更长
- CSS 处理有限:实验性 CSS 支持在复杂场景下可能不够高效
- esbuild 功能限制:由于底层使用 esbuild,无法使用 Rollup 生态中的高级优化插件
技术对比
tsup vs 同类工具
| 特性 | tsup | tsdown | unbuild | Rollup | pkgroll |
|---|---|---|---|---|---|
| 底层引擎 | esbuild (Go) | Rolldown (Rust) | Rollup (JS) | Rollup (JS) | Rollup (JS) |
| 打包速度 | ⚡ 快 | ⚡⚡ 极快 | 🐢 中等 | 🐢 中等 | 🐢 中等 |
| 50 文件打包 | ~2.5s | ~0.6s | ~4-5s | ~4-5s | ~4-5s |
| 零配置 | ✅ | ✅ | ⚠️ 需少量配置 | ❌ | ✅ |
| ESM + CJS | ✅ | ✅ | ✅ | ✅ | ✅ |
| DTS 生成 | ✅ 实验性 | ✅ 原生支持 | ✅ | ❌ 需插件 | ✅ |
| Tree Shaking | ✅ | ✅ | ✅ 更强 | ✅ | ✅ |
| Stub 模式 | ❌ | ✅ | ✅ | ❌ | ❌ |
| 插件生态 | esbuild 插件 | Rolldown 插件 | Rollup 插件 | Rollup 插件(最丰富) | Rollup 插件 |
| 维护状态 | ❌ 停止维护 | ✅ 活跃开发 | ✅ 活跃开发 | ✅ 活跃开发 | ✅ 活跃开发 |
| 周下载量 | ~560 万 | ~50 万 | ~300 万 | ~2500 万 | 较少 |
关键差异分析
tsup vs tsdown:
- tsdown 是 tsup 的直接继任者,配置几乎 100% 兼容
- tsdown 使用 Rolldown(Rust)替代 esbuild(Go),构建速度提升 3-10 倍
- tsdown 是 ESM-first 设计,原生解决
.mjs/.cjs扩展名问题 - tsdown 新增 stub 模式、workspace 支持、CSS 完整管线、独立二进制打包等功能
- tsdown 的 DTS 生成原生支持
isolatedDeclarations,更可靠
tsup vs unbuild:
- unbuild 基于 Rollup,Tree Shaking 效果更好
- unbuild 属于 UnJS/Nuxt 生态,与该生态集成更紧密
- unbuild 的 stub 模式对 monorepo 开发更友好
- tsup 配置更简单、上手更快
tsup vs Rollup:
- Rollup 是工业级标准打包器,插件生态最丰富
- tsup 是 Rollup 的高层封装(但底层用 esbuild),专注于库开发场景
- Rollup 更灵活但需要更多配置
最佳实践
生产环境建议
1. 配置文件最佳实践:
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm', 'cjs'],
dts: true,
splitting: true,
sourcemap: true,
clean: true,
target: 'es2020',
// 关键:标记 peerDependencies 为外部依赖
external: ['react', 'react-dom', 'vue'],
// 忽略测试文件
ignoreWatch: ['**/*.test.ts', '**/*.spec.ts'],
// 构建完成后执行检查
onSuccess: async () => {
console.log('✅ Build completed')
},
})2. 多入口打包:
export default defineConfig({
entry: {
index: 'src/index.ts',
cli: 'src/cli.ts',
'utils/helpers': 'src/utils/helpers.ts',
},
format: ['esm', 'cjs'],
dts: true,
splitting: true,
})3. 环境变量替换:
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
define: {
'process.env.VERSION': JSON.stringify(process.env.npm_package_version),
},
})4. 样式注入:
export default defineConfig({
entry: ['src/index.ts'],
injectStyle: async (path) => {
const css = await fs.readFile(path, 'utf-8')
return `injectStyle(${JSON.stringify(css)})`
},
})常见陷阱
- 忘记将 peerDependencies 设为 external:导致 React/Vue 等框架被打包进库中,产生运行时错误
- 混淆类型检查与打包:tsup 不检查类型错误,需要单独运行
tsc --noEmit bundle: false使用不当:如果不需要打包(只想转译),应使用--no-bundle而非逐个添加 external- 忽略
exports字段校验:发布前务必用publint检查,避免消费端解析失败 - DTS 生成遗漏边界情况:复杂的泛型、条件类型可能在
.d.ts中出错,需人工检查输出
推荐模式
- 小型工具库:单入口 + ESM/CJS 双格式 + DTS
- 组件库:多入口 + code splitting + external 框架依赖
- CLI 工具:单独入口 + shebang 支持 + target 指定 Node.js 版本
- Monorepo:每个子包独立 tsup 配置 + watch 模式并行开发
技术局限与边界
已知限制
- 不再活跃维护:2025 年下半年,作者宣布 tsup 不再积极维护。虽然现有版本仍然可用,但不会收到新的功能更新和及时的 bug 修复
- 底层 esbuild 的功能限制:
- 不支持 Rollup 的
output.intro/output.outro等高级包装选项 - 不支持 IIFE 格式中的复杂全局变量映射
- esbuild 的 Tree Shaking 不如 Rollup 精确(特别是对 side effects 的判断)
- 不支持 Rollup 的
- DTS 生成仍为实验性:
dts: true在复杂类型场景下可能产生不正确的声明文件 - CSS 支持有限:仅为实验性,不支持 PostCSS、CSS Modules 等高级功能
- 不支持
splitting: false:某些场景下无法精确控制 chunk 生成 - 无 Stub 模式:不像 unbuild/tsdown 支持生成代理文件用于 monorepo 开发
- 不支持 SWC:虽然 v8.5.0 曾尝试添加 SWC 支持,但整体集成有限
不适用场景
- 大型应用打包:tsup 面向库打包,不适合 Webpack/Vite 的应用级打包场景
- 需要复杂 CSS 管线的 UI 库:考虑 Vite Library Mode 或 Rslib
- 需要极致 Tree Shaking 的库:Rollup/unbuild 的 Tree Shaking 更精确
- 需要丰富插件生态的场景:esbuild 插件生态不如 Rollup 丰富
- 对构建速度有极致要求的大型 Monorepo:考虑 tsdown(Rolldown/Rust)
迁移注意事项
如果考虑从 tsup 迁移到 tsdown:
# 自动迁移工具
npx tsdown-migrate
# Monorepo 批量迁移
npx tsdown-migrate 'packages/*'
# 预览迁移变更
npx tsdown-migrate --dry-run关键配置映射:
| tsup 配置 | tsdown 配置 |
|---|---|
entryPoints | entry |
publicDir | copy |
bundle: false | unbundle: true |
external | deps.neverBundle |
noExternal | deps.alwaysBundle |
esbuildPlugins | plugins(需换为 unplugin/rolldown) |
metafile | devtools: true |
迁移后建议:
- 在 tsconfig 中启用
isolatedDeclarations: true - 使用
are-the-types-wrong验证类型输出 - 考虑发布主版本以避免微妙不兼容
学习资源
官方资源
- 官方文档:https://tsup.egoist.dev/
- GitHub 仓库:https://github.com/egoist/tsup
- API 文档:https://jsdocs.io/package/tsup
- 配置 JSON Schema:官方提供
tsup.schema.json,可配置到编辑器获得自动补全
教程与指南
- Using tsup to bundle your TypeScript package — LogRocket Blog:详细的入门到进阶教程(2025 年 2 月)
- What is tsup? — DEV Community:概念介绍与快速上手(2025 年 8 月)
- Tsup: A Guide to the TypeScript Bundler — Built In:完整使用指南
- How tsup loads your tsup.config.ts — Think Throo:深入配置文件加载机制
- Creating a tree-shakable library with tsup — Dor Shinar:Tree Shaking 最佳实践
- Rollup 到 tsup 的实现原理对比 — Weekly:中文实现原理分析
社区资源
- GitHub Issues:https://github.com/egoist/tsup/issues(问题反馈和讨论)
- GitHub Discussions:https://github.com/egoist/tsup/discussions
- Reddit 讨论:r/node、r/javascript 社区中有多篇讨论帖
- 知乎专栏:tsdown vs tsup 对比分析
- 迁移到 tsdown 指南:https://tsdown.dev/guide/migrate-from-tsup
视频资源
- What Is tsup? — YouTube Shorts:快速介绍
- Project setup with tsup | Build & Release NPM package — YouTube:完整项目搭建教程
2026 年现状
最新版本
- 当前版本:v8.5.1(2025 年 11 月 12 日发布)
- 发布频率:v8.x 系列在 2024-2025 年间发布了 20+ 个版本,更新节奏在后期明显放缓
- 历史总版本:206+ 个 release
维护状态
⚠️ 项目不再活跃维护。 GitHub 仓库中已明确标注:
"This project is not actively maintained anymore. Please consider using tsdown instead."
这意味着:
- 现有版本仍然可用且稳定
- 不会再有重大功能更新
- 关键安全修复可能不会及时跟进
- 社区 PR 合并速度显著降低
发展趋势
2025-2026 年 TypeScript 库打包领域的关键趋势:
- Rust 化加速:esbuild(Go)正在被 Rolldown(Rust)取代,Vite 8 也将切换到 Rolldown
- tsdown 崛起:作为 tsup 的直接继任者,tsdown 增长迅速,被多位知名框架作者推荐
- ESM-first 成为默认:新工具默认 ESM 优先,CJS 作为兼容输出
- DTS 生成标准化:
isolatedDeclarations成为 TypeScript 5.5+ 的标准方案 - 零配置成为标配:几乎所有新工具都提供零配置体验
社区活跃度
| 指标 | 数值 |
|---|---|
| GitHub Stars | ~11,300+ |
| npm 周下载量 | ~560 万(仍为同类最高) |
| 累计 Issue 数 | 1,300+ |
| 贡献者 | 200+ |
| 最近代码提交 | 趋于停滞 |
未来路线图
tsup 本身已无公开的 future roadmap。生态的未来方向是:
- 短期(2026):tsup 仍是"安全选择",文档最多、社区最大、95% 的场景够用
- 中期(2026-2027):tsdown 逐步接管,新项目和迁移项目首选 tsdown
- 长期:随着 Vite 8 采用 Rolldown,整个生态向 Rust 打包器迁移,esbuild 时代逐步落幕
选型建议(2026 年)
| 情况 | 建议 |
|---|---|
| 新项目,从零开始 | 选择 tsdown |
| 现有 tsup 项目,运行正常 | 继续使用 tsup,计划迁移到 tsdown |
| 需要 Rollup 插件生态 | 选择 unbuild 或 Rollup |
| 在 UnJS/Nuxt 生态中 | 选择 unbuild |
| 需要极致构建性能 | 选择 tsdown |
| 快速原型/教学 | tsup 仍可用,但建议直接用 tsdown |