@babel/plugin-transform-runtime


博客:姜瑞濤的官方網站
原文鏈接:https://www.jiangruitao.com/babel/transform-runtime/
版權采用《署名-非商業性使用-禁止演繹 4.0 國際》許可協議 轉載需注明原文作者、鏈接與版權協議

本節主要講@babel/plugin-transform-runtime以及@babel/runtime。

在我們用Babel做語法轉換的時候(注意,這里是單純的做語法轉換,暫時不使用polyfill補齊API),需要Babel在轉換后的代碼里注入一些函數才能正常工作,先看一個例子。

github配套代碼是babel13的例子。

Babel配置文件如下,用@babel/preset-env做語法轉換:

  {
    "presets": [
      "@babel/env"
    ],
    "plugins": [
      
    ]
  }

轉換前的代碼使用了ES6的class類語法:

  class Person {
    sayname() {
      return 'name'
    }
  }

  var john = new Person()
  console.log(john)

Babel轉碼后生成的代碼如下:

  "use strict";

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

  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

  var Person = /*#__PURE__*/function () {
    function Person() {
      _classCallCheck(this, Person);
    }

    _createClass(Person, [{
      key: "sayname",
      value: function sayname() {
        return 'name';
      }
    }]);

    return Person;
  }();

  var john = new Person();
  console.log(john);

可以看到轉換后的代碼上面增加了好幾個函數聲明,這就是注入的函數,我們稱之為輔助函數。@babel/preset-env在做語法轉換的時候,注入了這些函數聲明,以便語法轉換后使用。

但樣這做存在一個問題。在我們正常的前端工程開發的時候,少則幾十個js文件,多則上千個。如果每個文件里都使用了class類語法,那會導致每個轉換后的文件上部都會注入這些相同的函數聲明。這會導致我們用構建工具打包出來的包非常大。

那么怎么辦?一個思路就是,我們把這些函數聲明都放在一個npm包里,需要使用的時候直接從這個包里引入到我們的文件里。這樣即使上千個文件,也會從相同的包里引用這些函數。通過webpack這一類的構建工具打包的時候,我們只會把使用到的npm包里的函數引入一次,這樣就做到了復用,減少了體積。

@babel/runtime就是上面說的這個npm包,@babel/runtime把所有語法轉換會用到的輔助函數都集成在了一起。

我們先安裝這個包:

  npm install --save @babel/runtime
  npm install --save-dev @babel/cli @babel/core  @babel/preset-env

然后到node_modules目錄下看一下這個包結構

_classCallCheck, _defineProperties與 _createClass這個三個輔助函數就在圖片所示的位置,我們直接引入即可。

github配套代碼是babel13a的例子。

我們手動把輔助函數替換掉函數聲明,之前文件的代碼就變成如下所示:

  "use strict";

  var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
  var _defineProperties = require("@babel/runtime/helpers/defineProperties");
  var _createClass = require("@babel/runtime/helpers/createClass");

  var Person = /*#__PURE__*/function () {
    function Person() {
      _classCallCheck(this, Person);
    }

    _createClass(Person, [{
      key: "sayname",
      value: function sayname() {
        return 'name';
      }
    }]);

    return Person;
  }();

  var john = new Person();
  console.log(john);

這樣就解決了代碼復用和最終文件體積大的問題。不過,這么多輔助函數要一個個記住並手動引入,平常人是做不到的,我也做不到。這個時候,Babel插件@babel/plugin-transform-runtime就來幫我們解決這個問題。

@babel/plugin-transform-runtime有三大作用,其中之一就是自動移除語法轉換后內聯的輔助函數(inline Babel helpers),使用@babel/runtime/helpers里的輔助函數來替代。這樣就減少了我們手動引入的麻煩。

github配套代碼是babel13b的例子。

現在我們除了安裝@babel/runtime包提供輔助函數模塊,還要安裝Babel插件@babel/plugin-transform-runtime來自動替換輔助函數:

  npm install --save @babel/runtime
  npm install --save-dev @babel/cli @babel/core  @babel/preset-env @babel/plugin-transform-runtime

現在,我們的Babel配置文件如下:

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

轉換前a.js代碼:

  class Person {
    sayname() {
      return 'name'
    }
  }

  var john = new Person()
  console.log(john)

執行"npx babel a.js -o b.js"命令后,轉換生成的b.js里代碼如下:

  "use strict";

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

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

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

  var Person = /*#__PURE__*/function () {
    function Person() {
      (0, _classCallCheck2["default"])(this, Person);
    }

    (0, _createClass2["default"])(Person, [{
      key: "sayname",
      value: function sayname() {
        return 'name';
      }
    }]);
    return Person;
  }();

  var john = new Person();
  console.log(john);

可以看到,它生成的代碼比我們完全手動引入@babel/runtime里的輔助函數更加優雅。實際前端開發的時候,我們除了安裝@babel/runtime這個包外,一定會安裝@babel/plugin-transform-runtime這個Babel插件包的。

下一節接着講@babel/plugin-transform-runtime的使用。

注:

1.每個轉換后的文件上部都會注入這些相同的函數聲明,那為何不用webpack一類的打包工具去掉重復的函數聲明,而是要單獨再引一個輔助函數包?

webpack在構建的時候,是基於模塊來做去重工作的。每一個函數聲明都是引用類型,在堆內存不同的空間存放,缺少唯一的地址來找到他們。所以webpack本身是做不到把每個文件的相同函數聲明去重的。因此我們需要單獨的輔助函數包,這樣webpack打包的時候會基於模塊來做去重工作。


免責聲明!

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



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