iT邦幫忙

0

[JS]使用babel 轉譯 ES7 的 Async function(適用於瀏覽器)--2

本篇主旨:透過babel轉譯使用Async function的js檔,使其可在瀏覽器(非Node環境)運行
上篇

閱前注意:

本篇為個人使用筆記,為供未來使用,會包含一些瑣碎的設定
新手發文,還請多多包涵並給予指教
流程為個人嘗試以及思考的脈絡,未必是最佳化的流程

Step0 發現問題

  1. 我們回到編譯過的dist/index.js檔,聚焦於找不到的regeneratorRuntime
var asyncFunc = /*#__PURE__*/function () {
//regeneratorRuntime在這!
  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);
  }));

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

遍尋上下文,確實找不到regeneratorRuntime在哪定義,唯一合理的解釋,只有regeneratorRuntime是被定義在其他地方而在這裡使用。

Step1 可能的解答

我們打開官方文件,搜索一番,發現:

The @babel/polyfill module includes core-js and a custom regenerator runtime to emulate a full ES2015+ environment.

原來,babel在轉譯一些太新的特性時,會產生一些額外的"引用",這些引用存在於@babel/polyfill裡,regeneratorRuntime便是其中之一。
這意味著,在你編譯後的檔案中必須包含對@babel/polyfill的引用。

Step2 開始解決

1.安裝plugin

我們順著官方文件往下看,找找該如何引入@babel/polyfill,然而我們發現:

? As of Babel 7.4.0, this package has been deprecated in favor of directly including core-js/stable (to polyfill ECMAScript features) and regenerator-runtime/runtime (needed to use transpiled generator functions):

官方並不推這直接引用@babel/polyfillcore-js/stable以及regenerator-runtime/runtime,因為他們太肥了,例如我們只需要regeneratorRuntime,便不需要整包引入。

對此,官方推薦:

For library/tool authors this may be too much. If you don't need the instance methods like Array.prototype.includes you can do without polluting the global scope altogether by using the transform runtime plugin instead of @babel/polyfill.

打開transform runtime plugin文件,按部就班

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
  1. @babel/plugin-transform-runtime-用來在轉譯後的js引入Step1所說的額外引入
  2. @babel/runtime-額外引入的實體檔案,也就是包含regeneratorRuntime的地方,注意安裝時的參數為--save沒有-dev,因為它無論是在測試或正式環境都需要被參考

2.編輯.babelrc

我們需要加入plugins設定轉譯時使用的plugins

{
  "presets": ["@babel/env"],
  //加入以下設定,轉譯時會使用@babel/plugin-transform-runtime
  "plugins": [
    [
      "@babel/plugin-transform-runtime"
    ]
  ]
}

3.執行編譯

於terminal執行:

npm run trans

4.檢視轉譯後的檔案

"use strict";

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

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

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

var asyncFunc = /*#__PURE__*/function () {
  var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
    return _regenerator["default"].wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));

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

走到這一步,原以為留暗花明又一村,卻是半路殺出程咬金,細心的人可能已經發現了下面的問題

  1. babel轉譯後的引用是透過require,這意味著babel的轉譯是為了在CommonJS中執行,或者說,在Node環境中執行
  2. 如果我們的目標是在ES5的環境中使用babel轉譯的檔案,這意味著我們不能做任何引入,自然不能require與import

Step3 小節

為了達成最終在瀏覽器+ES5的環境下使用babel轉譯過的async function,我們必須解決以下關鍵問題

  • 不使用任何引入(require/import)下使用regeneratorRuntime
    或者
  • regeneratorRuntime這部分的程式碼注入轉譯後的js

礙於篇幅,請待下回分解

下一篇


尚未有邦友留言

立即登入留言