ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Razzle 自定义 Webpack 配置实现 Vendor Bundle 分包实战(with-vendor-bundle 示例深度解析)

Razzle 自定义 Webpack 配置实现 Vendor Bundle 分包实战(with-vendor-bundle 示例深度解析) 前端构建工具前端构建后端【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址https://gitcode.com/gh_mirrors/ra/razzle点击查看免费下载导读本篇技术指南以 examples/with-vendor-bundle 示例为核心完整讲解如何在 Razzle 的零配置体系之上通过razzle.config.js的modifyWebpackConfig钩子深度定制底层 webpack 配置把 React、ReactDOM 等第三方依赖抽离为独立 vendor 分包并同步改造服务端 HTML 模板与开发期错误覆盖层路径。读完本文你将掌握一套可直接复制的Razzle 手动 vendor bundle实战方案理解 Razzle 配置钩子的调用时机、assets manifest 的生成规则以及为什么开发与生产环境需要不同的脚本标签写法。示例概览与运行方式该示例位于仓库 examples/with-vendor-bundle其package.json依赖了react^17.0.1、react-dom^17.0.1、express^4.17.1构建工具链为razzle4.2.15与webpack^4.44.1。按照示例 README 提供的标准流程创建并启动npx create-razzle-app --example with-vendor-bundle with-vendor-bundle cd with-vendor-bundle yarn start启动后项目在http://localhost:3000通过src/index.js中的process.env.PORT || 3000提供服务。除yarn start开发模式外示例package.json还提供yarn build生产构建与yarn start:prod以NODE_ENVproduction node build/server.js运行生产构建产物等脚本可用于验证 vendor 分包在生产构建中的真实效果。思路为什么要把第三方依赖拆成 vendor 分包这个示例的核心思想源自 Twitter Lite 的高性能 React PWA 实践Paul Armstrong 的 Medium 文章把 React、ReactDOM 这类极少变动、体积巨大的第三方库从业务代码中独立出来单独打成一份 vendor bundle。带来的收益包括缓存友好vendor 分包只有在依赖升级时才会产生新的内容 hash业务代码每次发布产生的 hash 变化不会波及 vendor 文件浏览器可以长期命中缓存的 vendor 资源体积可控业务 bundle 中不再重复打包第三方依赖首屏需要传输的业务字节显著减少便于长期优化vendor 文件可以进一步配合defer加载、CDN 预置等手段做性能调优。示例 README 中有一句点睛之笔m.twitter.com 本身并不做服务端渲染所以这套服务端渲染 vendor 分包的构建工具链甚至比 Twitter Lite 的构建方案更进一步。第一步通过 modifyWebpackConfig 钩子改造 webpack 配置Razzle 的核心设计是零配置可用、按需可覆盖。razzle.config.js是 Razzle 约定的配置文件源码层面由 packages/razzle/config/paths.js 中的appRazzleConfig: resolveApp(razzle.config.js)指定路径当文件存在时packages/razzle/config/loadRazzleConfig.js 会加载它随后 packages/razzle/config/createConfigAsync.js 在生成完整 webpack 配置后会调用其中的modifyWebpackConfig({ env, webpackConfig, webpackObject, options, paths })钩子让你拿到最终配置对象并自由修改。示例的 examples/with-vendor-bundle/razzle.config.js 完整代码如下use strict; module.exports { modifyWebpackConfig(opts) { const config opts.webpackConfig; // Change the name of the server output file in production if (opts.env.target web) { // modify filenaming to account for multiple entry files config.output.filename opts.env.dev ? static/js/[name].js : static/js/[name].[hash:8].js; // add another entry point called vendor config.entry.vendor [ require.resolve(react), require.resolve(react-dom), // ... add any other vendor packages with require.resolve(xxx) ]; config.optimization { splitChunks: { // Chunk splitting optimiztion chunks: all, // Switch off name generation, otherwise files would be invalidated // when more chunks with the same vendors are added name: false, }, }; } return config; }, };关键点一只在 web 目标上生效opts.env.target用于区分 Razzle 的两套独立 webpack 构建web客户端与node服务端。服务端构建在 createConfigAsync.js 中被设计为单 entryserver: [paths.appServerIndexJs]并限制单 chunkLimitChunkCountPlugin因此 vendor 拆分只对客户端有意义。示例用if (opts.env.target web)把全部改造限定在客户端配置上避免破坏服务端 bundle。关键点二多 entry 下必须自定义输出文件名Razzle 默认的客户端输出文件名只针对单一 entry 设计开发为static/js/bundle.js之类生产带 contenthash。一旦新增第二个 entryvendor[name]占位符就成了必需品。示例按环境区分开发环境static/js/[name].js无 hash便于 HMR 与调试生产环境static/js/[name].[hash:8].js8 位内容 hash用于缓存失效控制。关键点三vendor entry 与 splitChunks 的配合config.entry.vendor [ require.resolve(react), require.resolve(react-dom), // ... add any other vendor packages with require.resolve(xxx) ];这里用require.resolve把 React 与 ReactDOM 的入口模块显式声明为新的 vendor entrywebpack 会据此把这两个包及其内部依赖图完整提取到独立的 vendor chunk 中。需要追加其他第三方包时只需按注释所示继续追加require.resolve(xxx)。同时示例覆盖了config.optimization.splitChunksconfig.optimization { splitChunks: { chunks: all, name: false, }, };注释说明了name: false的动机关闭自动命名后当更多 vendor chunk 加入时不会因为同名冲突导致既有文件失效文件内容不变则 hash 不变缓存即可复用。值得注意的是Razzle 默认对 dev 与 prod 分别内置了splitChunksConfigs见 createConfigAsync.js其中cacheGroups.default与vendors均被禁用因此示例是在默认关闭 vendor 缓存组的基础上改用显式 entry 全局chunks: all的方式实现同样的目标。钩子执行时机说明从 createConfigAsync.js 的调用顺序可以确认modifyWebpackConfig在 webpack 基础配置entry、output、loader、plugin、optimization全部组装完毕之后执行且用户配置中的钩子最后调用插件钩子在前、用户钩子在后。因此你可以像示例一样直接改写config.output、config.entry、config.optimization无需关心底层配置如何生成。返回的config即最终生效的 webpack 配置。第二步在服务端 HTML 模板中按顺序引入多个脚本vendor 分包后构建产物不再只有一份client相关文件而是client、vendor等多个入口同时 Razzle 还会通过 webpack-manifest-plugin 生成 assets manifest。服务端必须显式把这些脚本按正确顺序写入 HTML。示例 README 给出的模板改造如下与示例源码 examples/with-vendor-bundle/src/server.js 的renderApp思路一致README 中为便于讲解直接内联了三组脚本标签// server.js // ... server .disable(x-powered-by) .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get(/*, (req, res) { const markup renderToString(App /); res.send( !doctype html html lang head meta http-equivX-UA-Compatible contentIEedge / meta charSetutf-8 / titleWelcome to Razzle/title meta nameviewport contentwidthdevice-width, initial-scale1 ${assets.client.css ? link relstylesheet href${assets.client.css} : } ${process.env.NODE_ENV production ? script src${assets.manifest.js} defer/script : script src${assets.manifest.js} defer crossorigin/script} ${process.env.NODE_ENV production ? script src${assets.vendor.js} defer/script : script src${assets.vendor.js} defer crossorigin/script} ${process.env.NODE_ENV production ? script src${assets.client.js} defer/script : script src${assets.client.js} defer crossorigin/script} /head body div idroot${markup}/div /body /html ); });这里的关键信息assets来自process.env.RAZZLE_ASSETS_MANIFEST即构建生成的assets-manifest.json该环境变量在 packages/razzle/config/env.js 中被注入manifest 文件本身由 createConfigAsync.js 中的ManifestPlugin按 entry 名生成。新增的vendorentry 会自然出现在 manifest 中所以assets.vendor.js可直接取到 vendor 文件的 URL脚本顺序至关重要manifest→vendor→client。webpack runtimemanifest 部分必须先加载然后 vendor 提供 React/ReactDOM 等运行时依赖最后才是业务代码开发与生产使用不同的属性生产模式用script src... defer/script开发模式额外加crossorigin。原因在于开发模式下客户端 bundle 由 webpack-dev-server 运行在http://localhost:3001跨端口HTML 页面localhost:3000通过 CORS 加载脚本crossorigin属性是错误覆盖层与 source map 正确工作所必需的。示例源码 examples/with-vendor-bundle/src/server.js 还封装了cssLinksFromAssets与jsScriptTagsFromAssets两个辅助函数用assets[entrypoint].css/js数组自动生成标签可复用同一套逻辑处理任意数量的入口与 CSS 文件。第三步用 REACT_DEV_BUNDLE_PATH 保住开发期错误覆盖层体验完成上述两步后开发环境下 React 的真实代码被搬到了 vendor bundlestatic/js/vendor.js里。如果不对 Razzle 做额外说明其内置的 webpack-hot-dev-client见 packages/razzle-dev-utils/webpackHotDevClient.js通过react-error-overlayErrorOverlay.startReportingRuntimeErrors把运行时错误渲染成覆盖页面error overlay而非输出到控制台而该机制需要知道 React 开发版 bundle 的位置。解决办法是在项目根目录创建.env文件写入REACT_DEV_BUNDLE_PATH/static/js/vendor.js这个相对路径指向开发模式下 vendor bundle 的公开路径。示例 README 明确说明通过这一行配置Razzle 就能把运行时错误管道进漂亮的错误覆盖层而不是退化成控制台日志——这是开发者体验DX层面的关键细节容易在手动改配置时被忽略。验证与运行以上三步全部完成后的效果验证方式yarn start启动开发服务器后访问http://localhost:3000浏览器 Network 面板应能看到static/js/vendor.js、static/js/client.js以及 webpack runtime 脚本分别作为独立请求加载。改用生产链路验证缓存效果yarn build yarn start:prod构建产物中会生成带 8 位 hash 的static/js/vendor.[hash:8].js且client与vendor的 hash 相互独立——后续只改动业务代码重新构建时vendor 文件 hash 保持不变这正是 vendor 分包实现长期缓存复用的核心收益。小结一份可复制的 Razzle 分包清单回顾整个示例在 Razzle 中实现 vendor 分包只需三步改构建在 razzle.config.js 的modifyWebpackConfig中为 web 目标新增config.entry.vendor并用[name]文件名与splitChunks配置保证多 entry 输出正确、缓存稳定改模板在服务端 HTML 中按manifest → vendor → client的顺序输出脚本并区分开发加crossorigin与生产纯defer两种写法保体验在.env中设置REACT_DEV_BUNDLE_PATH/static/js/vendor.js让开发期错误覆盖层继续正常工作。这三步分别对应构建配置层、服务端渲染层与开发工具层的配合体现了 Razzle零配置起步、配置钩子精准干预的设计哲学默认约定帮你跑起来modifyWebpackConfig这类钩子让你在需要时拥有对底层 webpack 的完整控制权钩子的完整参数与执行顺序可查阅 packages/razzle/config/createConfigAsync.js 与 packages/razzle/config/loadRazzleConfig.js。如果你想在自己的 Razzle 项目中应用此方案直接对照示例的三个文件改造即可。赞分享前端构建工具前端构建后端【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址https://gitcode.com/gh_mirrors/ra/razzle点击查看免费下载相关推荐Solar Pro Preview 社区支持与贡献指南如何参与模型改进与反馈Solar Pro Preview 社区支持与贡献指南如何参与模型改进与反馈 Solar Pro Preview 是一款高效的 220 亿参数大型语言模型专razzle-plugin-bundle-analyzer为 Razzle 应用接入 webpack-bundle-analyzer 包体积分析razzle plugin bundle analyzer为 Razzle 应用接入 webpack bundle analyzer 包体积分析 本指南围绕前端构建工具前端构建后端Webpack DLL 分包构建实战DllPlugin 与 output.library 将 vendor 与 app 分离dll-app-and-vendor 示例详解Webpack DLL 分包构建实战DllPlugin 与 output.library 将 vendor 与 app 分离dll app and vend前端构建开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表