通过 chunk 哈希解析 Angular 构建产物 X.vendor.js 与 X.main.js

下文先用一段概要勾勒核心结论,再逐层剖析生成机制、文件职责、命名规律以及可验证的示例代码。

在一个由 Angular CLI 构建或 ng serve 热重载的应用里,开发者通常会在浏览器 Sources 面板看到形似 e3f4c.vendor.jse3f4c.main.js 等文件。e3f4c 这一段其实是由 output-hashing 机制按照 内容哈希contenthash/chunkhash)自动生成,用来实现精细的长效缓存;vendor 代表 第三方依赖代码块main 代表 业务入口代码块。二者都由 Angular CLI 内置的 @angular-devkit/build-angular 构建器在 TypeScript → esbuild/webpack → 浏览器可执行文件 的流水线中自动拆分,并且在 ng buildng serve 时机根据 angular.json 中的 vendorChunkoptimizationoutputHashing 等选项确定是否拆分、何时注入哈希、最终写入 dist/ 或内存文件系统。


文件命名结构与 X 的含义

  • 构建管线在生成最终脚本资源时,会为每一个 entry chunk 计算内容摘要;摘要通常被截断为 4-8 位十六进制字符,例如 e3f4c。这一段对应问题中的 X,并随 output-hashing 配置决定是否出现以及出现位置(stackoverflow.com, angular.dev)。

  • outputHashing 取值 bundlesall(生产环境默认)时,每个 bundle 名都会带上哈希,以确保内容变化必然导致 URL 变化,浏览器即可对未变更的老文件做到“永久缓存”(reddit.com)。

  • 在开发环境下若 outputHashing 设为 none,则编译器仅保留逻辑名称,不会带哈希,调试会更直观,也便于 HMR 增量替换(github.com)。


vendor 块承担什么职责

  • vendor.jsSplitChunksPlugin(Webpack 5)或 esbuild 的 splitting 逻辑按“来自 node_modules 的依赖”规则抽取生成,专门放置 Angular 框架、RxJS、第三方 UI 组件库等不常变动的大体量代码(chitaranjanbiswal93.medium.com, justjeb.medium.com)。

  • 把庞大的外部依赖与业务代码隔离,可使首次加载后浏览器对 vendor 建立独立 HTTP 缓存;只要依赖版本没变,后续上线仅更新 main ,可极大降低增量发布流量(stackoverflow.com)。

  • angular.jsonbuild.options.vendorChunk 默认为 true;若显式改为 false,拆分逻辑会被关闭,依赖被内联入对应 entry(如 main),适合极简微应用或离线扩展场景(preemptive.com, angular.dev)。


main 块承担什么职责

  • main.jsbrowser 入口(即 src/main.ts)经过 AOT/JIT 编译、tree-shakingts-transpile 后产出,包含应用启动引导(platformBrowserDynamic().bootstrapModule(...))、所有惰性加载之外的业务组件、服务与样式引用(stackoverflow.com)。

  • 当启用差分编译时,CLI 会为现代浏览器与旧版浏览器各生成一组 main-es20XX.jsmain-es5.js 文件,并在 index.html 里通过 <script type="module"> / <script nomodule> 标签自动分发(stackoverflow.com)。


生成时机、地点与流水线

  1. 触发命令ng build --configuration productionng serve。前者把文件写入 dist/project-name/,后者使用内存 dev-server 提供(angular.dev)。

  2. 编译阶段@angular-devkit/build-angular 根据 angular.json 读取 browser target,调用 esbuild(Angular 17+)或 webpack(旧版)编译 TypeScript 及模板。

  3. Chunk 拆分

    • esbuild 原生 splitting: true 配合 format:"esm" 把依赖收敛进 vendor;webpack 旧链路则通过 optimization.splitChunks.cacheGroups.vendor 规则实现(webpack.js.org)。
  4. 哈希注入:构建器根据 outputHashingcontenthash 追加到文件名;相同 chunk 内容不变时哈希保持不变,浏览器即可利用 304 缓存(stackoverflow.com)。

  5. 写入或注入:生产构建将物理文件输出到 dist/;开发构建通过 Webpack dev-middleware 注入到内存,浏览器仍以 URL 形式访问。


可运行示例(Angular 17.x)

# 初始化项目
npm create @angular@latest sample-hash-demo -- --routing --style scss
cd sample-hash-demo

# 修改 angular.json,显式保留 vendor 块并打开所有哈希
npx jq '.projects["sample-hash-demo"].architect.build.options.vendorChunk=true |
        .projects["sample-hash-demo"].architect.build.configurations.production.outputHashing="all"' \
        angular.json > tmp && mv tmp angular.json

# 添加一个第三方依赖以观察 vendor 增长
npm i lodash-es

# 在任何组件里引用
echo "import pad from 'lodash-es/pad'; console.log(pad('hash',10,'-'));" >> src/main.ts

# 产出构建物
ng build --configuration production

执行完毕后,可在 dist/sample-hash-demo/browser/ 目录看到类似下列文件清单:

e3f4c.vendor.js
e3f4c.vendor.js.map
e3f4c.main.js
e3f4c.main.js.map
e3f4c.polyfills.js
e3f4c.runtime.js
index.html

vendor 大小会因 lodash-es 明显增大,而 main 只收录业务组件与少量 bootstrap 代码;若再次修改业务组件但不变更依赖,重新构建后 main 的哈希将改变,而 vendor 的哈希保持 e3f4c 不变,恰好验证了长效缓存设计。


命名细节与调试提示

  • 调试源码映射:CLI 总是在非优化模式下为 mainvendor 生成 .map 文件,便于 Chrome 对应到 .ts 源文件(stackoverflow.com)。

  • 哈希过长:可通过 namedChunks:true 保留原有名字(main.jsvendor.js),但生产环境并不推荐,因为会破坏缓存粒度(angular.dev)。

  • 禁用 vendor 拆分:在极简脚本或扩展场景中,可将 vendorChunk:false,此时所有第三方模块连同业务代码被并入 main,减少一次请求,但也失去了依赖层面的缓存优势(justjeb.medium.com, stackoverflow.com)。


参考线上资料

  1. Medium 文章对各 bundle 职责的解释(chitaranjanbiswal93.medium.com)

  2. StackOverflow 对 main.jsvendor.js 的条目式说明(stackoverflow.com)

  3. Medium 讨论 vendorChunk 开关及性能影响(justjeb.medium.com)

  4. Webpack 官方文档 SplitChunksPlugin 关于默认命名规则解释(webpack.js.org)

  5. StackOverflow 关于是否在生产中启用 vendorChunk 的探讨(stackoverflow.com)

  6. Angular 新构建系统迁移指南指出已弃用 vendorChunk 选项(angular.dev)

  7. JSDefender 文档示例展示如何在 Angular 中使用 --vendorChunk=true(preemptive.com)

  8. CLI 文档 ng build 关于 outputHashing 的说明(angular.dev, angular.dev)

  9. StackOverflow 回答总结四种 --output-hashing 模式(stackoverflow.com)

  10. Reddit 讨论说明哈希一致性与缓存关系(reddit.com)

  11. GitHub issue 展示差异化构建产物包含 es2020es5 文件(stackoverflow.com)

  12. Split vendor 方案及性能讨论(justjeb.medium.com)

  13. Webpack issue 关于默认命名 vendors~main.js 的描述(webpack.js.org)

  14. Angular CLI serve 旧文档里 --vendor-chunk 开关(angular.ossez.com)

  15. 粗略文件清单与输出示例 StackOverflow 讨论(chitaranjanbiswal93.medium.com, stackoverflow.com)

这些来源交叉印证了命名规则、拆分策略与缓存原理,使得开发者可以在浏览器调试界面迅速判断脚本职责、找准潜在优化点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪子熙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值