preset-env 按需 polyfill 是怎么实现的?

开发时我们会使用一些新的 api,但用户的浏览器各种版本都有,可能并不支持这些 api,但我们也不能因此就不用了,这时候就可以通过 polyfill 来解决。

polyfill 是垫片的意思,也就是在运行业务代码之前,在全局注入一些 api 的实现,这样之后运行的业务代码用到该 api 时就有了,也就不会有兼容问题。

但用户的浏览器可能是各种各样的,有可能我们 polyfill 的 api 本来就支持,这时候加载 polyfill 就很没必要,而且也浪费了性能。

有没有什么办法能够既解决不支持这个 api 的运行环境的兼容问题,又不会在支持这个 api 的环境引入不必要的代码呢?

答案就是 preset-env,它实现了按需引入 polyfill。

这里的 preset-env 指的是 babel 的 @babel/preset-env 和 postcss 的 postcss-preset-env,它们一个是按需做语法转换、按需引入 JS 的 polyfill,一个是按需做添加 prefix 等 css 兼容处理。

虽然分别是针对 JS 和 CSS 的,但他们两个的原理差不多,我们分别来看一下。

@babel/preset-env

按需指的是按照目标运行环境是否支持,那怎么指定目标运行环境呢?

@babel/preset-env 支持通过 targets 来指定目标环境:

{ 
   "presets": [
        ["@babel/preset-env", { 
            "targets": "> 0.25%, not dead" 
        }]
   ]
}

这里的 targets 是 browserslist 的查询字符串,它可以解析查询字符串返回对应的浏览器版本:

243ab6c3f932e381635ddfd0f6a97521.png

有了这些目标浏览器的版本,还需要知道各种特性是在什么版本支持的:

babel 维护了一个数据库,在 @babel/compat-data 这个包里:

c1504a47df4a818971755a8aecdc0438.png

这样就能根据目标浏览器的版本,过滤出哪些特性是支持的,哪些是不支持的。然后只对不支持的特性做语法转换和 polyfill 即可。

5174cfcb1ac950993ab88e52ac2f88b4.png

这就是按需 polyfill 的实现原理。

css 的按需做兼容处理也差不多:

postcss-preset-env

postcss 是通过 postcss-preset-env 来做按需处理的,同样支持配置目标环境,也就是 browsers:

postcssPresetEnv({ browsers: 'last 2 versions' })

同样也是用 browserslist 来把查询字符串转换成对应的浏览器版本。

然后再根据哪些 css 特性是从什么浏览器版本开始支持的来过滤出不支持的 css 特性。

这里用的是 caniuse 的数据,在 cssdb 这个包里:

eec86d35b05dc312de63771913ad3eae.png

知道了目标浏览器的版本,知道了这些特性在什么浏览器版本支持,那自然就可以过滤出不支持的 css 特性。然后引入不同的 postcss 插件来处理这些特性的 prefix 等就可以了。

这就是 css 的按需 prefix 等处理的原理。

可以看到 babel 和 potcss 都依赖了 browerslist 这个包来查询目标浏览器版本,那自然可以统一成一个,也就是在根目录下的 .browserslistrc 的配置文件,通过指定同一个的环境来按需做 JS 和 CSS 的兼容处理。

总结

用户的浏览器可能是各种各样的,我们开发时用的 JS 和 CSS 的特性在用户的浏览器不一定支持,为了保证功能正常就要做兼容处理。

JS 的兼容处理就是 polyfill,CSS 的兼容处理就是添加 prefix 等。

babel 是通过 @babel/preset-env 来做按需 polyfill 和转换的,原理是通过 browserslist 来查询出目标浏览器版本,然后根据 @babel/compat-data 的数据库来过滤出这些浏览器版本里哪些特性不支持,之后引入对应的插件处理。

postcss 是通过 postcss-preset-env 来做按需 prefix 等的,原理也是通过 browserslist 来查询出目标浏览器版本,然后根据 cssdb 的数据库(来自 caniuse)来过滤出不支持的 CSS 特性,然后对这些 CSS 做处理即可。

就像 preset-env 的名字一样,它们的意义就是根据目标环境来按需做处理的,也被叫做智能处理,比之前的 es5、es6 这种粗暴的指定目标,确实聪明了很多。

- END -

acfd49687b2346361eef0825a4161815.png

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

ea2b4196dd7cc13093de70f4935b6e59.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值