测试 npm 打包产物calcom/embed-react 的 packaged tests 实践指南【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy本篇技术指南以 packages/embeds/embed-react/test/packaged/README.md 为核心深入讲解 Cal.comcal.diy如何针对发布到 npm 的打包后代码而非源码进行专项测试。读者将掌握为什么源码能跑通不等于发布后能用package.json的files、main、module、types、exports字段如何影响产物以及如何用 Vitest TypeScript 同时验证打包产物的运行时行为与类型声明为自研 npm 库建立可复用的发布前质量保障流程。一、为什么要专门测试打包后的代码大多数项目对源码进行单元测试、集成测试却往往忽略了对发布产物的验证。calcom/embed-react的做法是在发布前单独开辟一套针对打包代码的测试目录test/packaged/并在 README.md 中明确说明The tests in this file are run on the packaged code that is published to npm.其根本原因是打包后的代码与源码至少在以下方面存在差异这些差异正是 bug 的高发地带并非所有文件都会进入打包产物。一旦package.json中声明了files字段只有被该字段列出的文件才会随包发布。开发者很容易意外漏掉某个源码中正常存在、但发布包里缺失的关键文件。打包产物中不存在.ts文件。源码中的.ts会被编译为.js同时单独生成.d.ts类型声明文件用于 TypeScript 支持。这样同一个包既能被 TypeScript 项目引用拿到类型也能被纯 JavaScript 项目引用直接运行。换句话说源码级别的测试覆盖的是逻辑是否正确而 packaged tests 覆盖的是发布到 npm 之后的包是否可被正确引入、正确运行、正确补全类型这一更外层的问题。二、差异一files字段决定发布内容漏一个文件就毁一个包原文档指出如果package.json中配置了files字段只有列出的文件会被发布。以 packages/embeds/embed-react/package.json 为例files: [ dist ],这意味着calcom/embed-react发布到 npm 时只包含dist/目录下的构建产物src/下的 TypeScript 源码、测试文件等均不会随包发布。这也是打包产物测试存在的核心动机之一——一旦构建流程改变导致dist目录内容不完整例如缺少某个入口文件源码阶段无法察觉只有消费者在安装后才发现Cannot find module。从 npm 的发布语义看files字段本质上是发布白名单而 packaged tests 正是针对这份白名单的结果即实际dist产物做的收货检验。三、差异二.ts编译为.js.d.ts类型与运行时必须双验证原文档强调打包代码里没有.ts文件它们被编译成.js并额外生成.d.ts从而让包同时兼容 TypeScript 与非 TypeScript 环境。这一点在calcom/embed-react的构建脚本中体现得淋漓尽致。package.json 中的build命令分两步完成build: npx rimraf dist vite build npx shx cp ./dist/Cal.es.js ./dist/Cal.es.mjs tsc --emitDeclarationOnly --declarationDir distvite build以库模式lib mode打包出可供浏览器/打包器直接使用的 JS 产物详见下文第四节tsc --emitDeclarationOnly --declarationDir dist只做类型检查与声明文件生成不输出 JS把.d.ts写入dist目录供 TypeScript 消费者使用。于是dist目录中同时存在.js运行时与.d.ts类型两类文件而 packaged tests 恰好从这两个维度各验证一次见第五节。四、打包配置源码级剖析入口、格式与use client 处理要理解 packaged tests 到底在验证什么必须先看清打包配置。 packages/embeds/embed-react/vite.config.js 的核心内容如下build: { lib: { entry: path.resolve(__dirname, src/index.ts), name: Cal, fileName: (format) Cal.${format}.js, }, rollupOptions: { external: [react, react/jsx-runtime, react-dom, react-dom/client], output: { exports: named, banner: useClientBanner, // use client; globals: { react: React, react-dom: ReactDOM, react/jsx-runtime: jsxRuntime, }, }, }, },关键点入口是src/index.ts最终产物文件名为Cal.es.js、Cal.umd.jsES 与 UMD 两种格式再通过shx cp复制出Cal.es.mjs供 ESM 场景使用react、react-dom等被 external 化不打进包里由消费者自己提供这也是 package.json 中peerDependenciesreact: ^18.2.0 || ^19.0.0的由来banner: use client为了让产物兼容 Next.js App Router 的客户端组件约定Rollup 会把出现在文件中间的use client指令忽略/移除因此这里通过banner重新把它放到产物最顶部。这是打包产物与源码不同的又一个具体实例。这些配置最终决定了发布包的门面—— package.json 中的入口声明main: ./dist/Cal.umd.js, module: ./dist/Cal.es.mjs, types: ./dist/embed-react/src/index.d.ts, exports: { .: { types: ./dist/embed-react/src/index.d.ts, import: ./dist/Cal.es.mjs, require: ./dist/Cal.umd.js } }其中mainCommonJS 入口、moduleESM 入口、types类型入口以及更现代的exports条件导出任何一个指向的文件缺失或路径写错消费者端都会直接报错——这正是 packaged tests 的验证对象。五、packaged tests 的实现一次测试双通道验证packages/embeds/embed-react/test/packaged/api.test.ts 是这份 README 背后唯一的测试文件其文件头注释精炼地概括了它的双重使命它是一个 Vitest 测试文件测试代码能否无错误执行从而验证package.json的main/module字段是否正确同时验证断言。它同时用于类型校验从而验证calcom/embed-react在package.json的types字段中正确声明了类型。具体实现// 此导入在 IDE 中可能显示为错误但没关系因为类型声明只有在 embed-react 构建完成后才可用 import { getCalApi } from calcom/embed-react; const api getCalApi(); test(Check that the API is available, async () { expect(api).toBeDefined(); const awaitedApi await api; awaitedApi(floatingButton, { calLink: free, config: { // ts-expect-error 我们故意测试无效值 layout: wrongview, }, }); });5.1 运行时通道验证main/module入口import { getCalApi } from calcom/embed-react在 Vitest 环境中会按exports/module/main的解析规则找到dist里的实际产物。如果构建时产物缺失、入口字段指向错误路径这个 import 本身就会失败——运行时通道在能否被正确引入并执行层面完成验证。5.2 类型通道验证types声明同一份文件同时参与 TypeScript 类型检查。测试目录 tsconfig.json 继承了calcom/tsconfig/base.json声明了declaration: true并开启类型解析。当import { getCalApi }能通过tsc检查时就说明types字段指向的.d.ts确实存在且声明正确。5.3 故意传入无效值的深意类型系统的反向验证测试中特意传入layout: wrongview并在上一行标注ts-expect-error。这是一个精巧的双向校验如果类型声明失效例如d.ts缺失、config参数退化为anyts-expect-error会因为下一行没有类型错误而自身报错——反向证明类型约束确实生效同时运行时仍会调用floatingButton证明即使传入不合法配置API 调用链也不会崩溃。5.4 被测对象getCalApi与 Cal 组件测试调用的getCalApi定义于 packages/embeds/embed-react/src/index.ts它通过calcom/embed-snippet的EmbedSnippet往页面注入embed.js支持namespace隔离与 50ms 轮询等待 API 就绪export function getCalApi(optionsOrEmbedJsUrl?): PromiseGlobalCal | GlobalCalWithoutNs { const options typeof optionsOrEmbedJsUrl string ? { embedJsUrl: optionsOrEmbedJsUrl } : optionsOrEmbedJsUrl ?? {}; const { namespace , embedJsUrl } options; return new Promise(function tryReadingFromWindow(resolve) { const globalCal EmbedSnippet(embedJsUrl); globalCal(init, namespace); const api namespace ? globalCal.ns[namespace] : globalCal; if (!api) { setTimeout(() { tryReadingFromWindow(resolve); }, 50); return; } resolve(api); }); }包的另一半是默认导出的Cal组件src/Cal.tsx它要求必传calLink在useEffect中通过useEmbedsrc/useEmbed.ts懒加载全局Cal对象再以inline模式把预订界面渲染到挂载的div上支持namespace、calOrigin、initConfig、config等 props。README 描述的打包后测试正是围绕这套对外 API 展开的。六、如何运行与接入packaged:tests与prepack钩子6.1 手动运行package.json 定义了专用脚本packaged:tests: cd test/packaged yarn tsc --noEmit VITEST_MODEpackaged-embed yarn run -T test它分两步执行yarn tsc --noEmit在test/packaged目录下做纯类型检查——这一句就完成了上文类型通道的验证确认.d.ts可用VITEST_MODEpackaged-embed yarn run -T test以packaged-embed模式运行 Vitest——完成运行时通道的验证确认 JS 产物可执行。运行前提是先完成构建由于类型声明只在embed-react构建完成后才存在测试文件头注释也特别说明IDE 里 import 报错是正常的。因此正确的执行顺序是先yarn build产出dist再跑yarn packaged:tests。6.2 发布前自动执行更关键的是prepack钩子package.jsonprepack: yarn ../../../ lint --filtercalcom/embed-react yarn withEmbedPublishEnv build yarn packaged:testsnpm pack/npm publish会自动触发prepack依次执行lint → 以线上 embed 地址构建withEmbedPublishEnv注入NEXT_PUBLIC_EMBED_LIB_URL与NEXT_PUBLIC_WEBAPP_URL→ packaged tests。也就是说任何一次发布动作都会强制先通过打包产物测试从机制上杜绝带病发布。6.3 测试目录配置一览test/packaged/tsconfig.json 的关键编译选项{ extends: calcom/tsconfig/base.json, compilerOptions: { module: ESNext, target: ES2015, moduleResolution: Node, declaration: true, jsx: preserve, outDir: dist }, include: [**/*.ts] }注意declaration: true与moduleResolution: Node——前者让该目录也能产出声明文件后者决定calcom/embed-react的类型解析走types/main字段路径恰好与发布后消费者的解析方式对齐。七、可复用的最佳实践总结结合原文档的两点核心差异与calcom/embed-react的落地实现可以提炼出针对任意 npm 库的发布产物测试方法论单独建一个测试目录如test/packaged/只面向dist产物与源码测试隔离双通道验证入口字段运行时通道验证main/module/exports指向的 JS 能被 import 且可执行类型通道验证types指向的.d.ts能被tsc解析用ts-expect-error反向验证类型约束故意传非法值若类型声明退化则测试自身失败把测试挂进prepack让npm publish自动触发 lint build packaged tests形成发布强校验牢记执行顺序先构建生成dist含.d.ts再运行 packaged tests否则类型通道必然失败。这套机制的价值在于files白名单漏文件、构建产物入口缺失、类型声明失效这类源码阶段完全看不见的问题会在发布动作发生的瞬间被拦截下来——这正是 Cal.com 将 packaged tests 作为calcom/embed-react发布流水线一环的原因。【免费下载链接】cal.diyScheduling infrastructure for absolutely everyone.项目地址: https://gitcode.com/GitHub_Trending/ca/cal.diy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考