客户端兼容性
Polyfill 模式
编译时 Polyfill
Modern.js 在编译时默认通过 core-js 引入对应的 Polyfill 代码。
默认情况下会根据项目 Browserslist 的设置情况引入所需的 Polyfill 代码, 这样基本不用再担心项目源码和第三方依赖的 Polyfill 问题了,但是因为包含了一些没有用到的 Polyfill 代码,所以最终的包大小可能会有所增加。
注
对于明确第三方依赖不需要 Polyfill 的场景,可以设置 output.polyfill
为 usage
, 这样 Babel 编译时只会根据代码中使用到的语法引入 Polyfill 代码。
运行时按需 Polyfill
Modern.js 中还提供了基于浏览器 UA 信息的运行时按需 Polyfill 方案,相比于 Babel 优势如下:
- 不会插入到代码中,只根据访问页面的设备,按需下发 Polyfill 代码 ,减少整体代码体积。
- 相同浏览器会公用一份 Polyfill 代码。因此,随着项目越来越多,基于 UA 的 Polyfill 代码下发速度会越来越快,综合速度超过常规方案。
可以通过微生成器开启该功能:
? 请选择你想要的操作:启用可选功能
? 启用可选功能:启用「基于 UA 的 Polyfill」功能
安装依赖后,配置 output.polyfill
为 ua
并且执行 pnpm run build && pnpm run start
启动服务器后,访问页面可以看到 HTML 产物中包含如下脚本:
<script src="/__polyfill__" crossorigin></script>
在 Chrome 51 下访问页面可以看到 http://localhost:8080/__polyfill__
返回内容如下:
差异化分发
Modern.js 提供了运行时基于浏览器 User Agent 的差异化分发方案, 设置 output.enableModernMode
后, 生产环境会自动构建出针对现代浏览器语法未降级的 JS 产物和针对旧版本浏览器带有 Polyfill 的 JS 产物:
├── 370.95db0e84-es6.js
├── 370.95db0e84-es6.js.map
├── 370.ace5d8a0.js
├── 370.ace5d8a0.js.map
├── main.64eb3bc7-es6.js
├── main.64eb3bc7-es6.js.map
├── main.c8aab430.js
├── main.c8aab430.js.map
├── runtime-main.9ad9a46b-es6.js
├── runtime-main.9ad9a46b-es6.js.map
├── runtime-main.dccca6e0.js
└── runtime-main.dccca6e0.js.map
同时 HTML 也会构建出对应的 ES6 版本:
<script defer="defer" src="/static/js/370.95db0e84-es6.js"></script>
<script defer="defer" src="/static/js/370.ace5d8a0.js"></script>
通过 pnpm run build && pnpm run start
启动服务器, 访问页面时,会根据浏览器信息决定返回 index-es6.html
还是 index.html
。
注
内部目前使用 @babel/compat-data 来判断具体浏览器是否支持 es6 语法。
Browserslist 配置
Modern.js 支持在项目根目录 package.json
文件中的 browserslist
字段(或单独的 .browserslistrc
文件)指定项目覆盖的目标浏览器范围。该值会被 @babel/preset-env
和 autoprefixer
用来确定需要转换的 JavaScript 语法特性和需要添加的 CSS 浏览器前缀。
Modern.js 中默认值如下:
['> 0.01%', 'not dead', 'not op_mini all']
可以在这里了解如何自定义浏览器范围。