如何配置babel?

在对babel进行配置的时候,我们一般都是复制粘贴官网上例子或者使用现成的脚手架,但其实其中的每一项我们都不太了解,它是做什么的?实现了什么功能?因此,做一下具体详细的记录。
1.首先es6增加的内容分为语法和api

语法:比如箭头函数和解构

const fn = () => {}
const arr2 = [...arr1]

新的api:比如map和promise

const m = new Map()
const p = new Promise(() => {})

2.@babel/core
安装:npm install @babel/core --save-dev
@babel/core是babel的核心,它的作用是按照配置的文件进行转码。

3.@babel-cli
安装:npm install @babel/cli
@babel/cli的作用是让我们能够在命令行使用babel功能

4.plugins和presets
官网:babel是基于插件架构的,如果不引入插件,babel不会做任何事情,输入什么就输出什么。我们如果想转换箭头函数,直接引用箭头函数插件即可。

/* .babelrc */
{
  "plugins": ["@babel/plugin-transform-arrow-functions"]    
}

如果想引入转换解构的插件:

/* .babelrc */
{
  "plugins": [
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-destructuring"
  ]    
}

但是es6的新增语法那么多,这样引入的插件也太多了啊,幸亏babel提供了插件的集合presets,它相当于插件的集合,比如:preset-env(专门处理es6+规范语法的集合) preset-stage(处理尚在提案时期的语法集合) preset-react(处理react语法的集合)

5.preset-env

/* .babelrc */
{
  "presets": ["@babel/preset-env"]    
}

preset-env可以让你尽情使用es6的语法,它会帮你转换成浏览器能够识别的js语法,默认情况下,不用配置任何东西,它会转换所有的es6+的语法,我们可以给他加一个targets用来给他设定转换的浏览器版本。
/* .babelrc */

{
  "presets": [
    ["@babel/preset-env", {
      "targets": "ie >= 8"
    }]
  ]    
}

只有ie浏览器版本大于8的时候,才会转换es6+的语法,其他不予转换。

6.@babel/polyfill
当我们引入promise的时候,发现转换过后的文件并没有发生任何变化,这是因为es6的语法部分可以用@babel/preset-env进行转换,但是api部分,如map 和 promise 等要用到ployfill进行转换。

/* test.js */
import '@babel/polyfill'

const fn = () => {}
new Promise(() => {})


/* test-compiled.js */
import '@babel/polyfill';

var fn = function fn() {};
new Promise(function () {});

只需要在index.js文件中直接用import引入即可。这样,使用promise的文件就可以运行在ie8环境中了,但是我们发现,引入这个包之后,文件的体积变大了好几倍。这是因为,polyfill在处理浏览器不支持的属性的时候,它会自己实现一遍所有的es6+ API,为了让它只引入我们使用的api,preset-env帮助我们实现了这个功能:

/* .babelrc */
{
  "presets": [
    ["@babel/preset-env", {
      "useBuiltIns": "entry",
      "core-js":3,//需要声明core-js的版本,否则webapck会报错
      "targets": "ie >= 8"
    }]
  ]    
}

useBuiltIns属性有两个值,entry 和 usage和false。entry的作用是在程序的入口处,将ie8所有不支持的api的polyfill都引入进来。能够覆盖到‘hello‘.includes(‘h‘)这种句法,足够安全且代码体积不是特别大!(推荐使用)

/* test.js */
import '@babel/polyfill'

const fn = () => {}
new Promise(() => {})


/* test-compiled.js */
import "core-js/modules/es6.array.copy-within";
import "core-js/modules/es6.array.every";
import "core-js/modules/es6.array.fill";
...   //省略若干引入
import "core-js/modules/web.immediate";
import "core-js/modules/web.dom.iterable";
import "regenerator-runtime/runtime";

var fn = function fn() {};
new Promise(function () {});

usage更加智能一些,它会扫描你的代码,你的代码用到了哪个api,就会引入相应的polyfill。但是,我们在转译的时候都会除去node-modules,如果有第三方包没有做好es6转译的情况下,就会出问题。
但是它检测不到‘hello‘.includes(‘h‘)这种句法,可以在书写规范并且信任第三方包的情况下使用。

/* .babelrc */
{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "useBuiltIns": "usage",
      "core-js":2,//也因 core-js@3 的原因,需要配置 corejs 参数去指定使用的corejs 版本,否则 webpack 运行时会报 warning。
      "targets": "ie >= 8"
    }]
  ]    
}
/* test.js */
const fn = () => {}
new Promise(() => {})

/* test-compiled.js */
import "core-js/modules/es6.promise";
import "core-js/modules/es6.object.to-string";

var fn = function fn() {};
new Promise(function () {});

useBuiltIns为false时,会默认把所有的包引入,体积较大。不推荐使用。

注:为什么无法识别includes等api?
usage时通过识别api来引入垫片,比如promise、map等,但是includes是在数组原型上的方法(Array.prototype
.includes),但是无法确认引用includes方法的是什么类型,所以无法引入数组原型。

如果你在写一个APP或者页面以上配置已经足够了,但是如果你想写一个类库或者框架,还有一个需要注意的地方。
以上使用polyfill的方法会污染全局环境,可能会覆盖掉一些全局的api。我们需要换一种方法来引入polyfill:
安装:yarn add @babel/plugin-transform-runtime -D
yarn add @babel/runtime-corejs2

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
      }
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 2 // 推荐
      }
    ]
  ]
}
/* test.js */
class Test {}
new Promise(() => {})


/* test-compiled.js */
import _Promise from "@babel/runtime-corejs2/core-js/promise";
import _classCallCheck from "@babel/runtime-corejs2/helpers/classCallCheck";

var Test = function Test() {
  _classCallCheck(this, Test);
};

new _Promise(function () {});
接下来,我们记录一下这两种方法的区别,首先,这两种方法都可以实现es6 API 的转换:
1.@babel/preset-env + @babel/polyfill可以转译语法、新 API,但存在污染全局问题,用在业务场景
2.@babel/preset-env + @babel/plugin-transform-runtime + @babel/runtime-corejs2,可按需导入,转译语法、新 API,且避免全局污染(会为引入的模块创建一个沙箱环境),但是检测不到‘hello‘.includes(‘h‘)这种句法;

**core-js3改进了core-js2不能识别原型方法的这个特点,就includes方法来说,因为只有数组和字符串可以用这个方法,所以会一次性将数组和字符串的原型都引入。**建议升级使用core-js3

借鉴:
https://segmentfault.com/a/1190000020237817
https://zhuanlan.zhihu.com/p/139359864
https://segmentfault.com/a/1190000018721165

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值