Rollup 打包与许可证管理
Rollup 打包与许可证管理
学习目标
本章分析 Chrome DevTools MCP 的构建与打包策略。你将理解:
- 为什么需要 Rollup bundle(而非直接使用 TypeScript 编译结果)
- 多 bundle 入口设计:
third_party/index.js、devtools-formatter-worker.js、devtools-heap-snapshot-worker.js inlineDynamicImports: true的必要性- 许可证自动校验(白名单 +
failOnViolation) - Lighthouse 单独 bundle 的原因
chrome-devtools-frontend第三方库的手动许可证处理
项目实践
为什么需要 Bundle?
Chrome DevTools MCP 依赖以下大型库:
| 依赖 | 体积 | 特点 |
|---|---|---|
@modelcontextprotocol/sdk | 中 | MCP 协议实现 |
puppeteer-core | 大 | 浏览器自动化 |
lighthouse | 很大 | 性能审计引擎 |
chrome-devtools-frontend | 很大 | DevTools 前端代码 |
直接使用 tsc 编译后,node_modules 需要随 npm 包一起发布。Bundle 的作用:
- 减小体积:只打包实际使用的代码(tree-shaking)
- 消除外部依赖:bundle 后
node_modules不需要随包发布 - 许可证合规:自动收集所有依赖的许可证信息
多 Bundle 入口
rollup.config.mjs 定义了 3 个 bundle:
1. third_party/index.js → MCP SDK + Puppeteer + Lighthouse + 其他依赖 → 主 bundle,inlineDynamicImports: true
2. devtools-formatter-worker.js → DevTools 格式化器 Web Worker → 独立的 Worker 环境
3. devtools-heap-snapshot-worker.js → DevTools 堆快照分析 Web Worker → 独立的 Worker 环境inlineDynamicImports 的必要性
output: { inlineDynamicImports: true, format: 'esm',}inlineDynamicImports: true 将动态导入(import())内联到主 bundle 中。
为什么必须:MCP Server 通过 stdio 通信,如果 dynamic import 触发文件加载,可能因路径问题失败。内联后所有代码在同一个 bundle 中。
许可证自动校验
license({ thirdParty: { allow: { test: dependency => allowedLicenses.includes(dependency.license), failOnUnlicensed: true, failOnViolation: true, }, output: { file: './build/src/third_party/THIRD_PARTY_NOTICES', // 收集每个依赖的名称、URL、版本、许可证、许可证文本 }, },});白名单:
const allowedLicenses = [ 'MIT', 'Apache 2.0', 'Apache-2.0', 'BSD-3-Clause', 'BSD-2-Clause', 'ISC', '0BSD',];如果依赖使用了非白名单许可证(如 GPL),构建会直接失败,确保发布的 npm 包不含许可证风险。
自定义依赖收集插件
listBundledDeps() — 自定义 Rollup 插件: 1. 遍历 bundle 中所有模块 2. 通过文件路径反推所属 npm 包 3. 收集所有被打包的依赖名称 4. 生成 bundled-packages.json这个信息用于 npm 包的元数据,告知用户哪些依赖已被内嵌。
Lighthouse 单独 Bundle
Lighthouse 被单独打包为 lighthouse-devtools-mcp-bundle.js,原因:
- Lighthouse 体积大,单独 bundle 可按需加载
- 与 DevTools 前端有特殊集成(自定义 snapshot/navigation/generateReport 入口)
- 通过
third_party/index.js的 external 配置排除,避免重复打包
chrome-devtools-frontend 手动许可证处理
chrome-devtools-frontend 目录下有自己的第三方库(如 CodeMirror、marked 等),这些库不在 node_modules 中,因此 Rollup 的 license 插件无法自动检测。
处理方式:
// 遍历 tsconfig.json 中 include 的 third_party 目录const thirdPartyDirectories = tsConfig.include.filter( location => location.includes('chrome-devtools-frontend/front_end/third_party'));// 为每个目录读取 LICENSE 文件并追加到 THIRD_PARTY_NOTICES构建流程
设计取舍
| 取舍 | 选择 | 原因 |
|---|---|---|
| Rollup vs Webpack vs esbuild | Rollup | 对 ESM 支持好,适合库打包 |
| 单一 bundle vs 多 bundle | 多 bundle | Worker 需要独立环境,Lighthouse 按需加载 |
| 严格许可证 vs 宽松 | 严格 | Google 发布标准,避免法律风险 |
| tree-shaking vs 全量 | tree-shaking | Rollup 自动去除未使用代码 |
陷阱与对策
| 陷阱 | 后果 | 对策 |
|---|---|---|
| 新依赖使用了非白名单许可证 | 构建失败 | 添加依赖前检查许可证 |
inlineDynamicImports: false | stdio 模式下动态加载失败 | 必须设为 true |
| 忘记更新 bundled-packages.json | 用户不知道哪些依赖被内嵌 | 自定义 listBundledDeps() 自动生成 |