babel

114 阅读5分钟

操作原理

image.png

简单使用(cli)

npm i @babel/core @babel/cli --save-dev

// index.js

const a = "1";

const fn = (params) => {
  console.log(params);
};

fn(a);

npx babel index.js --out-file result.js

// result.js

const a = "1";

const fn = params => {
  console.log(params);
};

fn(a);

可以看见,并没有任何改变,这是因为@babel/core仅仅只是个核心库,babel属于微内核架构,能做的事情非常少,需要转换还需要借助插件来实现.

  • 转换const需要转换作用域的插件@babel/plugin-transform-block-scoping
  • 转换箭头函数需要插件@babel/plugin-transform-arrow-functions

npm i @babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions --save-dev

npx babel index.js --out-file result.js --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping

// 转化后
"use strict";

var a = "1";

var fn = function fn(params) {
  console.log(params);
};

fn(a);

可以看到已经转化好了,每一种转化都需要对应的插件,所以,babel提供了一种预设插件@babel/preset-env(插件集合),方便统一处理

npm install --save-dev @babel/preset-env

npx babel index.js --out-file result.js --presets=@babel/preset-env

// 转化后
"use strict";

var a = "1";

var fn = function fn(params) {
  console.log(params);
};

fn(a);

在webpack使用

基本配置

npm i @babel/core babel-loader --save-dev

  • 采用独立插件方式 npm i @babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions --save-dev

image.png

  • 用预设插件的方式 npm i @babel/preset-env --save-dev

image.png

  • 抽离配置到babel.config.js 注意:babel.config.js与.babelrc的区别在于babel.config.js属于全局配置,而.babelrc属于局部配置,如果是单一工程,那么二者的效果相同,如果在局部找到.babelrc,那么就会直接应用
.
├── .babelrc
├── babel.config.js
├── package.json
└── src
    ├── index.js
    └── subdir
        ├── .babelrc
        └── utils.js

配置详情

module.exports = {
  presets: [["@babel/preset-env"]],
};

image.png

适配浏览器

  • 在package.json中配置

image.png

  • 在babel.config.js配置文件中配置

image.png

  • 使用.browserslistrc文件配置

image.png

在.browserslistrc中配置是最好的选择,因为,有比较多的配置项目,都是根据这个文件来去兼容浏览器的,可以再项目中统一用一份文件管理

浏览器适配实践

image.png

// 转化前
const a = "1";

const fn = (params) => {
  console.log(params);
};

fn(a);

//转化后
var a = "1";

var fn = function fn(params) {
  console.log(params);
};

fn(a);

可以看见做出兼容了

image.png

// 转化前
const a = "1";

const fn = (params) => {
  console.log(params);
};

fn(a);

//转化后
const a = "1";

const fn = params => {
  console.log(params);
};

fn(a);

可以看出,什么都没改,因为chrome 99已经不需要适配这些语法了

polyfill

  • babel只转换句法,并不会处理新的内置函数(Promise或者Array.prototype.slice之类的),babel为了保证正确的语义,只能转换语法而不是去增加或修改原有的属性和方法,而polyfill就是帮助在全局或者局部添加这些函数

旧的使用方法

npm i @babel/polyfill --save

  • 直接从entry引入即可,不需要在文件中引入了(useBuiltIns为false或者未指定,也是使用这个方法),但是仍然可以将polyfill在文件中引入,但不建议这么做,整个polyfill都引入了

image.png

  • 当useBuiltIns为entry时,在文件中引入才可以使用,并且,将polyfill在入口文件顶部引入,entry不需要配置了,根据配置的浏览器列表进行导入

image.png

image.png

  • 当useBuiltIns为usage时,其他都不需要配置和引入了,babel会帮助引入我们在代码中有写到的函数,没写到的就不会引入

image.png

新的使用方法

  • 官方提示: @babel/polyfill从Babel 7.4.0 开始,这个包已经被弃用,取而代之的是直接包含core-js/stable(以填充 ECMAScript 特性)和regenerator-runtime/runtime(需要使用转译的生成器函数)

npm i core-js regenerator-runtime --save

  • 直接从entry引入即可,不需要在文件中引入了(useBuiltIns为false或者未指定,也是使用这个方法),但是仍然可以将polyfill在文件中引入,但不建议这么做,整个polyfill都引入了

image.png

  • 当useBuiltIns为entry时,在文件中引入才可以使用,并且,将core-js/stable与regenerator-runtime/runtime在入口点顶部引入,根据配置的浏览器列表进行导入

image.png

image.png

  • 当useBuiltIns为usage时,其他都不需要配置和引入了,babel会帮助引入我们在代码中有写到的函数,没写到的就不会引入

image.png

注意事项

image.png

需要把node_module排除

工具库的做法(runtime)

在使用@babel/preset-env提供的语法转换和api添加的功能时,会造成文件的体积增加以及api的全局污染。为了解决这类问题,引入了runtime的概念,runtime核心思想是以引入替换的方式来解决兼容性问题。(单独使用需要手动引入)

@babel/plugin-transform-runtime为了方便@babel/runtime的使用。通过ast的分析,自动识别并替换代码中的新api,解决手动require的烦恼。

npm i @babel/plugin-transform-runtime --save-dev

npm install --save @babel/runtime-corejs3

image.png

image.png

总结

  • polyfill方案很明显的缺点就是会造成全局污染,而且会注入冗余的工具代码;优点是可以根据浏览器对新特性的支持度来选择性的进行兼容性处理

  • runtime方案虽然解决了polyfill方案的那些缺点,但是不能根据浏览器对新特性的支持度来选择性的进行兼容性处理,也就是说只要在代码中识别到的api,就会自动替换,这样一来就会造成一些不必要的转换,从而增加代码体积。

所以,polyfill方案比较适合单独运行的业务项目,如果你是想开发一些供别人使用的第三方工具库,则建议你使用runtime方案来处理兼容性方案,以免影响使用者的运行环境。