Skip to content

1.脚手架@babel/cli

babel 作为一门转换工具。它自带了一套自己的脚手架工具。

新建一个项目,执行:

shell
yarn add @babel/cli -D

TIP

babel@7.0 版本开始,babel 会将它所有的官方包都放在 @babel 这个命名空间下。其实这并不是 babel 的特例。而是 npm 对于它自身包管理的一种优化。 babel 只是顺道遵守了而已。

这样的话,我们就可以使用 babel 命令行。由于环境变量的原因,所以我们配置下 package.json (你也可以利用 npx 取代这种方式)。利用 npm 来执行 babel:

json
{
  "scripts": {
    "compiler": "babel './src/main.js' --out-dir dist"
  }
}

当执行 yarn compiler 时,按照道理来说babel 就会将 src 目录下的 main.js,转译到 dist 目录中。

但现在执行 yarn compiler 后,会发现 dist/main.js 文件中的代码并没有任何转换迹象。

2.核心库@babel/core

babel的核心功能包含在 @babel/core 模块中。安装:

shell
yarn add @babel/core -D

这时执行 yarn compiler, 代码仍然不会转换。

可以将 @babel/core 理解成一个核心转换模块函数,它的执行依赖于 options 配置。如果没有 options ,那么这个函数什么也不会做。

js
function core (code, options = []) {
  options.forEach(item => {
    code += item
  })
  return code
}

而这些 optionsbabel 中对应的就是 plugins

3.插件plugins

安装下转换箭头函数的插件:

shell
yarn add @babel/plugin-transform-arrow-functions -D

package.json 中的 scripts 添加命令:

json
{
  "scripts": {
    "compiler:plugin": "babel './src/main.js' --out-dir dist --plugins=@babel/plugin-transform-arrow-functions"
  }
}

再次执行 yarn compiler:plugin,会发现 main.js 中的箭头已被转换:

js
var _this = this;

// 1.arrow function
const arrowFun = function () {
  console.log('arrow-function', _this);
};

4.预设presets

presets 其实就是一组 plugins 的集合。官方提供的预设有四组:

  • @babel/preset-env
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

其中 @babel/preset-env 代表的是对于环境 environment 的预设。现在我们使用 --presets 来代替上面使用的 --plugins

json
{
  "scripts": {
    "compiler:preset": "babel './src/main.js' --out-dir dist --presets=@babel/preset-env"
  }
}

执行 yarn compiler:preset。会发现代码已经被转换成ES5代码(除了需要@babel/polyfill的语法。如promise等。)

另外直接执行转译过后的代码,会有报错 ReferenceError: regeneratorRuntime is not defined。这是因为 async await 的实际运行也需要 @babel/polyfill

具体代码可见下方。

TIP

在未指定浏览器目标的情况下,@babel/preset-env 会将所有 ES2015-ES2020 代码转换为与ES5兼容。 但是不建议以这种方式使用 @babel/preset-env ,因为它没有利用针对特定环境/版本的功能。

js
"use strict";

var _this = void 0;

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }

function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }

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

// 1.arrow function
var arrowFun = function arrowFun() {
  console.log('arrow-function', _this);
}; 

// 2.class
var Person = /*#__PURE__*/function () {
  function Person() {
    _classCallCheck(this, Person);

    this.name = name;
  }

  _createClass(Person, [{
    key: "say",
    value: function say() {
      alert('hello');
    }
  }]);

  return Person;
}(); 

// 3.promise es6新增
var promise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    if (Math.random() * 10 >= 5) {
      resolve('大于5');
    } else {
      reject('小于5');
    }
  }, 2000);
});

// 4.async await es7
function fn() {
  return _fn.apply(this, arguments);
}

function _fn() {
  _fn = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    var result;
    return regeneratorRuntime.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            _context.prev = 0;
            _context.next = 3;
            return promise;

          case 3:
            result = _context.sent;
            console.log(result);
            _context.next = 10;
            break;

          case 7:
            _context.prev = 7;
            _context.t0 = _context["catch"](0);
            console.warn('error', _context.t0);

          case 10:
            console.log('--- after promise ---');

          case 11:
          case "end":
            return _context.stop();
        }
      }
    }, _callee, null, [[0, 7]]);
  }));
  return _fn.apply(this, arguments);
}
fn(); 

// 5.includes
var flag = [1, 2, 3].includes(1);
console.log('includes', flag);

5.总结

这一章,主要来了解快速使用 babel 需要安装什么。

  • @babel/cli, 官方脚手架。
  • @babel/core, 核心转换模块。
  • @babel/plugins 或者 @babel/presets, 具体的转换规则。
  • @babel/polyfill, 低版本浏览器需要腻子。不过 babel 已经有新的使用方法来弥补 @babel/polyfill 存在的缺点。

后面我们会循序渐进的来深入了解。