關於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知識

相關文章
相關標籤/搜索