babel-polyfill VS babel-runtime

_墨白發表於2019-03-04

背景

在專案迭代過程中,因為有相容 IE 的需求,根據文件使用babel-polyfillbabel-runtime兩個外掛解決問題。但是對於二者之間的恩怨情仇,卻不甚瞭解,便打算細細探究一番。

關於 Babel

如果我們沒有配置一些規則,Babel 預設只轉換新的 JavaScript 句法(syntax),而不轉換新的 API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全域性物件,以及一些定義在全域性物件上的方法(比如 Object.assign )都不會轉碼。
所以,當這樣的程式碼出現時:

const key = `babel`
const obj = {
    [key]: `foo`,
}
複製程式碼

Babel 預設會編譯成下面的程式碼

function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
    } else {
        obj[key] = value;
    }
    return obj;
}

var key = `babel`;
var obj = _defineProperty({}, key, Object.assign({}, { key: `foo` }));
複製程式碼

我們可以看到程式碼中多了一個名為_defineProperty的幫助函式,但是這個幫助函式僅僅在當前模組中生效,因此其他模組中如果用到了同樣的語法,編譯後就會出現大量的重複程式碼。

babel-polyfill

原理是當執行環境中並沒有實現的一些方法,babel-polyfill 會給其做相容。
但是這樣做也有一個缺點,就是會汙染全域性變數,而且專案打包以後體積會增大很多,因為把整個依賴包也搭了進去。所以並不推薦在一些方法類庫中去使用。

用法

1. `npm install --save babel-polyfill`
2. 在應用的入口引用,以確保它能夠最先載入:
`import "babel-polyfill";` 或者
`require("babel-polyfill");`
複製程式碼

babel-runtime

為了不汙染全域性物件和內建的物件原型,但是又想體驗使用新鮮語法的快感。就可以配合使用babel-runtimebabel-plugin-transform-runtime
比如當前執行環境不支援promise,可以通過引入babel-runtime/core-js/promise來獲取promise
或者通過babel-plugin-transform-runtime自動重寫你的promise。也許有人會奇怪,為什麼會有兩個runtime外掛,其實是有歷史原因的:剛開始開始只有babel-runtime外掛,但是用起來很不方便,在程式碼中直接引入helper 函式,意味著不能共享,造成最終打包出來的檔案裡有很多重複的helper程式碼。所以,Babel又開發了babel-plugin-transform-runtime,這個模組會將我們的程式碼重寫,如將Promise重寫成_Promise(只是打比方),然後引入_Promise helper函式。這樣就避免了重複打包程式碼和手動引入模組的痛苦。

用法

1. `npm install --save-dev babel-plugin-transform-runtime`
2. `npm install --save babel-runtime`
3. 寫入 `.babelrc`
複製程式碼
{
  "plugins": ["transform-runtime"]
}
複製程式碼

啟用外掛babel-plugin-transform-runtime後,Babel就會使用babel-runtime下的工具函式,轉譯程式碼如下:

`use strict`;

var _defineProperty2 = require(`babel-runtime/helpers/defineProperty`);

var _defineProperty3 = _interopRequireDefault(_defineProperty2);

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

var key = `babel`;
var obj = (0, _defineProperty3.default)({}, key, `foo`);
複製程式碼

不足

babel-runtime 不能轉碼例項方法,比如這樣的程式碼:

`!!!`.repeat(3);
`hello`.includes(`h`);
複製程式碼

這隻能通過 babel-polyfill 來轉碼,因為 babel-polyfill 是直接在原型鏈上增加方法。

And more

隨著歷史程式的發展,新一代的 babel-prenset-env 很強大,瞭解一下?

參考連結

自由轉載-非商用-非衍生-保持署名(創意共享3.0許可證

相關文章