news 2026/9/8 21:20:06

tsdown 包校验实践:publint 与 attw 双保险配置详解(基于 airi 仓库实证)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
tsdown 包校验实践:publint 与 attw 双保险配置详解(基于 airi 仓库实证)

tsdown 包校验实践:publint 与 attw 双保险配置详解(基于 airi 仓库实证)

【免费下载链接】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 的publintattw两个包校验选项展开:前者在构建后校验package.json字段(exportsmainmoduletypes)与实际产物文件是否一致,后者验证 TypeScript 类型声明在node10node16bundler等多种模块解析策略下是否全部正确。读完本篇,你可以在自己的库中配置出「本地开发不打扰、CI 严格拦截」的发布前类型与打包校验流水线,并理解 airi 这类大型 pnpm monorepo 是如何在多个插件包中落地这套校验的。

为什么需要发布前包校验

TypeScript 库发布后最常见的翻车点有两类:

  1. package.json元数据与实际产物不匹配exports里声明了某个入口,但 dist 目录里没有对应文件;或者main指向 CJS 文件而实际输出是 ESM。这类问题在npm pack之后或下游安装时才暴露。
  2. 类型声明在不同解析策略下表现不一致:同一个.d.ts文件,在moduleResolution: node10下能解析,换到node16bundler下就报"解析不到类型"或"CJS 类型指向了 ESM 实现"。tsdown 通过dts: true生成声明文件,但生成不等于正确,需要工具按多套解析策略逐一复核。

tsdown 把两个社区标准工具 publint(对应包结构校验)与 Are the types wrong?(attw,对应类型解析校验)集成进了构建流程,两者都是可选依赖,按需启用。

安装依赖

两个工具都作为开发依赖按需安装:

# 只装 publint npm install -D publint # 只装 attw npm install -D @arethetypeswrong/core # 两个都要 npm install -D publint @arethetypeswrong/core

以 airi 仓库为例,它使用 pnpm catalog 统一版本管理,在 pnpm-workspace.yaml 中声明:

catalog: '@arethetypeswrong/core': ^0.18.5 publint: ^0.3.24 tsdown: ^0.22.14

根目录 package.json 则通过"publint": "catalog:""@arethetypeswrong/core": "catalog:"引用这两个依赖——这意味着 tsdown 在执行publint/attw校验时,能在 node_modules 中找到已安装的核心包,而不是每次临时下载。

publint:package.json 与实际产物的对齐检查

启用

在 tsdown 配置文件中开启即可,构建完成时 tsdown 会对输出目录执行 publint 检查:

export default defineConfig({ publint: true, })

配置项

publint也接受对象形式,用于控制报告级别:

export default defineConfig({ publint: { level: 'error', // 'warning' | 'error' | 'suggestion' }, })

level决定哪些级别的诊断会被上报并影响构建退出码:设为'error'时仅错误级别的问题会导致构建失败;设为'suggestion'则连建议级别的问题也会输出。

CLI 方式

不想改配置文件时,可以直接在命令行临时开启:

tsdown --publint

根据 CLI 参考 中的标志映射规则,--publint等价于设置publint: true,且 CLI 标志的优先级高于配置文件选项。

airi 仓库中的真实用法

airi 的多个插件包把publint: true直接写进了构建配置。以 plugins/airi-plugin-homeassistant/tsdown.config.ts 为例:

import { defineConfig } from 'tsdown' export default defineConfig([ { entry: ['./src/index.ts'], dts: true, unused: true, publint: true, }, ])

plugins/airi-plugin-claude-code/tsdown.config.ts 与 plugins/airi-plugin-bilibili-laplace/tsdown.config.ts 采用了同样的模式(dts: true+publint: true+unused: true)。从源码结构看,这套组合拳是 airi 插件体系的标配:dts负责产出声明文件,publint在产物生成后立即核对exports/main/types字段是否指向真实存在的文件,unused则顺带检查未使用的依赖。这也解释了为什么仓库根目录需要把publint列为 devDependency——没有它,publint: true就无法执行。

attw:多解析策略下的类型正确性验证

启用

export default defineConfig({ attw: true, })

配置项

export default defineConfig({ attw: { profile: 'node16', // 'strict' | 'node16' | 'esm-only' level: 'error', // 'warn' | 'error' ignoreRules: ['false-cjs', 'cjs-resolves-to-esm'], }, })

三个子项各管一件事:

  • profile:选择校验严格度档位(见下表);
  • level'warn'只提示不阻断,'error'则让构建失败;
  • ignoreRules:按问题类型白名单,抑制确认可接受的特定告警。

Profile 档位

Profile说明
strict要求所有解析策略(node10、node16、bundler)全部通过(默认值)
node16忽略node10解析失败
esm-only忽略node10node16-cjs解析失败

选择依据通常来自你的用户群:如果你的库以 ESM 为主、面向现代打包器(Vite、Bundler 生态),esm-only是最宽松的合理档位;如果还要兼容 CJS 消费方(Node 生态 CLI 工具),至少选node16strict适合追求全兼容的公共库。

ignoreRules 完整清单

attw 会按规则类型报告问题,ignoreRules可以精确抑制其中特定类型。完整规则表如下:

规则含义
no-resolution模块完全无法被解析
untyped-resolution解析成功但没有附带类型
false-cjs类型声明标记为 CJS,实际实现是 ESM
false-esm类型声明标记为 ESM,实际实现是 CJS
cjs-resolves-to-esmCJS 解析路径指向了一个 ESM 模块
fallback-condition解析时使用了回退/通配条件
cjs-only-exports-defaultCJS 模块只导出了 default
named-exports类型与实现的命名导出(named exports)不一致
false-export-default类型声明了 default 导出但实现中不存在
missing-export-equalsCJS 类型缺少export =
unexpected-module-syntax文件使用了意外的模块语法
internal-resolution-error类型检查内部的解析错误

配置示例ignoreRules: ['false-cjs', 'cjs-resolves-to-esm']适合一种常见场景:包用双格式(ESM + CJS)构建,CJS 产物的.d.tsmoduleResolution: node16的 CJS 侧解析时会被误判为 ESM 类型,这两条规则正是为此类误报准备的。

CLI 方式

tsdown --attw

CI 集成:本地宽松、CI 严格

tsdown 的 CI 感知机制通过检测CI环境变量判断是否处于 CI 环境(当process.env.CI的值不是0false(不区分大小写)时视为 CI 开启),多个选项因此接受 CI 感知字符串值:

行为
true始终启用
false始终禁用
'ci-only'仅在 CI 启用,本地禁用
'local-only'仅本地启用,CI 禁用

publintattw都在支持该机制的选项列表中(同列表的还有dtsreportexportsunuseddevtoolsfailOnWarn)。推荐配置是「本地开发不跑校验保持构建快,CI 上严格拦截」:

export default defineConfig({ publint: 'ci-only', attw: { enabled: 'ci-only', profile: 'node16', level: 'error', }, })

注意对象形式下用enabled字段承载 CI 感知值。配套的典型 CI 完整配置:

export default defineConfig({ entry: 'src/index.ts', format: ['esm', 'cjs'], dts: true, failOnWarn: 'ci-only', publint: 'ci-only', attw: 'ci-only', })

failOnWarn: 'ci-only'是显式 opt-in 的:本地出现警告不阻断,CI 上任何警告都让构建失败,适合在稳定期收紧质量门禁。

前置条件与相关选项

  • 两者都要求项目目录下存在package.json:publint 校验的对象就是package.json字段,attw 也依赖包元数据确定解析条件,没有它则无法运行。
  • 两个工具都是可选依赖:不安装publint/@arethetypeswrong/core时不要启用对应选项,否则校验步骤无法执行。
  • 与 CI Environment 文档配合可了解 CI 检测与'ci-only'/'local-only'的完整语义。
  • 与 Package Exports 配合可了解exports: true如何自动生成package.jsonexports字段——自动生成之后,publint 正是核对这套字段与产物一致性的守门人,两者天然形成「生成—校验」闭环。

小结:把校验放进构建流水线的完整姿势

  1. 安装依赖:npm install -D publint @arethetypeswrong/core
  2. tsdown.config.ts中启用publint: 'ci-only'attw: { enabled: 'ci-only', profile: 'node16', level: 'error' }
  3. 遇到可解释的误报时,用ignoreRules精确抑制,而不是整体放宽level
  4. 需要临时排查时用 CLI 标志tsdown --publint/tsdown --attw即时开启;
  5. 参考 airi 仓库的做法,把dts: true+publint: true+unused: true作为插件类库包的标准构建配置,让校验随每次构建自动执行。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 21:19:21

Firecrawl:将网页秒变干净Markdown,为LLM与RAG高效供给数据

先说结论:如果你想用 LLM 批量处理网页内容,但又不希望整天被 HTML 标签、动态渲染、反爬策略这些东西折磨,Firecrawl 是目前难得让我觉得“终于有个工具是把我想做的事直接做好”的抓取 API。它做的事情一句话就能讲清楚:把任意 …

作者头像 李华
网站建设 2026/9/8 21:19:10

Godot 4入门:从零搭建第一个2D游戏场景

很多朋友在群里问我同一个问题:想学做游戏,到底从哪个引擎入手最合适。我的答案一直很直接——如果你只是想快速搭出第一个 2D 游戏场景,不打算被授权费、安装流程和一堆专业术语劝退,Godot 4 是非常值得投入时间的那一个。Godot …

作者头像 李华
网站建设 2026/9/8 21:19:03

Hermes:基于规则引擎与语义分析的自动化代码评审工具实践

PR积压到20个的时候,再佛系的团队也会急。我们组曾经统计过一次,一个月的PR量在240个左右,但能稳定做代码评审的只有3个人,平均一个PR从提交到拿到第一条有效评论要12个小时,遇到组里开会或者忙上线,拖两天…

作者头像 李华
网站建设 2026/9/8 21:17:01

Qt+FFmpeg+OpenGL打造高性能播放器内核:解码渲染实战解析

简介:一份基于 Qt、FFmpeg 与 OpenGL 的视频播放器完整源码项目,面向有一定 Qt 基础、希望进阶音视频渲染的开发者。项目内置 64 位 FFmpeg 依赖库,采用 VSQt 编译,无需额外配置第三方库,下载后可直接编译运行&#xf…

作者头像 李华
网站建设 2026/9/8 21:16:42

tiny11builder 使用指南:从官方 ISO 生成轻量 Windows 11 安装镜像

tiny11builder 使用指南:从官方 ISO 生成轻量 Windows 11 安装镜像 【免费下载链接】tiny11builder Scripts to build a trimmed-down Windows 11 image. 项目地址: https://gitcode.com/GitHub_Trending/ti/tiny11builder tiny11builder 是一组 PowerShell …

作者头像 李华