Preset-Env 按需 Polyfill 是怎么实现的?

系统 浏览器
开发时我们会使用一些新的 api,但用户的浏览器各种版本都有,可能并不支持这些 api,但我们也不能因此就不用了,这时候就可以通过 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 的查询字符串,它可以解析查询字符串返回对应的浏览器版本:

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

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

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

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

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

postcss-preset-env

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

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

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

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

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

知道了目标浏览器的版本,知道了这些特性在什么浏览器版本支持,那自然就可以过滤出不支持的 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 这种粗暴的指定目标,确实聪明了很多。


责任编辑:武晓燕 来源: 神光的编程秘籍
相关推荐

2017-08-23 19:00:29

SDN网络技术虚拟网络

2009-02-17 18:52:06

网络虚拟化路由系统数据中心

2021-08-30 22:38:47

VscodeMarkdown预览

2021-09-07 09:18:18

Kubernetes负载均衡服务发现

2024-01-15 08:08:27

2014-07-31 10:10:53

全息影像手机数码

2021-05-11 09:13:08

服务器存储数据中心

2023-11-23 19:30:35

Python编程语言

2022-08-30 19:11:12

Docker虚拟化技术

2020-09-11 06:44:29

Python增强算术

2022-05-10 08:59:25

IP网络

2021-11-17 09:00:00

Kubernetes集群容器

2009-02-05 09:38:36

企业无线网家庭无线

2023-07-12 20:12:57

前端Monorepo代码

2023-04-28 07:44:44

MyBatis查询SQL

2023-03-29 08:09:51

Spring@Service@Component

2016-11-17 22:18:31

id串行化服务器

2023-03-26 00:04:14

2022-01-14 17:01:44

GoError结构

2022-01-07 07:59:14

Go语言Go Error
点赞
收藏

51CTO技术栈公众号