关于Babel7的介绍

1、 Babel的介绍

Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转化为向后兼容的javaScript语法,以便能运行在当前和旧版本的浏览器或其余环境中。
babel7的重要组成部分java

  • @babel/cli
  • @babel/core
  • @babel/preset-env
  • @babel/polyfill
  • @babel/runtime
  • @babel/plugin-transform-runtime
  • @babel/plugin-transform-xxx

以上这些就是咱们之后经常会使用的babel的各个重要部分了
这里要注意一下这个@这个符号,这个是只有babel7才特有的,这是 babel7 的一大调整,原来的 babel-xx 包统一迁移到babel域下,域由 @符号来标识。
下面咱们来随便建一个项目,例如index.js里面写一行代码:node

let fn = () => console.log('Hello World')

而后咱们能够想将其搁置一边,一步步学习!npm

2、@babel/cli和@babel/core

@babel/cli是babel提供的内建的命令行工具,主要是提供babel这个命令来对js文件进行编译,适合安装在项目里。可是仅仅npm install @babel/cli再执行babel index.js 并不会执行成功。由于Babel 的核心功能包含在 @babel/core 模块中。因此须要安装 @babel/core
即执行:segmentfault

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

这时候咱们用babel来执行下咱们上面的index.js数组

babel index.js

发现生成的代码并无任何改变!看来还须要其余的配合,因而咱们继续配置其余的选项!浏览器

3、@babel/preset-env

真正使Babel作实际工做的实际上是插件。以上面的代码为例,咱们想转化下箭头函数,咱们须要插件 @babel/plugin-transform-arrow-functions。
因而输入命令行:babel

npm install --save-dev @babel/plugin-transform-arrow-functions

建立一个名为 .babelrc的配置文件,@babel/cli在调用之时都会去调用.babelrc文件
文件内容以下函数

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

再编译,会发现箭头函数已经变成非箭头函数了
可是咱们还须要其余ES6的新特性也进行转化,好比要将const或者let转化成var,须要插件 @babel/plugin-transform-block-scoping,将class关键字转化成传统基于原型的,须要插件@babel/plugin-transform-classes。因此咱们在使用ES6时须要配置大量的插件,这很显然不合理,因而babel提出了预设的概念----preset,其实就是预先为咱们作好了一系列的插件包。工具

咱们在.babelrc的配置文件里做以下配置:学习

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "4"
        }
      }
    ]
  ]
}

注:targets是指定目标环境,该参数配置除了能够设置node环境外,还能够设置针对各个浏览器环境的配置。
按照上述配置,运行后发现就目前的代码是没有问题了!

4、@babel/polyfill

如今咱们把index.js的代码改成以下:

const m = [1,2,3].findIndex(x => x == 1)

发现编译后的代码以下:

"use strict";

var m = [1, 2, 3].findIndex(function (x) {
  return x == 1;
});

此代码若是运行在低版本浏览器,必定会报错,由于低版本浏览器中数组实例上没有 includes 方法。这种状况的发生是由于语法转换只是将高版本的语法转换成低版本的,可是新的内置函数、实例方法没法转换。
这时 polyfill 登场了。

顾名思义,polyfill的中文意思是垫片,所谓垫片就是垫平不一样浏览器或者不一样环境下的差别,让新的内置函数、实例方法等在低版本浏览器中也可使用。

首先安装 @babel/polyfill 依赖:

npm install --save @babel/polyfill

咱们须要在咱们的代码里对 polyfill引入:

import '@babel/polyfill';
const m = [1,2,3].findIndex(x => x == 1)

这样代码能够在低版本运行了,可是咱们未必须要加载全部的 polyfill,这会致使咱们最终构建出的包的体积很大。为了解决这一问题,@babel/preset-env 提供了一个 useBuiltIns 参数,设置值为 usage 时,就只会包含代码须要的 polyfill 。
配置此参数的值为 usage ,必需要同时设置 corejs (若是不设置,会给出警告,默认使用的是"corejs": 2), 为了可使用更多的新特性,建议你们使用 core-js@3。

因而咱们在.babelrc的配置文件里做以下配置:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "4"
        },
         "useBuiltIns": "usage",
         "corejs": 3
      }
    ]
  ]
}

这样编译后的代码为:

import "core-js/modules/es.array.find-index";
var m = [1, 2, 3].findIndex(function (x) {
  return x == 1;
});

这样咱们须要findIndex 函数就只须要打包polyfill里的findIndex函数

5、@babel/plugin-transform-runtime

如今咱们将index.js的代码修改成:

class A {
    constructor (name) {
        this.name = name
    }
}
const a = new A()

被编译后的代码以下:

import "core-js/modules/es.function.name";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var A = function A(name) {
  _classCallCheck(this, A);

  this.name = name;
};

var a = new A();

如今试想若是多个js文件都有class,那么是否是每一个被编译后的文件都会有_classCallCheck函数。为了解决这个问题,babel拥有了@babel/plugin-transform-runtime插件。使用 @babel/plugin-transform-runtime 插件,全部帮助程序都将引用模块 @babel/runtime,这样就能够避免编译后的代码中出现重复的帮助程序,有效减小包体积。

@babel/plugin-transform-runtime须要和@babel/runtime配合使用。

首先安装依赖,@babel/plugin-transform-runtime一般仅在开发时使用,可是运行时最终代码须要依赖@babel/runtime,因此@babel/runtime必需要做为生产依赖被安装,以下 :

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

修改 .babelrc 的配置,以下:

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "corejs": 3
            }
        ]
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime"
        ]
    ]
}

编译后的代码为:

"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

require("core-js/modules/es.function.name");

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var A = function A(name) {
  (0, _classCallCheck2["default"])(this, A);
  this.name = name;
};

var a = new A();

这时发现_classCallCheck2函数是经过引入的方式,而不是直接将函数插入到代码中。

如今咱们说回findIndex函数,编译后会require("core-js/modules/es.array.find-index"),这种方式会修改Array.prototype,而后全局污染。为了防止这一问题,该插件还有一个做用,能够避免全局污染。固然咱们须要给 @babel/plugin-transform-runtime 增长配置信息。
首先新增依赖 @babel/runtime-corejs3:

npm install @babel/runtime-corejs3 --save

修改配置文件

{
    "presets": [
        [
            "@babel/preset-env"
        ]
    ],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",{
                "corejs": 3
            }
        ]
    ]
}

编译后生成的代码为

"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");

var _findIndex = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/find-index"));

var _context;

var m = (0, _findIndex["default"])(_context = [1, 2, 3]).call(_context, function (x) {
  return x == 1;
});

如上面所示,这种就不会直接修改Array.prototype。避免全局污染。

结语

本人常常看到关于Babel配置的文章,可是没有特别清晰有体系的讲解,直到我看到了《不容错过的Babel7知识》。本文基本是按照文章做者的思路,本身捋了一遍。若是你们看到这篇文章,而且想有更深的理解,还请参考原做者的文章!
参考连接 不容错过的 Babel7知识

相关文章
相关标签/搜索