babel-preset-env使用指南


文章概覽

babel-preset-env是非常重要且常用的一個插件預設,掌握它的用法以及實現原理非常有必要。

本文主要內容包括:babel-preset-env是什么、入門實例、如何配置以支持特定版本的 node/瀏覽器、實現原理等。

本文所有例子可以在 筆者的github 找到。

babel-preset-env簡介

首先,介紹下歷史背景,對了解和學習 babel-preset-env 有幫助。

最初,為了讓開發者能夠盡早用上新的JS特性,babel團隊開發了babel-preset-latest。這個preset比較特殊,它是多個preset的集合(es2015+),並且隨着ECMA規范的更新更增加它的內容。

比如,當前(2018.06.02),它包含的preset包括:es2017、es1016、es2015。

到了明年,可能它包含的preset就包括:es2018、es2017、es2016、es2015。

隨着時間的推移,babel-preset-latest 包含的插件越來越多,這帶來了如下問題:

  1. 加載的插件越來越多,編譯速度會越來越慢;
  2. 隨着用戶瀏覽器的升級,ECMA規范的支持逐步完善,編譯至低版本規范的必要性在減少(比如ES6 -> ES5),多余的轉換不單降低執行效率,還浪費帶寬。

因為上述問題的存在,babel官方推出了babel-preset-env插件。它可以根據開發者的配置,按需加載插件。配置項大致包括:

  1. 需要支持的平台:比如node、瀏覽器等。
  2. 需要支持的平台的版本:比如支持node@6.1等。

默認配置的情況下,它跟 babel-preset-latest 是等同的,會加載從es2015開始的所有preset。

入門例子

首先,安裝依賴。

npm install babel-cli --save-dev
npm install babel-preset-env --save-dev

創建 index.js。

let foo = () => 'foo';

配置文件 .babelrc 如下,當前為默認配置。

{
  "presets": [ "env" ]
}

運行轉換命令

`npm bin`/babel index.js

轉換結果如下:

'use strict';

var foo = function foo() {
  return 'foo';
};

針對node版本的配置

前面提到,babel-preset-env 提供了更精細化的配置,以提升編譯速度,同時減少代碼冗余。

我們看下實際例子。假設當前有如下代碼:

// index.js
async function foo () {}

采用 babel-preset-env,默認配置下,輸出的轉換結果如下(具體內容不用關心,知道很長就行了)。

"use strict";

var foo = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, this);
  }));

  return function foo() {
    return _ref.apply(this, arguments);
  };
}();

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"); }); }; }

如果我們的代碼是打算跑在node@8.9.3版本上,那上面的兼容代碼就有點多余了,因為node@8.9.3已經支持了async/await。

修改下 .babelrc,加上配置參數"target",它表示我們需要支持哪些平台+哪些版本。這里聲明我們要支持的是node版本為8.9.3。

{
  "presets": [
    ["env", {
      "targets": {
        "node": "8.9.3"
      }      
    }]
  ]
}

再次進行轉碼,結果如下。幾乎沒有變化,因為node最新版本支持 async/await,因此不需要額外的兼容代碼。

"use strict";

async function foo() {}

針對瀏覽器版本的配置

babel-preset-env 同樣提供了對瀏覽器版本的配置能力。

支持特定版本的瀏覽器

假設我們的代碼如下:

let nick = '程序猿小卡';
let desc = `你好 ${nick}`;

如果只需要支持 IE11,那么可以這樣配置。

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": "ie 11"
      }      
    }]
  ]
}

如果只需要支持支持 Edge 16,那么可以這樣配置

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": "edge 16"
      }      
    }]
  ]
}

因為 IE 11 不支持模板字面量,而 Edge 16支持模板字面量,因此上面配置的轉碼結果是不同的,讀者可以自行嘗試。

支持特定版本范圍的瀏覽器

大部分時候,我們要針對的都是特定范圍的瀏覽器,比如 IE8+,那么,逐個指定是不現實的。好在 babel-preset-env 支持要支持的版本范圍。

比如,我們需要支持 IE8+、chrome62+,那么可以這樣配置:

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": [ "ie >= 8", "chrome >= 62" ]
      }      
    }]
  ]
}

看下前面聲明的范圍涵蓋了哪些瀏覽器。

$ `npm bin`/browserslist "ie >= 8, chrome >= 62"
chrome 66
chrome 65
chrome 64
chrome 63
chrome 62
ie 11
ie 10
ie 9
ie 8

對瀏覽器版本范圍的配置,babel-preset-env 借助了 browserslist 這個庫,還有更多的配置方式,可以自行探究。

babel-preset-env實現原理

實現原理很簡單。官方文檔寫的挺簡潔的,挑重點大致翻譯下。

1、首先,檢測瀏覽器對JS特性的支持程度,比如通過通過 compat-table 這樣的外部數據。

2、將 JS特性 跟 特定的babel插件 建立映射,映射關系可以參考 這里

3、stage-x 的插件不包括在內。

4、根據開發者的配置項,確定至少需要包含哪些插件。比如聲明了需要支持 IE8+、chrome62+,那么,所有IE8+需要的插件都會被包含進去。

相關鏈接

https://babeljs.io/docs/plugins/preset-env/#how-it-works


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM