babel入門

Babel

Babel 是一個 JavaScript 編譯器,它能夠將ES6+語法編譯為瀏覽器支撐的ES5語法。要學好babel必須先明白相干的觀點,然則你剛起步就去扣這些細節的話,極能夠因為babel一些龐雜而隱約的觀點襲擊你的信息。所以我們先從最簡樸的最先,然後深切。

最簡樸的例子

接下來我們嘗試根據官方文檔做一個最簡樸的例子

裝置babel-cli

npm install --save-dev babel-cli

增添babel編譯敕令

"build": "babel src -d lib"

增添.babelrc設置文件

{
  "presets": [],
  "plugins": []
}

增添JS文件

// /src/main.js
const fetch = args => args;
console.log(Promise);

實行 npm run build,我們發明編譯后的文件沒有發生任何的轉變,就是簡樸的原樣輸出

// /lib/main.js
const fetch = args => args;
console.log(Promise);

為何呢?這是因為在.babelrc文件沒有做任何的設置。我們一共運用了三個新特徵,離別是常量申明const ,箭頭函數=>,新全局變量Promise。接下來我門嘗試將他們編譯為ES5代碼。

《babel入門》

如上圖所示,藉助plugin能夠完成我們的目的。接下來我們離別完成它:

  • const

原文鏈接 文檔中申明:

babel-plugin-check-es2015-constants 這個插件僅僅是考證const變量的劃定規矩,比方不能反覆申明,不可變等特徵。

把它編譯為ES5代碼須要藉助babel-plugin-transform-es2015-block-scoping

我們設置須要編譯的代碼為:

const fetch = args => args;
fetch = 55; // 有意寫錯
console.log(Promise);

裝置上面所需的兩個plugin並改寫.babelrc設置:

{
  "presets": [],
  "plugins": [
    "check-es2015-constants",
    "transform-es2015-block-scoping"
  ]
}

編譯歷程報錯考證check-es2015-constants見效
《babel入門》

我們修正須要編譯的代碼為:

const fetch = args => args;
console.log(Promise);

再次編譯勝利

var fetch = args => args;
console.log(Promise);

到這裏我們已勝利的運用插件對const的語法和轉譯(Syntaxtransform)ES5化。是不是是很高興呢? 接下來我們處置懲罰箭頭函數=>

  • arrow functions

一樣裝置對應的plugin :

npm install --save-dev babel-plugin-transform-es2015-arrow-functions

這裏延用上面須要compile的源代碼:

var fetch = args => args;
console.log(Promise);

改寫.babelrc設置文件:

{
  "presets": [],
  "plugins": [
    "check-es2015-constants",
    "transform-es2015-block-scoping",
    "transform-es2015-arrow-functions"
  ]
}

編譯效果:

var fetch = function (args) {
  return args;
};
console.log(Promise);

編譯勝利,unbelievable, we did it!!!,是不是是真的很簡樸?先別自滿???,另有一個Promise沒有處理呢。有欣喜喲!!!

  • Promise

我有一個題目:我特地將上面的兩個例子放在一同,是因為他們都屬於對新語法Syntax舉行編譯,而Promise是作為一個全局api的存在,在大部份瀏覽器中是不存在這個全局api的,假如讓你來處理這個題目,你會怎樣做?

你的答案:是的,沒錯!就是在不支撐Promise的環境中完成Promise,在babel中被稱為polyfill,注重它和shim的區分哦~

babel-polyfill 文檔最簡樸的運用:

npm install --save-dev babel-polyfill

Use it by requiring it at the top of the entry point to your application or in your bundler config. —在進口文件的最頂層作用域直接引入

到這裏我們已完成既定的3個目的,然則你有無想過,跟着我們ES6新特徵的增添,plugin的長度也逐步增添,能夠碰見會有多長?,而且本身去找這些對應的plugin也是比較貧苦的。有無傻瓜式的集成要領呢?您接着往下看。

Preset

為了輕易,Babel團隊將一些Plugins鳩合在一同,並稱之為preset。所以一個preset是一系列plugin的總和。根據年份分別:

ES2015/ ES-2016/ES2017 等等,還延長了stage的觀點,詳情請查閱官網。

babel-preset-env

A Babel preset that compiles ES2015+ down to ES5 by automatically determining the Babel plugins and polyfills you need based on your targeted browser or runtime environments.

不須要指定任何的
plugin
polyfill,Babel preset 能夠將ES6+的新語法向下編譯為ES5代碼,根據你指定的運轉環境。詳細的設置項請看官網。

Without any configuration options, babel-preset-env behaves exactly the same as babel-preset-latest (or babel-preset-es2015, babel-preset-es2016, and babel-preset-es2017 together).
不須要做任何設置選項,它和babel-preset-latest表現一致,或許說和babel-preset-es2015, babel-preset-es2016, babel-preset-es20174個preset總和一致。

覺得是不是是很牛逼!下面我們來嘗試一個例子。為防備有任何的代碼污染,我卸載一切npm package

最初的模樣:

{
  "name": "babelrc",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "babel src -d lib"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {}
}

我裝置時發明@babel/preset-env還處於bate版本,運用時另有一些題目,所以決議照樣運用老版本。

(1)裝置babel-preset-env

《babel入門》

上圖為babel-preset-env的一些依靠,重要為一些helperplugin

為了考證出babel-preset-env的是不是滿足要求,我新增了幾行包含ES6的代碼:

const fetch = args => args;
console.log(Promise);

// 新增一些代碼
class G {

}

let [a, b, c] = [1, 2, 3];

(async () => {
  await console.log(1)
})();

(2)設置.babelrc

{
  "presets": ["env"],
  "plugins": []
}

(3)編譯效果

"use strict";

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

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

var fetch = function fetch(args) {
  return args;
};
console.log(Promise);

// 新增一些代碼

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

var a = 1,
    b = 2,
    c = 3;


_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
  return regeneratorRuntime.wrap(function _callee$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return console.log(1);

        case 2:
        case "end":
          return _context.stop();
      }
    }
  }, _callee, undefined);
}))();

我就問另有誰???一切的新語法特徵都被勝利處置懲罰了。

Runtime

官網文檔

babel為源代碼非實例要領(比方Object.assign)和 babel-runtime/helps下的東西函數自動引用了polyfill。如許能夠防止全局空間的污染,異常合適用於JS庫和東西包的完成。然則實例要領(比方someString.includes("target"))照樣須要運用babel-polyfill

假如你是新手,你能夠沒有注重到,babel編譯時會在每一個文件天生一些須要協助函數,假如文件比較多,那末這些反覆的代碼會增添編譯后的代碼體積。下面是一個例子:

源代碼

class G {
  
}

.babelrc設置

{
  "presets": ["env"],
  "plugins": []
}

編譯代碼

"use strict";

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

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

// _classCallCheck就是一個內部天生的協助函數

為了優化編譯體積,babel 團隊推出了 babel-plugin-transform-runtime + babel-runtime來處理這個題目。先看一下直觀體驗:

源代碼

class G {
  
}

.babelrc設置

{
  "presets": ["env"],
  "plugins": ["transform-runtime"]
}

編譯后的代碼:

"use strict";

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

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var G = function G() {
  (0, _classCallCheck3.default)(this, G);
};

經由過程對照能夠看出,第二種計劃直接從babel-runtime引入babel-runtime/helpers/classCallCheck,防止本身定義,從而削減代碼的體積。

除了這個長處不測

  • babel-runtime

《babel入門》

三個重要部份:core.js + helpers+ regenerator

固然除了上面的要領,經由過程按需引入 polyfillstransforms更能帶來更多的體積優化。

削減對不必要瀏覽器的兼容來削減 polyfillstransforms的引入:

{
  "presets": [
    ["env", {
      "targets": {
        // The % refers to the global coverage of users from browserslist
        "browsers": [ ">0.25%", "not ie 11", "not op_mini all"]
      }
    }]
  ]
}

答疑

(1)能夠你發明了我並沒有裝置babel-cli,為何我能運用babel敕令?

因為我在全局裝置了babel

(2) browserslistrc 設置變動以後 babel編譯后的代碼怎樣沒有轉變。或許說 browserslistrc 影響babel編譯的詳細表現是怎樣的?

臨時我也不知道,我正在研討,背面更新。

參考

[1] browserslist
[2] browserslist-example
[3] browserslist-queries

因為本人表達能力真的很差,表達不夠清晰還望人人多多見諒。

    原文作者:gaollard
    原文地址: https://segmentfault.com/a/1190000014571128
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞