Umi 4 非现代浏览器兼容实践:从 targets 到 legacy mode 的完整指南
Umi 4 非现代浏览器兼容实践从 targets 到 legacy mode 的完整指南【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi导读Umi 4 默认将编译目标锁定在chrome: 80产物直接面向现代浏览器但当你的用户群体仍在使用旧版 Chrome、非现代内核浏览器甚至 IE 11 时就需要一套明确的降级方案。本文以 docs/docs/blog/legacy-browser.en-US.md 为骨架结合 Umi 仓库源码与配置文档系统讲解targets、legacy、extraBabelIncludes、headScripts等配置的用法与原理覆盖「轻度兼容」到「IE 11 全面降级」的完整链路读完即可在你的项目中落地可运行的兼容配置。默认兼容说明Umi 4 为什么不支持 IEUmi 4 默认不兼容 IE。其默认编译兼容目标targets为{ chrome: 80 }该默认值定义于 packages/bundler-webpack/src/constants.tsexport const DEFAULT_BROWSER_TARGETS { chrome: 80, };在 packages/bundler-webpack/src/config/config.ts 中当用户未配置targets时会自动注入该默认值并据此推导 browserslist、控制语法转译、polyfill 引入与 autoprefixer 行为见 config.md。因此如果你的项目只需要比 chrome 80 稍旧一点的兼容直接指定明确的targets即可// .umirc.ts export default { targets: { chrome: 67 }, };targets支持各浏览器内核及版本号例如{ ie: 11 }或{ chrome: 67, firefox: 68 }。它是 Umi 做语法转换与 polyfill 注入的总开关后续的legacy模式本质上也是在它之上叠加更强的降级策略。轻度兼容调整 targets 与压缩器产物等级如果你并不需要兼容到 IE只是希望提升对非现代浏览器的兼容性优先调整targets即可。但需要注意Umi 4 默认使用现代构建工具产物默认生成至 ES6。若你希望构建出 ES5 产物需要同步调整 JS/CSS 压缩器因为默认的压缩工具基于 esbuild/swc 的快速路径可能无法产出低版本浏览器可运行的语法。文档给出的配置为// .umirc.ts export default { jsMinifier: terser, cssMinifier: cssnano, };jsMinifier: terser保留并遵循ecma目标输出行为与旧版 bundle CLI 一致cssMinifier: cssnano支持低版本 target 的 CSS 压缩。关于这两个配置项的详细类型说明可参见 config.md 与 config.md。兼容旧时代浏览器IE 11legacy mode当确实需要兼容 IE 11 时单靠targets: { ie: 11 }并不够——还需要保证node_modules中大量仅发布 ES6 产物的依赖也被转译并选择支持 ES5 输出的构建链路。这正是 Umi 4 内置legacy配置的用途。框架自带的 legacy mode在 [.umirc.ts] 中开启// .umirc.ts export default { legacy: {}, };legacy的配置 schema 定义在 packages/preset-umi/src/features/legacy/legacy.ts共支持三个字段均为可选字段类型默认值说明buildOnlybooleantrue是否仅在构建production时生效nodeModulesTransformbooleantrue是否转译全部node_modules为 ES5checkOutputbooleanfalse构建结束后用es-check校验产物是否为 ES5 语法默认仅在构建时生效当api.env为 development 且buildOnly为true时legacy不会对开发链路做任何改动见 legacy.ts。开启后 Umi 会自动做四件事源码位于 legacy.ts强制srcTranspiler babel——注释中明确标注只有 babel 能可靠转译到 ES5swc 支持 ES5 但存在边界情况esbuild 不支持 ES5强制jsMinifier terser——保留ecma目标行为与旧版 bundle CLI 一致强制cssMinifier cssnano——支持低版本 target将targets合并进ie: 11——const ieTarget userConfig.targets?.ie || api.config.targets?.ie || 11;并把memo.targets扩展为{ ...userConfig.targets, ie: ieTarget }。同时开启legacy后不支持再手动配置srcTranspiler、jsMinifier、cssMinifier三者否则会直接logger.fatal并抛错见 legacy.ts。产物语法校验checkOutputlegacy并不能保证产物 100% 无边界情况。若想自动校验产物语法是否真的是 ES5可开启// .umirc.ts export default { legacy: { checkOutput: true, }, };当api.env Env.production且开启checkOutput时Umi 会按需安装es-check^7.1.0并在onBuildComplete阶段对输出目录下所有.js文件执行es-check es5检查见 legacy.ts。构建完成后若产物存在非 ES5 语法会在终端直接暴露问题适合接入 CI 作为回归防线。legacy mode 的更多自定义关掉全量 node_modules 转译legacy开启时默认会转译全部node_modules。在大型项目中这会把构建时间拉到难以接受的程度。若你清楚当前项目依赖的情况知道哪些包已不再提供 ES5 产物可以关闭node_modules的整体转换改为用extraBabelIncludes定点配置需要额外纳入转换范围的包// .umirc.ts export default { legacy: { nodeModulesTransform: false, }, extraBabelIncludes: [some-es6-pkg, /scope\//], };extraBabelIncludes类型为Arraystring | RegExp默认[]支持绝对路径、npm 包名以及正则如/scope\//命中所有 scope 包详见 config.md从源码看当nodeModulesTransform: true时webpack 的extra-src规则会.include.add(/node_modules/)将全部依赖纳入 Babel 转译同时会自动.exclude.add(/core-js/)避免重复转译 core-js polyfill与.add(/node_modules\/(css-loader)/)规避 mini-css-extract-plugin 相关问题并额外对 svgr 输出做 Babel 转译见 legacy.ts。提高兼容的鲁棒性前置全量 polyfilllegacy只解决语法转译不解决API 缺失。被淘汰浏览器往往同时缺少Promise、fetch、Array.prototype.includes等运行时 API因此还需要前置的、全量polyfill 来增强项目的鲁棒性// .umirc.ts export default { headScripts: [ http://polyfill.alicdn.com/v3/polyfill.min.js, // or https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js ], legacy: {}, };headScripts类型为string[] | Script[]会将字符串作为script src注入head详见 config.md。常见思路对比如下方案说明CDN 引入以 CDN 形式引入script 形式且前置的、目标浏览器环境缺少的 polyfill JS 文件如 es6-shim人工 core-js利用 core-js 系工具如 core-js-builder构建自己需要的 polyfill 产物再以前置 script形式引入项目动态 polyfill 服务使用根据当前浏览器请求 UA 动态下发所需 polyfill 的服务如 polyfill.ioalicdn / CloudFlare也可用 polyfill-service 自建同样的动态下发服务两点重要提示处于内外网隔离的开发环境时可将全部 polyfill JS 内容传入内网在内网 CDN 使用或放入public目录等方式使用script 前置引入的意义在于在项目 JS 资源运行前就准备好一个完整、被 polyfill 过的 API 环境。为什么 Umi 自身还内置了 core-js 体系值得一提的补充Umi 4 本身也内置了 polyfill 机制。在 packages/preset-umi/src/features/polyfill/polyfill.ts 中Umi 会基于api.config.polyfill?.imports默认import core-js;生成临时的core/polyfill.ts并通过 preset-env 的useBuiltIns: entry按targets展开后作为首个 polyfill 导入注入应用。也就是说targets会影响 Umi 内置 polyfill 的裁剪范围在 qiankun 场景下源码还专门排除了esnext.math.deg-per-rad等会重复覆盖的 polyfill见 polyfill.ts而本文推荐的前置scriptpolyfill 与内置 core-js 并不冲突前者在 bundle 执行前补齐环境后者随 bundle 按需注入两者配合可最大化鲁棒性。在开发环境验证推荐的验证方式是构建后在本地通过umi preview或serve、nginx 等启动服务验证产物的 IE 11 运行可行性。umi preview会在本地启动静态 Web 服务器预览dist产物支持--port指定端口详见 commands.md。若你一定要在开发环境验证按以下两步操作将legacy.buildOnly置为false由于 react fresh、hmr 等开发注入的 ES6 代码始终在第一位运行需要以 script 形式添加一个前置的 polyfill提前准备好环境// .umirc.ts const isProd process.env.NODE_ENV production; export default { legacy: { buildOnly: false, }, headScripts: isProd ? [] : [http://polyfill.alicdn.com/v3/polyfill.min.js], };注意IE 11 并不能完整支持开发时的热更新且缓存可能需要人为在控制台清除后才能看到最新页面请做好心理准备。legacy mode 的边界与注意点结合源码使用legacy时还应留意两个边界mfsu 会被自动关闭legacy在开发环境生效时buildOnly: false源码会强制memo.mfsu false并打印 warning——原因是 mfsu 使用了 top level await与低版本浏览器不兼容见 legacy.tsexternals 与 async externalsType 冲突低版本浏览器不支持 top level await若你使用了externals如{ lodash: [script http://path, _] }或通过chainWebpack设置了externalsType: script同时又存在同步 import源码会打印警告提示见 legacy.ts。配置速查与决策路径根据项目实际情况可按下表快速决策场景推荐配置仅需比 chrome 80 略旧的现代浏览器targets: { chrome: 67 }需 ES5 产物但不含 IEtargetsjsMinifier: tersercssMinifier: cssnano必须兼容 IE 11legacy: {}必要时叠加前置 polyfillheadScripts大型项目、依赖可控legacy: { nodeModulesTransform: false }extraBabelIncludes定点转译构建产物自动校验legacy: { checkOutput: true }依赖按需安装es-check开发环境联调 IElegacy: { buildOnly: false } 非生产环境前置 polyfill最后再次强调legacy模式会显著增加构建时间默认转译全部node_modules且不能 100% 保证产物在被淘汰浏览器内没有边界情况——它只负责语法降级鲁棒性需要前置 polyfill 来兜底。合理组合targets、legacy、extraBabelIncludes与headScripts即可在现代化构建与老旧浏览器兼容之间取得平衡。【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →