:用 API Extractor 锁定向后兼容边界的工程实践)
Crawlee 公共 API 表面映射Public API Surface Maps用 API Extractor 锁定向后兼容边界的工程实践【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawleeCrawlee 是一个用 JavaScript/TypeScript 编写的 Node.js 网页抓取与浏览器自动化库其仓库以 monorepo 形式管理着crawlee/*数十个可发布包。为了让每个包的公开接口在演进中保持稳定、可审计仓库在 docs/public-api/ 目录下维护了一批由 API Extractor 自动生成的公共 API 表面映射报告*.api.md并将其纳入 CI 强制校验。读完本文你将掌握这套报告是什么、如何生成、如何纳入日常开发与 CI 工作流以及它背后关于public裁剪、被遗忘导出forgotten exports、死导入清理等一系列值得借鉴的工程细节。一、什么是公共 API 表面映射docs/public-api/目录下每一个*.api.md文件都是某个可发布crawlee/*包的公共、类型级接口的完整地图——它枚举该包导出的每一个类、方法、属性、函数和类型并附上完整签名。这些报告定义的正是仓库承诺向后兼容backwards compatibilityBC的边界凡是在报告中出现的内容后续版本不应轻易破坏。以 docs/public-api/crawlee-core.api.md 为例报告文件头部是自动生成的说明与完整导入清单随后是带// public标注的接口声明例如// public (undocumented) export interface AddRequestsBatchedOptions extends RequestQueueOperationOptions { batchSize?: number; maxNewRequests?: number; waitBetweenBatchesMillis?: number; waitForAllRequestsToBeAdded?: boolean; }而聚合包的报告 docs/public-api/crawlee.api.md 则展示了crawlee主包如何通过export * from crawlee/basic、crawlee/core、crawlee/playwright等一系列子包重新导出并额外声明了一个组合了puppeteerUtils、playwrightUtils、social、sleep等工具的utils命名空间对象。也就是说这套报告既覆盖子包各自的表面也覆盖聚合包对外暴露的整体形状。所有报告均由 API Extractor 从每个包构建后的dist/index.d.ts生成因此报告反映的是编译产物的真实类型表面而非手写文档——它天然具备始终与源码同步的潜力。二、生成机制从dist/index.d.ts到提交入库的报告报告的生成链路是源码 .ts → pnpm buildturbo 构建产出各包 dist/index.d.ts → API Extractor 提取 → *.api.md在仓库根目录 package.json 中可以看到对应脚本api:extract: pnpm build pnpm dlx github:apify/api-extractor-report --excludecrawlee/cli,crawlee/templates --extract-commandpnpm api:extract, api:check: pnpm dlx github:apify/api-extractor-report --excludecrawlee/cli,crawlee/templates --extract-commandpnpm api:extract --verify两个命令都通过pnpm dlx github:apify/api-extractor-report调用报告生成器并显式传入--excludecrawlee/cli,crawlee/templates排除列表。区别在于api:extract负责生成并落盘报告而api:check额外带有--verify标志用于校验已提交的报告是否与当前构建产物一致。注意api:extract内部会先执行pnpm build这是因为报告必须从最新构建出的dist/index.d.ts提取这也是文档中强调报告从 dist/ 生成的原因。有一点值得说明docs/public-api/README.md提到生成器位于scripts/api-extractor/目录含run.ts但从当前仓库的实际结构看生成器是以github:apify/api-extractor-report的形式通过pnpm dlx按需拉取执行的仓库自身并未内置该目录如果你在仓库内找不到scripts/api-extractor/run.ts属于正常现象以 package.json 中实际注册的命令为准。三、日常维护工作流改公共 API 后必须做的事文档定义了一套明确的流程要求任何触及包公共表面的改动都必须同步更新并提交报告修改某个包的公共表面新增/删除/修改导出、签名或类型重新生成报告并提交pnpm build # 报告从 dist/ 生成 pnpm api:extractCI 强制把关CI 会运行pnpm api:check只要已提交的报告与最新构建不一致就判定失败。一次失败的api:check意味着两种情况改动是有意的——那就提交更新后的报告评审者会通过报告差异surface diff看到公共接口的每一次变化改动是意外的——例如不小心把某个符号从入口文件导出、或无意修改了签名——那就需要修复源码。换言之这套机制把公共 API 变更从隐性的代码改动变成了显式、可评审、可追溯的 diff任何未经报告的接口变化都会在 CI 阶段被拦下。四、api:check的第二种失败模式签名引用了被裁剪的符号报告过期只是api:check失败的一种原因。文档特别强调如果一份报告最终引用了它从未声明的符号检查同样会失败——此时报告描述了一个没有任何东西定义它的类型而重新生成无法修复这个问题必须回到源码去修。这种失败在实践中的典型成因是一个public符号的签名引用了被标记为internal/ignore的符号于是被引用的类型在裁剪trim过程中从报告里被抽走留下一个悬空引用。修复方式二选一去掉被引用类型的裁剪标签——它既然能从公共 API 被触达用户本就可以依赖它应当将其纳入公开表面把它移出公共签名——保持其内部性质不让公共接口引用它。另外文档给出一个重要的约定未打标签的符号默认为公开public。代码库遵循未标记即公开的约定并不使用显式的public标签。因此在决定给某符号打internal前需要先想清楚它是否真的不会被任何公共签名引用。五、裁剪规则与public变体只追踪真正公开的表面报告按 API Extractor 的public变体生成意味着所有被标记为internal以及alpha、beta的符号都会被排除只有public表面被追踪。此外遗留的ignore标签在这里被视同internal——生成器会在提取前先将其改写因此被ignore的符号同样被排除且不能被public签名引用生成器会先把public变体暂存为name.public.api.md放在docs/public-api/temp/下再提升promote为已提交的name.api.md从而保证被追踪的文件名保持稳定同时docs/public-api/temp/目录本身是 git-ignored 的中间产物。这套暂存变体 提升的策略让生成中间结果与提交最终报告两个动作解耦既方便本地调试又不污染版本库。六、死导入清理API Extractor 的固有缺陷与后处理补救API Extractor 有一个行为特点它在裁剪非public声明之前就构建导入import列表且之后不会回头重新审视。由此产生一个问题——一个仅被某个internal成员可达的类型会以裸导入的形式残留在报告中看起来像公共表面实则并非如此。文档明确指出 API Extractor 没有针对此行为的配置选项因此生成器对每份报告做了后处理解析报告内的 fenced TypeScript 代码块删掉那些绑定未被任何裁剪后幸存声明引用的导入。类似地因为 API Extractor 在public裁剪前就会给出各种符号的声明报告中也可能出现仅被永远不会进入报告的成员可达的声明。生成器采用与清理死导入相同的方式将其剔除保证报告不携带任何它自身未引用的内容同时只有被标记为ae-forgotten-export的符号才参与该剔除流程从而避免误伤真正可达的声明——例如crawlee/utils中通过declare namespace块暴露成员的social命名空间在 docs/public-api/crawlee-utils.api.md 中可以看到declare namespace social { ... }的形态这些合法声明得以完整保留。七、Forgotten exports被引用但不被导出的类型公共 API 中有一类特殊成员类型被公共 API 引用但入口文件从未导出它。通过includeForgottenExports这类成员也会被纳入报告并带有一段显式横幅// Not exported by the entry point; reachable only as a referenced type. // public (undocumented) interface SitemapUrlData {这段横幅传达了两个层面的语义它们的**形状shape**属于承诺不破坏的表面——只要公共签名引用了它们用户就能间接依赖其结构但它们的名字name不可导入——所以报告中它们以不带export的形式输出。为什么这么做因为 API Extractor 会把它们像其他任何成员一样标记为public (undocumented)乍看之下与真正的导出难以区分因此才需要额外横幅提示。文档给出了设计权衡如果反过来把每个此类类型都从所属包导出将新增约38 个新的公共导出等于把一批从未打算发布的名称也纳入了兼容承诺而当前方案既保护了形状、又不承诺名称。如果你确实希望某个类型可被导入就有意地显式导出它报告会相应以带export的形式展示。从当前仓库的统计数据看这种被遗忘导出在crawlee/core报告中出现约 18 处、crawlee/browser-pool约 6 处、crawlee/playwright约 6 处、crawlee/utils约 4 处说明它在核心与浏览器相关包中并非罕见值得在使用这套报告时留意横幅标注。八、排除列表为什么 CLI 与模板不在报告内crawlee/cli和crawlee/templates两个包被刻意排除在报告体系之外。原因很直接它们属于工具链一个 CLI 二进制和项目脚手架不是用户以import方式消费、需要承诺向后兼容的可导入 API。排除列表随--exclude参数传入报告生成器即 package.json 中api:extract/api:check脚本里写死的那两个包名。这一设计说明公共 API 表面映射服务的对象是可作为库导入的包而非所有发布物——把不承诺 BC 的工具包排除在外可以让报告的兼容承诺边界更清晰、更准确。九、与发布流程的衔接快照即契约这套报告不仅服务于日常开发还深度参与了发布与分支管理。在 RELEASE.md 中可以看到发布流程明确要求 CI 执行api:check、测试套件和网站构建而在处理 master 分支的功能合并时还特别提示要比较公共 API 快照docs/public-api/以防只存在于 master 的新特性在 rebase 中静默丢失。可见报告已被当作跨分支、跨版本的接口契约快照来使用。十、现状与展望从打标签隐藏到真正隐藏文档最后点明了这套机制的当前边界与演进方向报告目前仅覆盖public表面诸如未打标签的protected成员或_前缀成员仍会以公开面貌出现在报告中。进一步收缩报告体积——即真正隐藏类的内部实现而非仅仅打标签——是仓库在 issue #3109 中追踪的目标。也就是说当前的打标签机制是兼容性承诺的第一道防线而后续版本可能走向更严格的可见性控制。小结Crawlee 的docs/public-api/报告体系本质上是把向后兼容承诺工程化、自动化、可审计化的一次实践用 API Extractor 从构建产物提取公共类型表面用pnpm api:extract生成、pnpm api:check在 CI 中强制校验用public变体裁剪掉内部符号用后处理清理死导入用横幅标注不可导入的被引用类型并刻意排除 CLI 与模板这类非库形态的包。对于任何一个维护多包、多版本、且对 API 稳定性有硬性要求的 TypeScript 项目这套生成—提交—校验—评审的闭环都值得直接复用。【免费下载链接】crawleeCrawlee—A web scraping and browser automation library for Node.js to build reliable crawlers. In JavaScript and TypeScript. Extract data for AI, LLMs, RAG, or GPTs. Download HTML, PDF, JPG, PNG, and other files from websites. Works with Puppeteer, Playwright, Cheerio, JSDOM, and raw HTTP. Both headful and headless mode. With proxy rotation.项目地址: https://gitcode.com/GitHub_Trending/cr/crawlee创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考