tsdown root 选项详解:掌控输出目录结构映射,让入口路径与产物一一对应
【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
tsdown 是 airi 这个大型 pnpm monorepo 中用于构建各 TypeScript 库的打包器,而root选项是决定「源码入口文件如何映射到输出路径」的关键开关。读完本文你将掌握root与 TypeScriptrootDir的关系、默认公共基目录的推导规则、CLI 与配置文件的完整用法,以及它在 unbundle(bundleless)模式下作为preserveModulesRoot影响产物结构的底层原理。
什么是 root:为输出结构映射指定根目录
root选项用于指定「输入文件根目录」,其作用是决定入口文件的路径如何映射为输出路径。可以把 tsdown 中的root类比为 TypeScripttsconfig.json里的rootDir概念:编译器/打包器需要知道「从哪个目录起算」来保留目录结构。
默认情况下,tsdown 会自动把**所有入口文件的公共基础目录(common base directory)**当作 root。显式设置root则允许你覆盖这一默认推导行为,从而精细控制输出目录层级。
在 tsdown 的完整能力地图中,root被归类在 Output Enhancement(输出增强)之下,官方定位描述为「root: 'src'— Control output directory mapping」,可参考 SKILL.md 中的 Build Options / Output Enhancement 索引表。
基本用法:CLI 与配置文件两种方式
root既可以在命令行直接传入,也可以在tsdown.config.ts配置文件中声明。
CLI 方式
tsdown --root src配置文件方式
// tsdown.config.ts import { defineConfig } from 'tsdown' export default defineConfig({ entry: ['src/index.ts', 'src/utils/helper.ts'], root: 'src', })配置文件通过defineConfig导出,root接受一个相对于执行 tsdown 所在目录(通常是包根目录)的路径字符串。
工作原理:默认公共基目录 vs 显式 root
默认行为:自动计算公共基目录
给定两个入口src/index.ts与src/utils/helper.ts,它们的公共基础目录是src/,因此默认产出如下结构,src前缀被剥除:
dist/ ├── index.js └── utils/ └── helper.js显式设置 root: '.'
如果将 root 设为项目根目录.,则输出会保留src/前缀:
dist/ └── src/ ├── index.js └── utils/ └── helper.js这两组结构的差异正是root的核心价值:决定目录前缀保留还是剥除。这与 TypeScript 的rootDir行为一致——输出目录结构永远以 root 为基准镜像映射。
与 outDir 的分工
需要区分两个容易混淆的选项:
| 选项 | 作用 | 对应文档 |
|---|---|---|
root | 决定入口路径到输出路径的映射基准(去掉/保留前缀) | Root Directory |
outDir | 决定产物写入到哪个目录(默认dist) | Output Directory |
outDir是产物总目录,root决定outDir之下如何按源码目录结构摆放文件。例如root: '.'+ 默认outDir: 'dist',产出即上文dist/src/...结构。
root 具体影响的两件事
tsdown 中root主要作用于两个环节:
入口名称解析(Entry name resolution)当入口以数组形式给出(如
['src/index.ts', 'src/utils/helper.ts'])时,各入口的输出文件名是相对root计算的。root 不同,同一份 entry 列表得到的相对路径(从而输出文件路径)就不同。Unbundle 模式(输出结构保持)当开启
unbundle: true时,root会被当作preserveModulesRoot使用,直接控制「逐文件编译、镜像源码结构」模式下输出目录的挂载起点。可结合 Unbundle 模式说明 理解。
何时应该显式设置 root
满足以下任一需求时,应显式配置root:
- 自动推导出的公共基目录无法产生期望的输出结构;
- 需要在输出路径中保留或剔除特定目录前缀(比如保留
src/前缀,方便调试时在产物里定位对应源文件); - unbundle 模式下需要特定的目录映射(
preserveModulesRoot语义)。
默认推导通常只适合入口相对集中、公共基目录恰好等于你想要去掉的那一层的情况。一旦入口跨度变大(比如既包含src/又包含scripts/下的文件),公共基目录可能变成项目根目录,此时就需要root显式介入。
常见模式:从配置示例到真实仓库用法
模式一:库保留 src/ 前缀 + unbundle
export default defineConfig({ entry: ['src/**/*.ts', '!**/*.test.ts'], root: '.', unbundle: true, })该模式产出dist/src/...完整镜像,适合希望产物路径与源码路径几乎一致、便于用户按子路径 import 的库。
模式二:monorepo 包,去掉 src/ 前缀
export default defineConfig({ entry: ['src/index.ts'], root: 'src', unbundle: true, })产出为dist/index.js等扁平或子目录结构,src/前缀被剥除。
airi 仓库中的实际印证
在 airi monorepo(见 pnpm-workspace.yaml)里,大量库包采用 tsdown 构建,且多配合unbundle: true使用,正属于root选项最有价值的应用场景。例如:
- packages/audio/tsdown.config.ts:以对象形式声明多入口,并把
audio-context/、encoding/等子目录通过 entry key 映射到产物目录,同时开启unbundle: true; - packages/i18n/tsdown.config.ts:通过
entry对象 key(如locales/zh-Hans/index)显式规划输出子目录,配合unbundle: true与copy保持 i18n 资源结构; - packages/font-chillroundm/tsdown.config.ts、packages/font-departure-mono/tsdown.config.ts 等字体包同样使用
unbundle: true模式构建。
从这些配置可以看出:airi 内部多数场景依赖「默认公共基目录 + entry key / 对象入口」即可得到理想结构;当需要改变前缀剥除策略或让 unbundle 的preserveModulesRoot落在特定目录时,才会引入显式root。这正是 Entry 选项文档 所强调的——对象入口 key 本身也是规划输出结构的一种手段。
模式三:纯 unbundle 场景参考
若同时希望产物可被按需深层导入,可参考完整 unbundle 组合(源自 Unbundle 模式说明):
export default defineConfig({ entry: ['src/**/*.ts', '!**/*.test.ts'], format: ['esm', 'cjs'], unbundle: true, dts: true, })使用建议与注意事项
- 明确产物消费方式再定 root:若发布的是整体入口库(
main/exports['.']指向单文件),通常无需显式root;若希望用户按my-lib/utils/helper深路径导入,则应保证 unbundle 产物结构可预期,必要时显式root。 - 与 dts 保持一致:生成声明文件(
dts: true)时,.d.ts的输出结构同样遵循入口映射规则,root 变更会影响.d.ts的目录摆放,需一并检查。 - 根目录即产物时要小心:不要让
outDir落到项目根目录(尤其当 root 为.时),配合clean: true极易误删源码。详见 Output Directory 的警告。 - root 表达的是目录而非 glob:与
entry支持 glob 与取反不同,root是一个具体目录;入口文件集合与排除规则应全部交给 entry 负责。
小结
root是 tsdown 输出路径体系中最容易被忽略、却对产物目录结构起决定性作用的选项:默认值来自所有入口的公共基目录,显式赋值则赋予开发者对「目录前缀保留与否」与「unbundle 模式下 preserveModulesRoot」的完全控制。在 airi 这样大量以 unbundle 方式发布多子模块库的 monorepo 中,理解root与entry、unbundle、outDir的配合关系,是保证「产物目录与 package.json exports 子路径声明精确对应」的前提。
【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考