兼容计划的背景
面临的问题
- 尽管JS很多语法曾经到了正式公布的阶段,然而因为浏览器的反对水平不同导致咱们无奈释怀的应用。
- 有些曾经到了 stage3 的语法咱们也想尝试应用,如何失常运行?
现实的场景
咱们能够释怀的编写js代码,不必思考其余问题。
如何实现
在编译的时候通过一种办法让浏览器不反对的语法转换成浏览器反对的语法,这样代码就能够失常运行。
通过语法转换实现代码兼容
前端我的项目通常采纳 babel 来转换 js 代码,写这篇文章的时候最新的版本是 babel v7
, 上面的计划也会只介绍在这个版本下的。
明确指标
在实现计划之前咱们须要想分明几个问题:
- 须要兼容哪些语法: 依据 TC39,你用到了
stage-x
(x: 1-4) 的语法 - 不同浏览器对语法反对水平不同, 你要解决哪些浏览器的兼容
- 代码兼容的解决形式是按需引入还是全副引入(各有优劣,接下来会介绍)
思考 3 min ...
计划实现
简略介绍 babel 相干常识
polyfill 计划
计划@babel/preset-env + corejs@3
特点
- 通过
useBuiltIns
配置,能够采纳按需加载和全副加载的形式实现兼容 - 会净化全局:在全局和实例上增加api
- 反对指标浏览器设置: 通过 targets 或 browserslist, 可是实现特定浏览器下的兼容,缩小代码体积
介绍
core-js:Javascript 规范语法实现库
@babel/preset-env:
- 一系列语法转换 plugin 的汇合,它反对的 plugin 能够参考这里。通过这些plugin 能够实现语法兼容。
- 能够通过 browserslist 实现针对特定浏览器下的 api 兼容: 简略来说就是 browserslist 会依据 caniuse 上的数据和指标浏览器比照得出须要兼容哪些api。具体的能够深刻了解 browserslist
注意事项
- @babel/preset-env 兼容到 stage4也就是正式版。如果要应用 stage3这种语法,须要在 bablerc plugins外面再引入对应 plugin
- 你须要配置 targets 或 browserslist 能力实现特定浏览器语法兼容
形式一: 全副引入
.babelrc 文件内容:
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "entry", "targets":"> 1%, not dead", // 依据状况本人设置 "corejs": { "version": 3, "proposals": true } } ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": false } ] ]}
入口文件 index.js:
import 'core-js/stable';import 'regenerator-runtime/runtime';// 入口文件代码
形式二: 按需引入
.babelrc 文件内容:
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "targets":"> 1%, not dead", // 依据状况本人设置 "corejs": { "version": 3, "proposals": true } } ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": false } ] ]}
runtime 计划
计划@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime
特点
- 不会净化全局的:@babel/plugin-transform-runtime 插件通过模仿 api 实现兼容,不会净化全局的,所以更适宜 Library 作者应用
- 仅反对按需引入
- 应用到的api都会被替换, 不反对 targets 和 browserslist
介绍
- 依然须要
@babel/preset-env
对语法进行转换 - @babel/runtime-corejs3: 主用来模仿实现 api 性能的库
- @babel/plugin-transform-runtime:实现按需援用
@babel/runtime-corejs3
外面的 module
具体实现
.babelrc 文件内容:
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": false, "targets":"> 1%, not dead", // 依据状况本人设置 } ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": { "version": 3, "proposals": true } } ] ]}
总结
目前,babel解决兼容性问题有两种计划:
@babel/preset-env + corejs@3
实现语法转换、在全局和实例上增加api,反对全量加载和按需加载,咱们简称polyfill计划;@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime
实现语法转换、模仿替换api,只反对按需加载,咱们简称runtime计划。
两种计划都依赖外围包corejs@3,只不过依赖的模块不同,导致实现形式不同。两种计划各有优缺点:
- polyfill计划很显著的毛病就是会造成全局净化,而且会注入冗余的工具代码;长处是能够依据浏览器对新个性的反对度来选择性的进行兼容性解决;
- runtime计划尽管解决了polyfill计划的那些毛病,然而不能依据浏览器对新个性的反对度来选择性的进行兼容性解决,也就是说只有在代码中辨认到的api,并且该api也存在core-js-pure包中,就会主动替换,这样一来就会造成一些不必要的转换,从而减少代码体积。
所以,polyfill计划比拟适宜独自运行的业务我的项目,如果你是想开发一些供他人应用的第三方工具库,则倡议你应用runtime计划来解决兼容性计划,免得影响使用者的运行环境。
稍等,思考一种更好的计划: runtime 计划也反对 api targets 不就完满了吗... 还真有一个正在试验阶段的:babel-polyfills
QA
babelrc 文件 tagets、ignoreBrowserConfig 和 browserslist 的优先级和默认配置
- 配置:targets > browserslist
- 设置了
ignoreBrowserConfig:true
将默认不再读取browserslist
配置 - 两个都不存在时, 参考 No targets【大略意思是全副的ES2015之后的语法都会转换成 ES5】
@babel/polyfill 与 @babel/preset-env 的关系
- @babel/polyfill 是 babel@6 and core-js@2时代的产物, 相似 @babel/preset-env 的
"useBuiltIns":"entry"
,然而不反对 browserslist,目前曾经被弃用。 - @babel/preset-env 反对 browserslist,还有很多新个性,兼容必备
babel-plugin-transform-runtime 的作用
次要有两个作用:
- 复用通过 Babel 注入的 helper 的代码,缩小代码冗余
- 通过模仿 api 的形式实现代码兼容【runtime计划】
两种计划的具体配置
如上文,也能够看这里:https://developer.aliyun.com/...
runtime 计划能够应用 browserslist 配置吗?
- runtime计划的残缺办法是:
@babel/preset-env + @babel/runtime-corejs3 + @babel/plugin-transform-runtime
。 @babel/plugin-transform-runtime
是解决 api 局部,语法转换依然须要@babel/preset-env
, 所以在runtime计划下, target 对 语法转换仍是起作用的,然而对API局部是有效的
参考文章
- 99% 开发者没弄明确的 babel 常识
- 你所须要晓得的babel兼容性实现计划
- Browserslist 为你中意的浏览器写代码