浏览器兼容性
browserslist
package.json
文件里的 browserslist
字段 (或一个单独的 .browserslistrc
文件),指定了项目的目标浏览器的范围。这个值会被 @babel/preset-env 和 Autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀。
现状
我们想要用 ES6 语法来写 JavaScript。然而由于我们需要兼容老版本的浏览器,那些浏览器不支持 ES6,我们需要解决这个问题。
有一个标准的做法是:写 ES6 代码 → 将所有代码编译成 ES5 的(比如通过 Babel)→ 再将编译后的代码加载到浏览器执行。
这可能已经不再是最有效率的方式了。因为用这种方式,我们强制最新的浏览器运行旧代码,实际上它们完全可以运行最新的代码。它们支持 ES6,我们难道不能直接给它们 ES6 代码吗?
改进方式
有一个 polyfill 项目叫做 Polyfill.io API,它可以通过 polyfill 方式在客户端执行 ES6 代码。
它也实现了一些 HTML 特性的 polyfill,比如 <picture> 元素。
下面是他们网站的描述:
Polyfill.io 读取每个请求的 User-Agent(UA) 头,并生成适合于该浏览器的 polyfill ,基于你的应用所使用的特性发回必要的代码。[...]
要添加 Polyfill.io 到你的项目里非常简单。将托管在 CDN 的脚本添加到你的页面上:
<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
运行脚本将返回 UA 和你想要的特性。
UA detected: chrome/56.0.0
Features requested: default
@babel/polyfill模块
@babel/polyfill
模块用于模拟完整的 ES2015+ 环境。
这意味着你可以使用诸如 Promise
和 WeakMap
之类的新的内置组件、 Array.from
或 Object.assign
之类的静态方法、 Array.prototype.includes
之类的实例方法以及生成器函数(generator functions)
useBuiltIns参数
npm install --save @babel/polyfill
注意,使用 --save 参数而不是 --save-dev,因为这是一个需要在你的源码之前运行的 polyfill。
我们使用 env preset 提供的 "useBuiltIns" 参数,当此参数设置为 "usage" 时,就只包含你所需要的 polyfill。
const presets = [
[
"@babel/env",
{
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1",
},
useBuiltIns: "usage",
},
],
];
module.exports = { presets };
Babel 将检查你的所有代码,以便查找目标环境中缺失的功能,然后只把必须的 polyfill 包含进来。示例代码如下:
Promise.resolve().finally();
将被转换为(由于 Edge 17 没有 Promise.prototype.finally):
require("core-js/modules/es.promise.finally");
Promise.resolve().finally();
如果我们不使用 env preset 的 "useBuiltIns" 参数(即设置为 "usage"),那么我们必须在所有代码之前通过 require 加载一次完整的 polyfill。
网友评论