ARTICLE DETAIL

资讯详情

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

razzle-plugin-manifest 使用指南:为 Razzle 拆分产物自动生成 chunks.json 资源清单

razzle-plugin-manifest 使用指南:为 Razzle 拆分产物自动生成 chunks.json 资源清单 razzle-plugin-manifest 使用指南为 Razzle 拆分产物自动生成 chunks.json 资源清单【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址: https://gitcode.com/gh_mirrors/ra/razzle本文介绍 Razzle 官方插件生态中的razzle-plugin-manifest它能在构建期自动为服务端渲染SSR场景生成一份名为chunks.json的资源清单文件把 Webpack 拆分出的所有 JS / CSS chunk 与入口entrypoint的对应关系固化下来并通过RAZZLE_CHUNKS_MANIFEST环境变量暴露给应用代码。读完本文你将掌握该插件的安装、默认配置与产物结构理解其底层基于webpack-manifest-plugin与modifyWebpackConfig钩子的实现原理并能在src/server.js中用它动态渲染正确的link/script标签。插件定位解决服务端如何知道该引用哪些静态资源的问题在 Razzle 这类 universal同构 / SSR应用中同一份代码会被分别构建成client与server两个目标。浏览器端加载的 JS 与 CSS 文件名中包含由 Webpack 生成的内容哈希如main.9f1a2b.js还会因代码拆分code splitting产生大量异步 chunk。服务端在渲染 HTML 时必须在构建完成之后才能知道确切的静态资源 URL——这正是 manifest 文件的用武之地。razzle-plugin-manifest的官方定位见 packages/razzle-plugin-manifest/README.md是generating manifest file for splitted chunk paths with Razzle即为 Razzle 构建中拆分出的 chunk 路径生成清单文件。它属于 Razzle 插件体系中的构建期插件只负责在编译时产出数据文件不参与运行时逻辑因此对应用代码的侵入极小。安装插件插件与 Razzle 主包、razzle-dev-utils以 peer 依赖方式配套发布当前仓库中其版本为4.2.18见 packages/razzle-plugin-manifest/package.json依赖webpack-manifest-plugin^4.0.2。在项目根目录执行npm i razzle-plugin-manifest或使用 yarnyarn add razzle-plugin-manifest由于它声明了razzle与razzle-dev-utils的 peerDependencies安装时请确保项目中已存在对应版本的 Razzle即razzle与razzle-dev-utils均来自 4.x 系列避免出现 peer 依赖缺失告警。快速开始使用默认配置在项目根目录的razzle.config.js中将插件名以字符串形式写入plugins数组即可启用无需任何额外参数// razzle.config.js module.exports { plugins: [manifest], };这里需要说明插件名简写的解析机制Razzle 的插件加载器packages/razzle/config/loadPlugins.js会对plugins数组中的每一项做规范化处理——传入字符串manifest时会依次尝试解析razzle-plugin-manifest等完整包名同时兼容 scoped 包与{name}/razzle-plugin两种形态找到后以默认空选项{}调用。因此manifest实际等价于完整写法razzle-plugin-manifest。启用后每次构建时都会在 build 目录下生成一个名为chunks.json的文件。构建目录由 Razzle 的路径配置决定在 packages/razzle/config/paths.js 中appBuild被定义为项目根目录下的build因此默认产物路径为项目根/build/chunks.json。随后即可在代码中通过RAZZLE_CHUNKS_MANIFEST环境变量导入该文件const chunks require(process.env.RAZZLE_CHUNKS_MANIFEST);RAZZLE_CHUNKS_MANIFEST由插件在构建期通过 Webpack 的DefinePlugin静态注入为chunks.json的绝对路径详见下文底层原理因此该require在构建产物中会被替换为对真实文件路径的引用属于典型的构建期环境变量区别于运行时由 dotenv 注入的变量。Razzle 官方环境变量文档website/pages/docs/environment-variables.md中也收录了同样的用法示例。chunks.json 的产物结构与字段语义理解chunks.json的结构是正确消费它的前提。其数据由插件源码中的generate函数计算得出见 packages/razzle-plugin-manifest/index.js整体是一个以入口entrypoint名称为键的对象每个入口的值形如{ client: { css: [/static/css/main.9f1a2b.css], js: [/static/js/main.9f1a2b.js, /static/js/vendor.c3d4e5.js], chunks: [0, 1] } }各字段含义如下顶层键入口名称。取自entry.options.name若未显式命名则回退到runtimeChunk.name再回退到entry.id。Razzle 默认的客户端入口名为client这也是官方示例中总以chunks.client取用的原因。css该入口关联的全部 CSS 文件 URL已拼接webpackConfig.output.publicPath前缀下同。js该入口关联的全部 JS 文件 URL包括入口主 bundle 与其同步依赖的 chunk。chunks该入口下所有 chunk 的 id 数组便于在需要按 id 追踪加载状态时使用。注意几个实现细节仅收集 chunk 文件插件通过filter: item item.isChunk过滤掉非 chunk 资源如 public 目录拷贝的静态文件确保清单只包含编译产物。按 entrypoint 聚合generate先遍历所有文件反向收集它们所属的_groupsWebpack 4 的 entrypoint 概念再按入口聚合其下所有 chunk 的文件列表——这正是为拆分出的 chunk 路径生成清单的核心逻辑。JS / CSS 分类对每个文件 URL 按.css与.js后缀分别归入cssFiles与jsFiles因而清单天然可用于分别渲染link与script标签。默认只作用于 web 目标插件源码中if (target web)的判断index.js意味着WebpackManifestPlugin仅注入到客户端构建因为只有客户端构建的产物才需要被浏览器加载。在服务端渲染中使用 chunks.jsonchunks.json最典型的应用场景是替代手写死路径的静态link/script标签。Razzle 官方文档website/pages/docs/environment-variables.md给出了完整的src/server.js示例核心片段如下import App from ./App; import React from react; import express from express; import { renderToString } from react-dom/server; import serialize from serialize-javascript; // Safer stringify, prevents XSS attacks import { runtimeConfig } from ./config; const chunks require(process.env.RAZZLE_CHUNKS_MANIFEST); const server express(); 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 ${chunks.client.css.map(path link relstylesheet href${path})} /head body div idroot${markup}/div scriptwindow.env ${serialize(runtimeConfig)};/script ${chunks.client.js.map(path script src${path} defer crossorigin/script)} /body /html ); }); export default server;这一用法带来三重收益哈希免维护chunks.client.js/chunks.client.css中的文件名由构建期自动填写代码改动导致哈希变化时无需手工更新模板。自动包含 vendor 等公共 chunk若通过optimization.splitChunks拆出 vendor 包其 URL 会一并出现在js数组中服务端无需知道拆分策略的细节。crossorigin与defer可控由于是自行拼接标签可自由决定是否添加crossorigin配合 CDN / 修改 publicPath 的场景Razzle 官方建议在PUBLIC_PATH指向 CDN 时为script加上该属性与defer等属性。底层原理modifyWebpackConfig 钩子与 DefinePlugin 注入该插件是一个标准的 Razzle 插件对象导出modifyWebpackConfig钩子函数index.jsRazzle 会在每个目标client / server的 webpack 配置组装阶段调用它调用点位于 packages/razzle/config/createConfigAsync.js。其内部做了两件事1. 注入WebpackManifestPlugin仅 web 目标webpackConfig.plugins.push( new WebpackManifestPlugin({ fileName: pluginOptions.fileName, writeToFileEmit: true, filter: item item.isChunk, generate: /* 上文描述的聚合逻辑 */, }) );fileName默认值为path.join(paths.appBuild, chunks.json)即build/chunks.json可通过插件选项覆盖见下文。writeToFileEmit: true确保即使在使用内存文件系统的 dev server / watch 模式下也会把清单写入磁盘保证开发期服务端也能读到文件。generate回调接收(seed, files)从files反向还原 entrypoint 分组输出前文描述的结构。2. 注入环境变量RAZZLE_CHUNKS_MANIFEST所有目标webpackConfig.plugins.push( new webpackObject.DefinePlugin({ process.env.RAZZLE_CHUNKS_MANIFEST: JSON.stringify(pluginOptions.fileName), }) );DefinePlugin会在编译期把代码中出现的process.env.RAZZLE_CHUNKS_MANIFEST字面替换为清单文件的绝对路径字符串因此require(process.env.RAZZLE_CHUNKS_MANIFEST)无需在运行时依赖真实 shell 环境变量即可工作。这符合 Razzle 对RAZZLE_前缀构建期变量的约定——它们由构建工具在编译时内联进产物见 website/pages/docs/environment-variables.md 中Build-time Variables一节。自定义输出位置通过插件选项覆盖 fileName虽然插件默认开箱即用其modifyWebpackConfig钩子从options.pluginOptions中读取配置index.js因此你可以通过 Razzle 的数组式插件写法覆盖fileName把清单输出到自定义路径// razzle.config.js module.exports { plugins: [ [ manifest, { pluginOptions: { fileName: /absolute/path/to/my-chunks.json, }, }, ], ], };在 Razzle 的插件配置约定中plugins数组项既可以是一个简写字符串也可以是[插件名, 插件选项]的二元组——加载器loadPlugins.js会把二元组的第二项作为options传入插件的钩子。覆盖后生成的清单文件与RAZZLE_CHUNKS_MANIFEST指向的路径会同步变更二者始终一致无需额外处理。注意fileName需要是绝对路径因为webpack-manifest-plugin直接将其作为写入目标。注意事项与适用前提仅适用于 Razzle 4.x插件的 peerDependencies 明确要求razzle4.2.18与razzle-dev-utils4.2.18使用其他大版本时需确认插件 APImodifyWebpackConfig、paths.appBuild等是否兼容。依赖 Webpack 的 entrypoint 分组信息generate逻辑依赖chunk._groupsentrypoint内部结构因此它面向的是 Webpack 4 构建链路若未来 Razzle 升级到 Webpack 5 并改变分组数据结构清单聚合行为可能随之变化这一点可从源码对_groups的遍历看出。清单是构建期产物chunks.json在每次razzle build以及 dev 模式下的监听构建时重新生成不应手工编辑若服务端进程长期运行且使用了缓存需确保读取的是最新生成的构建目录。与RAZZLE_ASSETS_MANIFEST的区别Razzle 内置的RAZZLE_ASSETS_MANIFESTbuild/assets.json记录的是编译输出的扁平资源映射而本插件生成的是按入口聚合、区分 css/js/chunks 的服务端渲染专用视图两者用途不同可按需取用。小结razzle-plugin-manifest以极小的配置成本一行plugins: [manifest]解决了 SSR 应用中最棘手的构建产物路径与入口映射问题安装后构建即生成build/chunks.json并通过RAZZLE_CHUNKS_MANIFEST暴露给代码其实现建立在 Razzle 的modifyWebpackConfig插件钩子与webpack-manifest-plugin之上用约 80 行源码完成了 entrypoint 聚合、css/js 分类与路径拼接是理解 Razzle 插件机制与 manifest 消费流程的一个简洁范本。相关实现与文档可直接在本仓库中查阅插件源码、插件说明、插件元信息、环境变量文档 以及 插件加载机制。【免费下载链接】razzle✨ Create server-rendered universal JavaScript applications with no configuration项目地址: https://gitcode.com/gh_mirrors/ra/razzle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表