ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Umi 4 代码拆分实战指南:按页拆包、splitChunks 策略与产物分析

Umi 4 代码拆分实战指南:按页拆包、splitChunks 策略与产物分析 Umi 4 代码拆分实战指南按页拆包、splitChunks 策略与产物分析【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umiUmi 4 开箱即用地按路由页面拆包并按需加载同时通过codeSplitting配置提供了bigVendors、depPerChunk、granularChunks三种公共依赖提取策略配合React.lazy手动拆分和ANALYZE产物分析可以系统性地控制应用产物体积与加载性能。本文以官方《代码拆分指南》为主线结合 codeSplitting 插件源码 深入讲解每种策略的底层分包逻辑与适用场景帮助你为项目选择并落地合适的分包方案。默认行为按页拆包、按需加载Umi 4 默认即开启按页拆包Route-based Code Splitting——以路由为分界把页面拆成独立 chunk用户访问某个路由时才按需加载对应的 JS。这与 Umi 3 中通过dynamicImport配置开启的效果近似但现在是内置默认行为无需任何额外配置。相关说明见 配置文件 API 文档 中 codeSplitting 一节Umi 默认以路由为分界拆分 chunk实现路由维度的 chunk 按需加载。按页拆包带来的直接结果是页面切换时存在一个加载过程。为此 Umi 4 提供了约定式文件src/loading.(tsx|jsx)作为全局加载组件在页面 chunk 加载期间展示自定义加载动画。例如// src/loading.tsx export default function Loading() { return div页面加载中.../div; }该文件位于src目录约定结构之下见 目录结构文档 中loading.(tsx|jsx)一节Umi 会识别它并在路由级 chunk 加载时自动渲染。使用分包策略codeSplitting 配置当项目规模变大、多个页面共享大量第三方依赖时按页拆包会导致公共依赖在多个 chunk 中重复打包。此时可以在配置文件中开启codeSplitting进一步提取公共 chunk。// .umirc.ts export default { codeSplitting: { jsStrategy: granularChunks, }, };配置类型为类型{ jsStrategy: bigVendors | depPerChunk | granularChunks; jsStrategyOptions: {} }默认值null从 codeSplitting 插件源码 可以看到该配置的完整 schemajsStrategy限定三个枚举值同时支持可选的jsStrategyOptions透传对象以及一个暂未实现的cssStrategy。插件通过enableBy: api.EnableBy.config控制即只有显式配置了codeSplitting时策略才会生效且chainWebpack中在api.env ! production时直接返回说明这些分包策略仅在 production 构建时应用开发环境不受影响。三种策略的差异如下。bigVendors大 vendors 方案bigVendors会把所有async chunk异步 chunk中来自node_modules的依赖统一打包进一个名为vendors的 chunk// 源码实现节选 memo.optimization.splitChunks({ cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: 10, name: vendors, chunks: async, ...jsStrategyOptions, }, }, });优点只产出一个 vendors 包避免了依赖在多个页面 chunk 间的重复。缺点官方文档明确指出的两点单文件尺寸过大首屏需要下载整个 vendors 包毫无缓存效率可言——只要任意一个依赖升级整个 vendors 包都会失效重新下载。depPerChunk按依赖粒度拆分depPerChunk与bigVendors类似区别在于把依赖按 package name含 version逐一拆分每个依赖独立成 chunk// 源码实现节选 name(module: any) { const path module.context.replace(/.pnpm[\\/]/, ); const match path.match(/[\\/]node_modules[\\/](https://link.gitcode.com/i/edd8149cd837e5572d2fa250d4c550b9)([\\/]|$)/); if (!match) return npm.unknown; const packageName match[1]; return npm.${packageName.replace(//g, _at_).replace(/\/g, _)}; }从源码看chunk 命名规则为npm.packageName其中会被替换为_at_如lodash-es之于 scoped 包、会被替换为_保证 chunk 文件名合法。还处理了 pnpm 的.pnpm目录结构。优点解决了bigVendors的单文件过大与缓存失效问题——升级单个依赖只影响该依赖自己的 chunk。代价请求数量可能明显增多。官方文档的看法是对于非大型项目来说影响不大因为 1单个页面的请求通常不会包含非常多依赖2基于 HTTP/2几十个请求并不算问题但大型或巨型项目需要考虑更合适的方案。granularChunks细粒度分包推荐granularChunks在两者之间取了中间值同时对缓存利用更友好。它的splitChunks配置包含三个 cacheGroup见 源码cacheGroup命中规则关键参数效果framework命中FRAMEWORK_BUNDLES列表react、react-dom、history、react-router、react-router-dom、schedulerchunks: all、priority: 40、enforce: true框架代码单独打包成frameworkchunk任何页面都命中缓存libnode_modules中体积大于 160000 字节约 156 KB的模块priority: 30、minChunks: 1、chunks: async大依赖单独成包命名形如依赖名-lib避免与业务代码混杂shared被至少 2 个 chunk 共享的模块priority: 10、minChunks: 2、chunks: async公共代码按共享 chunk 组合生成shared-sha1 哈希包哈希随组合变化而变值得注意的实现细节framework组的FRAMEWORK_BUNDLES列表中core-js、regenerator-runtime被注释掉renderer-react标注了 TODO说明该策略仍在演进中shared组的命名通过对参与共享的 chunk 名称做 SHA-1 哈希生成并替换掉 URL 中可能转义的/字符源码注释引用了 umi issue #9845lib组的命名优先取module.rawRequest对相对路径如require(../../lib/codemirror)会先去掉前导.和/再替换为合法文件名isModuleCSS会排除各类 CSS 提取插件产出的模块避免 CSS 被误分进 JS 包。官方建议无特殊场景优先使用granularChunks策略。jsStrategyOptions 与 cssStrategyjsStrategyOptions为可选对象会通过...jsStrategyOptions展开合并进对应 cacheGroup可用于微调优先级、minChunks、reuseExistingChunk等 splitChunks 参数cssStrategy目前仅定义了枚举mergeAll但源码中一旦配置即抛出codeSplitting.cssStrategy is not supported yet错误说明CSS 拆分策略尚未支持生产项目请勿配置此项。手动拆分React.lazy Suspense当产物体积变大自动分包策略之外还需要更精细的控制时可以手动拆包。最常见的场景是手动拆分引用了较大第三方库的组件使其在需要时才加载import { lazy, Suspense } from react; // ./Page 该组件将被自动拆出去 const Page lazy(() import(./Page)); export default function () { return ( Suspense fallback{divloading.../div} Page / /Suspense ); }这里lazy(() import(./Page))使用动态import()语法webpack 会自动将./Page及其依赖拆分为独立 chunkSuspense的fallback则指定了 chunk 加载期间渲染的占位 UI。提示原文档示例中fallback的 JSX 结尾为divloading.../div缺少闭合标签/div本文已修正为可运行版本。配合手动拆分的典型实践对体积较大的图表库、代码编辑器、富文本编辑器等按需引入对低频页面如设置页、帮助页单独拆包结合路由级加载组件src/loading.(tsx|jsx)为手动拆分的组件提供统一的全局加载态。分析产物构成ANALYZE 环境变量拆包策略是否合理、依赖是否被正确提取需要通过产物分析来验证。Umi 提供了ANALYZE环境变量用于分析 bundle 构成ANALYZE1 umi build根据 环境变量文档 中的说明ANALYZE用于分析 bundle 构成默认关闭。构建完成后会生成可视化的产物构成分析结果你可以据此查看各 chunk 的体积占比定位过大的依赖或业务模块确认公共依赖是否被正确提取到framework/lib/shared或vendors/npm.*等 chunk结合分析结果决定调整codeSplitting策略、用React.lazy手动拆分大组件或通过jsStrategyOptions微调分包参数。建议在每次调整分包配置后都跑一次ANALYZE对比不同策略下的 chunk 数量与体积用数据驱动决策。小结Umi 4默认按路由页面拆包并按需加载src/loading.(tsx|jsx)用于定制页面加载动画需要提取公共依赖时通过 codeSplitting 配置 开启jsStrategybigVendors简单但体积与缓存差depPerChunk按依赖拆细但请求多granularChunks综合最优、官方推荐三种策略的完整实现可在 packages/preset-umi/src/features/codeSplitting/codeSplitting.ts 中查看它仅在 production 构建、且显式配置时生效cssStrategy尚未支持针对大体积第三方库组件使用React.lazySuspense手动拆包最后用ANALYZE1 umi build分析产物构成持续验证与优化分包效果。【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表