tsdown 的 CI 环境感知构建:`ci-only` 与 `local-only` 选项在 airi 仓库中的应用
本文基于 airi 仓库内置的 tsdown 技能文档 advanced-ci.md,完整讲解 tsdown 如何自动检测 CI 环境,并通过 true / false / 'ci-only' / 'local-only' 四种取值让同一份构建配置在本地与 CI 中表现出不同行为。读完本文,你能够在自己的库构建中实现“本地快速迭代、CI 严格校验”的差异化流水线,并理解 airi 这类大型 monorepo 中 tsdown 配置与 GitHub Actions 的实际配合方式。
CI 环境检测原理
tsdown 通过 CI 环境变量判断当前是否运行在 CI 环境中。检测规则如下:
- 当
process.env.CI被设置为**非0且非false(忽略大小写)**的值时,CI 模式启用; CI=0、CI=false、CI=FALSE均视为未启用 CI 模式,按本地构建处理;- 主流 CI 平台(GitHub Actions、GitLab CI 等)都会自动注入
CI=true,因此通常无需手动设置。
这一判断结果会作为 ci 布尔值传入配置函数的上下文(见下文“配置函数”一节),同时驱动所有 CI-aware 选项的取值解析。
CI 感知取值(CI-Aware Values)
tsdown 中多个选项不局限于 boolean,而是接受一种“CI 感知字符串”。四种取值的语义如下:
| 取值 | 行为 |
|---|---|
true |
始终启用(本地与 CI 都执行) |
false |
始终禁用 |
'ci-only' |
仅在 CI 中启用,本地禁用 |
'local-only' |
仅在本地启用,CI 中禁用 |
这套设计的核心动机是构建速度与质量校验的分离:DTS 生成、包校验(publint / attw)等步骤在本地开发时往往拖慢反馈循环,而它们恰恰是发布前最值得做的检查;反之,本地开发更需要 source map、更宽松的警告策略等体验优先的设置。
支持 CI 感知取值的选项
以下选项支持上表的 CI 感知字符串:
dts— TypeScript 声明文件(.d.ts)生成,底层由 option-dts.md 描述;publint— 校验package.json的exports/main/types等字段与实际产物是否一致;attw— Are The Types Wrong? 校验,验证声明文件在node10/node16/bundler等模块解析策略下是否正确;report— Bundle 体积报告;exports— 自动生成package.json的exports字段;unused— 未使用依赖检查;devtools— DevTools 集成;failOnWarn— 遇到警告时使构建失败,默认值为false(详见 option-log-level.md)。
其中 publint 与 attw 的配置细节(level、profile、ignoreRules 等参数)在 option-lint.md 中有完整说明,二者均为可选依赖:需要先安装 publint 或 @arethetypeswrong/core 才生效。
三种使用形式
形式一:字符串形式(最简洁)
对于取值本身就是开关的选项,直接写 CI 感知字符串:
export default defineConfig({
dts: 'local-only', // 本地生成 DTS,CI 中跳过以加速构建
publint: 'ci-only', // 仅在 CI 中运行 publint 包校验
failOnWarn: 'ci-only', // 仅 CI 中遇到警告即失败(opt-in)
})
dts: 'local-only' 是一个值得注意的组合:声明文件供 IDE 与下游类型检查使用,本地保留它能让开发体验完整;而 CI 打包发布场景若已有独立的类型检查 job,则可以跳过 DTS 节省时间。
形式二:对象形式(带参数)
当选项接受配置对象时,把 enabled 字段设为 CI 感知取值,其余参数照常配置:
export default defineConfig({
publint: {
enabled: 'ci-only',
level: 'error',
},
attw: {
enabled: 'ci-only',
profile: 'node16',
},
})
对象形式的好处是校验规则始终写死在配置里,只是执行时机受环境控制。例如 attw.profile: 'node16' 表示忽略 node10 解析失败的宽容策略,无论本地还是 CI 语义一致,仅由 enabled: 'ci-only' 决定何时真正运行。
形式三:配置函数(显式拿到 ci 布尔值)
配置函数形式的回调会接收上下文参数,其中包含 ci 布尔值,可以基于它派生任意其他选项:
export default defineConfig((_, { ci }) => ({
minify: ci,
sourcemap: !ci,
}))
这是对 CI 感知字符串的通用补充:凡是 minify、sourcemap 这类本身不支持 CI 感知字符串的选项,都可以借助 ci 布尔值实现等价的分环境行为。前两个参数分别为 CLI 传入的选项对象与环境上下文,ci 即 CI 环境变量解析后的结果。
典型的 CI 配置
将上述能力组合起来,文档给出的“发布前严格、本地宽松”的典型配置是:
export default defineConfig({
entry: 'src/index.ts',
format: ['esm', 'cjs'],
dts: true,
failOnWarn: 'ci-only',
publint: 'ci-only',
attw: 'ci-only',
})
其运行效果:
- 本地:正常产出 ESM/CJS 与 DTS,警告只提示不失败,不跑 publint / attw,反馈最快;
- CI:产出相同,但任何警告都会使构建失败,且包结构(publint)与类型声明(attw)都会接受校验——这两项正是“打包错误在用户安装时才暴露”这类问题最有效的拦截点。
在 airi 仓库中的实际应用
airi 是一个 pnpm + Turborepo 组织的多包 monorepo(package.json 中 build:packages 通过 turbo run build -F="./packages/*" 统一调度),仓库中 packages/ 下大量子包使用 tsdown 构建。从源码结构看,仓库内的 tsdown 配置以静态对象形式为主,普遍开启了 sourcemap 与 unused(未使用依赖检查),例如:
- packages/plugin-protocol/tsdown.config.ts:
sourcemap: true, unused: true; - packages/server-sdk/tsdown.config.ts:
sourcemap: true, unused: true, inlineOnly: false; - packages/stream-kit/tsdown.config.ts:最小配置,
dts: true; - services/computer-use-mcp/tsdown.config.ts:多入口 +
target: 'node18',为多个二进制入口(bin/run、bin/runner)生成 ESM 产物与 DTS。
这说明两类环境差异策略在 airi 中是分层落地的:
- CI 平台级差异由 GitHub Actions 工作流承担。.github/workflows/ci.yml 定义了
lint、build-test、unit-test、typecheck、check-provenance五个 job,其中build-test用 matrix 分别构建 stage-web、stage-tamagotchi 等应用,并固定node@26.7.0运行时;GitHub Actions 运行器自动注入CI=true,因此 tsdown 侧所有ci-only选项在该流程中会全部生效,无需在 YAML 里做任何额外声明。 - 包构建级差异由 tsdown 配置承担。airi 仓库当前的
tsdown.config.ts多为显式布尔值(如dts: true),未直接使用'ci-only'/'local-only'字符串——从源码结构看,仓库把“严格化”主要放在了独立的 typecheck / lint job 与unused: true这类轻量检查上,而把重量级的 publint / attw 校验留给发布流程(.github/workflows/release-pkg.yaml)。
对于想在 airi 风格仓库中复现文档典型配置的开发者,推荐路径是:在包级 tsdown.config.ts 中加入 publint: 'ci-only' 与 attw: 'ci-only',并安装对应的可选依赖;本地 pnpm build 不受影响,CI 中则自动获得发布前校验。
注意事项与适用前提
publint/attw需要项目目录下存在package.json,且分别依赖publint与@arethetypeswrong/core两个 devDependency,二者都缺失时选项不会生效;failOnWarn默认是false,写成'ci-only'属于显式 opt-in 的严格化,建议在包结构稳定后再开启,避免历史警告直接导致 CI 红灯;- 配置函数中的
ci布尔值与CI环境变量解析规则完全一致(非0/ 非false即视为 CI),因此本地可用CI=1 pnpm build快速预演 CI 行为,无需真的推到远端; - 本文结论基于 airi 仓库内置的 tsdown 技能文档(.agents/skills/tsdown/references/ 目录)及其
tsdown.config.ts实际配置;不同版本的 tsdown 选项集合可能不同,请以项目 lockfile 锁定的版本为准。
小结
tsdown 的 CI 环境支持本质上是一套“一份配置、两套行为”的构建策略:通过 CI 环境变量检测运行环境,用 true / false / 'ci-only' / 'local-only' 四种取值控制 dts、publint、attw、report、exports、unused、devtools、failOnWarn 等选项的分环境启用,并允许在配置函数中直接读取 ci 布尔值派生 minify、sourcemap 等其他行为。在 airi 这类 pnpm + Turborepo monorepo 中,这套机制与 GitHub Actions 的 CI=true 注入天然契合,让本地开发保持快速反馈、CI 流水线承担发布前校验,是库构建工程化中成本很低但收益明确的做法。
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