Skip to content

Latest commit

 

History

History
572 lines (386 loc) · 17.3 KB

5.Babel:配置标准库和助手.md

File metadata and controls

572 lines (386 loc) · 17.3 KB

5. Babel:配置标准库和助手

转载请注明出处 https://brickcarvingartist.github.io/Setting-up-ES6/5.Babel%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%A0%87%E5%87%86%E5%BA%93%E5%92%8C%E5%8A%A9%E6%89%8B

这一章阐述如何配置及Babel6如何接入它自身的帮手方法和ES6标准库。

下面的Github仓库让你与我们在这里阐述的东西玩耍:babel-config-demo

5.1 概览

通过Babel提供的代码通常有两种外部依赖:

  • 助手方法(比如给子类用的)
  • 标准库功能(比如Map或者ES6字符串方法)

实现这些依赖有两种方式:通过全局安装功能或通过模块。两种情况下的功能都有npm包交付。

5.1.1 来自全局变量的额外依赖

下面的npm包全局安装它们变量并让你通过全局变量接入它:

  • (P)babel-plugin-external-helpers和(I)生成的文件:全局帮手
  • (I)babel-polyfill:全局标准库
  • ES5,ES6+,运行时再生器
  • (I)core-js:全局标准库
  • core-js/shim:ES5,ES6+
  • core-js/es6:ES6

装配:

  • (P)插件:以一个开发依赖安装的npm包并在Babel配置信息(参见“配置Babel6”章节)。
  • (I)导入:以一个运行时依赖安装npm包并在开始编码时导入。

5.1.2 通过模块引入外部依赖

下面的npm包可通过模块用依赖:

  • (P)babel-plugin-transform-runtime,(M)babel-runtime:通过引入的帮手和标准库(插件生成各引入)。
  • Babel帮手(必要)
  • 标准库(可被关闭)
  • 重生器API(可被关闭)
  • (M)core-js:来自模块的标准库。
  • 单体:
import _repeat from 'core-js/library/fn/string/repeat';
  • 命名空间对象(ES5,ES6+):
import * as core from 'core-js/library';
const myStr = core.String.repeat('*', 10);
  • 命名空间对象(ES6):
import * as core from 'core-js/library/es6';
const myStr = core.String.repeat('*', 10);

装配:

(P)插件:以一个开发依赖安装的npm包并在Babel配置信息(参见“配置Babel6”章节)。

(M)模块:以运行时依赖安装npm包并在运行时引入单体(当需要时)。

5.2 来自代码编译过的代码的外部依赖

通过Babel生成的代码在两种额外的依赖中需要被实现。

第一种,大多数代码调用ES6标准库中功能。默认的,你通过全局变量接入这些功能:

let m = new Map();
if (str.startsWith('/')) ···

第二种,Babel的被代码翻译过的代码调用帮手方法(比如给子类用的)。默认的,帮手方法是行内的,插入每个文件。比如(_classCallCheck是一个帮手方法):

//---------- 输入:ES6代码
class Person {}

//---------- 输出:用了帮手方法的ES5代码
"use strict";

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

var Person = function Person() {
    _classCallCheck(this, Person);
};

一旦同样的帮手在多个文件中被使用各行内帮手会带到代码复制集中。

你能得到标准库和非行内帮手有其中的两种选择:通过全局变量和通过模块导入。如何去做会被下节中介绍。

5.3 来自全局变量的外部依赖

5.3.1 来自全局变量的帮手:babel-plugin-external-helpers

有两个东西你需要下载:

  • 插件babel-plugin-external-helpers
  • 以开发环境依赖安装:
npm install --save-dev babel-plugin-external-helpers
  • 在Babel配置信息中激活:
"plugins": ["external-helpers"]
  • 设置上全局变量的babelHelpers文件:
  • 需要在运行时加载或引入,越早越好。举个例子:
import 'babelHelpers';
  • 来自命令行工具babel-external-helpers(如何去做会被下节中介绍)生成的。
  • 以一个开发依赖安装babel-external-helpers
npm install --save-dev babel-cli

这插件确保所有帮手通过全局对象babelHelpers的各方法调用。在这节,我将阐述它如何运作。在下一节,我会介绍如何假设babelHelpers

作为一个例子,考虑下面的ES6代码,在代码编译前:

class Point {
	constructor(x, y) {
		this.x = x;
		this.y = y;
	}
	toString() {
		return `(${this.x}, ${this.y})`;
	}
}

如果你不与external-helpers而单用ES2016前置项代码翻译它,你会得到:

"use strict";

var _createClass = (function () {
	···
})();

function _classCallCheck(instance, Constructor) {
	···
}

var Point = (function () {
	function Point(x, y) {
		_classCallCheck(this, Point);

		this.x = x;
		this.y = y;
	}

	_createClass(Point, [{
		key: "toString",
		value: function toString() {
			return "(" + this.x + ", " + this.y + ")";
		}
	}]);

	return Point;
})();

注意两个帮手函数_createClass_classCallCheck

如果你激活了external-helpers插件,你会得到这个输出:

"use strict";

var Point = (function () {
	function Point(x, y) {
		babelHelpers.classCallCheck(this, Point);

		this.x = x;
		this.y = y;
	}

	babelHelpers.createClass(Point, [{
		key: "toString",
		value: function toString() {
			return "(" + this.x + ", " + this.y + ")";
		}
	}]);
	return Point;
})();
5.3.1.1 安装全局的Babel帮手

你如何有各帮手的对象到全局变量babelHelpers中?通过一个有命令行工具babel-external-helpers生成的文件。这个工具是npm包babel-cli的一部分。这个文件适用三种格式:

  • babel-external-helpers -t global

显印一个置入各帮手至global.babelHelpers的Node.js模块。

  • babel-external-helpers -t var

显印一个以var声明至全局作用域并将一个有各帮手的对象转赋至它的babelHelpers的脚本文件(浏览器代码)。

  • babel-external-helpers -t umd

显印一个以CommonJS模块,AMD模块及以一个脚本(通过全局变量)运作的普适模块定义(UMD)。

这个调用会显印有用的信息:

babel-external-helpers --help

5.3.2 标准库以及更多来自各全局变量的:babel-polyfill

babel-polyfill包含了一个会安装一些东西到全局变量里去的模块:

  • ES5 polyfills(无论是否在ES5标准库里缺失):Object.create()Array.prototype.forEach()等等。
  • ES6 polyfillsMapString.prototype.repeat()等等。
  • 一些ECMAScript未来提案的polyfillsObject.entries()Array.prototype.includes()等。
  • 在运行时用的重生器(那些由Babel去用来代码翻译ES6生成ES5的)。
  • polyfills由[core-js](https://github.com/zloirock/core-js)提供,正如你所见当你看到两个导入表达式构成这个模块
import "core-js/shim";
import "babel-regenerator-runtime";
5.3.2.1 安装

当你发现任意以上功能在你的代码翻译的代码中缺失时通过npm以一个运行时的依赖安装babel-polyfill。在当前的各Node.js版本(译者注:指7.0+版本),你大概不需要用到它,因为这些版本携带着大多数ES6标准库和本地化的生成器。

这个模块被通过这样安装:

npm install --save babel-polyfill

你必须在使用标准库之前引入它:

import 'babel-polyfill';

这个模块将检查全局变量并只会安装缺失的功能。这个polyfill的负面是你总是交付并加载全部的功能,无关你要用多少。

5.3.3 仅来自全局变量中的标准库:core-js

如果你不需要运行时的重生器,你可以直接使用core-jspolyfill。

你可以像这样安装它:

npm install --save

这有一些途径去安装polyfill功能。两个常见的是:

  • import 'core-js/shim';

ES5,ES6和ES6后的各功能Polyfills。

  • import 'core-js/es6';

仅ES6各功能的Polyfills。

import表达式需要你接入运行时库才能生效。它全局地安装polyfills。

5.4 通过模块引入外部依赖

5.4.1 来自“引入”的帮手和标准库:babel-plugin-transform-runtime

这个方法的两个部分:

  • 一个包含帮手和标准库的模块。以一个运行时依赖安装:
npm install --save babel-runtime
  • 一个改变Babel输出的插件以便帮手和标准库由babel-runtime被导入。
  • 以一个开发依赖安装:
npm install --save-dev babel-plugin-transform-runtime

在Babel配置信息中激活:

"plugins": ["transform-runtime"]

这插件重定了三种来自babel-runtime的导入操作:

  1. Babel各助手(必要)
  2. 标准库(可被关闭)
  3. 重生器API(可被关闭):通过babel-plugin-transform-regenerator使用来代码翻译ES6生成器至ES5代码。

babel-runtime变为一个运行时依赖,但引入表达式由插件创建——你不需要引入任何东西。

这个插件可让你像以下方式关闭2号和3号:

"plugins": [
	["transform-runtime",
		{ "polyfill": false, "regenerator": false }],
]

下面两节探索transform-runtime如何为帮手和标准库工作。

5.4.2 transform-runtime和各Babel帮手

transform-runtime对各帮手效果很好。考虑下面的ES6代码:

class Point {
	constructor(x, y) {
		this.x = x;
		this.y = y;
	}
	toString() {
		return `(${this.x}, ${this.y})`;
	}
}

有了插件,这会代码翻译成:

"use strict";

var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); //(A)

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require("babel-runtime/helpers/createClass"); //(B)

var _createClass3 = _interopRequireDefault(_createClass2);

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

var Point = (function () {
	function Point(x, y) {
		(0, _classCallCheck3.default)(this, Point);

		this.x = x;
		this.y = y;
	}

	(0, _createClass3.default)(Point, [{
		key: "toString",
		value: function toString() {
			return "(" + this.x + ", " + this.y + ")";
		}
	}]);
	return Point;
})();

帮手的classCallCheck(行A)及createClass(行B)现在被babel-runtime导入。要注意的是每一个方法坐落在他自己的模块中,确保你确实在用的仅有的各方法在一个打包的代码中结束。

帮手方法_interopRequireDefault确保不仅朴实的CommonJS模块还有代码翻译过的ES6模块都能被使用。

ℹ️Babel如何编译ES6模块至CommonJS模块的细节会被“Babel和CommonJS模块”章介绍。

5.4.3 transform-runtime和标准库

transform-runtime插件自动处理帮手,但对于绝大多数的标准库,额外的工作是被需要的。让我们以下面的方式调试接入标准库的支持情况:

  • 接入各函数(已支持)
  • 常规地接入方法(未被支持)
  • 通过定制各多功能函数接入方法(已支持)
5.4.3.1 接入各函数(已支持)

transform-runtime会做适当方法接入侦测:被命名空间的各函数(比如Object.assignMath.sign)和各构造函数(比如MapPromise)。比如,接下来的ES6代码:

let m = new Map();
Math.sign(-1);
This code is transpiled to:

"use strict";

var _sign = require("babel-runtime/core-js/math/sign"); //(A)

var _sign2 = _interopRequireDefault(_sign);

var _map = require("babel-runtime/core-js/map"); //(B)

var _map2 = _interopRequireDefault(_map);

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

var m = new _map2.default();
(0, _sign2.default)(-1);

注意行A和行B的各引入内容。

5.4.3.2 常规地接入方法(未被支持)

不过,transform-runtime不会侦测像接下来那些ES6代码的方法调用:

console.log('a'.repeat(3));
console.log(String.prototype.repeat.call('b', 3));

这会被代码翻译成:

'use strict';

console.log('a'.repeat(3));
console.log(String.prototype.repeat.call('b', 3));

它们没有引入——输入的代码基本上是无法触及的。第一个方法调用是动态分发,所以transform-runtime不能抓获它是不足为奇的。然而,第二个是直接方法调用并且一样会被忽略。

5.4.3.3 通过定制各多功能函数接入方法(已支持)

transform-runtime为方法调用提供一个迂回空间——各多功能方法被附着到构造函数上。你能用它们去替换方法调用比如这个:

'c'.repeat(3);

用一个多功能函数接入:

String.repeat('c', 3);

被代码翻译的,代码类似这个(注意行A中的引入内容):

'use strict';

var _repeat = require('babel-runtime/core-js/string/repeat'); // (A)

var _repeat2 = _interopRequireDefault(_repeat);

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

(0, _repeat2.default)('c', 3);
5.4.3.4 Babel的polyfilling是基于core-js的

当你回过头看,所有通过transform-runtime生成的引用从babel-runtime/core-js开始使用模块ID。这是因为Babel的polyfilling是基于[core-js](https://github.com/zloirock/core-js)库的。你能翻阅transform-runtime如果详细遍历各定义并在仓库文件[definitions.js](https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-runtime/src/definitions.js)中链接各属性接入至core-js模块。这是一个摘录:

module.exports = {
	builtins: {
		···
		Set: "set",
		···
	},

	methods: {
		Array: {
			···
			from: "array/from",
			···
		},
		···
		String: {
			···
			repeat: "string/repeat",
			···
		},
		···
	}
};

那意味着transform-runtime提供SetArray.from()String.repeat()以及更多。

5.4.4 core-js:来自模块的标准库

考虑到transform-runtime当你想要调用一个方法需要你接入内置构造函数的属性,直接地用core-js是对那个插件另一种有用的选择。

以一个运行时依赖安装它:

npm install --save core-js

非全局地接入标准库功能的一种途径是通过一个简单的库对象:

import * as core from 'core-js/library';

const mySet = new core.Set([1, 2, 3, 2, 1]);
const myArr = core.Array.from(mySet);
const myStr = core.String.repeat('*', 10);

至于库对象的内容,你在下面两者中有一个选择:

  • core-js/library:ES5,ES6和少量提案特性的polyfills
  • core-js/library/es6:仅ES6的polyfills

另一种非全局接入标准库的方式是独立得去引入各单体:

import _Set from 'core-js/library/fn/set';
import _from from 'core-js/library/fn/array/from';
import _repeat from 'core-js/library/fn/string/repeat';

const mySet = new _Set([1, 2, 3, 2, 1]);
const myArr = _from(mySet);
const myStr = _repeat('*', 10);

5.5 我什么时候去用呢?

对于各库,你一定不要触碰全局变量,这是为什么一切都必须来自各引入:

  • Babel各帮手:babel-plugin-transform-runtimebabel-runtime很好用。
  • 运行时重生器:前一个套餐也通过各引入提供重生器。如果你不用或者代码翻译重生器那么你能关闭babel-plugin-transform-runtime的这个部分。
  • 标准库:我不喜欢babel-plugin-transform-runtime通过各非标准全局方法(比如Array.repeat())使ES6方法(比如Array.prototype.repeat())生效。我会将这个插件的这个部分关闭并直接使用core-js

对于各应用程序,你能使用混合途径:

  • 使用Babel各帮手——如果有必要——通过模块导入的运行时重生器,正如对各库的阐述。
  • 全局安装ES6标准库。而一个全局的polyfill将不作任何改变最终本地地运行得让你写代码。我发现那更重要。
    考虑到重生器已经被照顾到了,你不需要babel-polyfillcore-js就足够了。

多余的各Babel帮手总归会只是一个优化,尤其是对于大基数的代码,因为对于节省空间很有价值。

致谢。感谢Denis Pushkarev(@zloirock)和Paul Klimashkin在这个内容上的反馈。


感谢支持译者翻译

支持译者继续翻译


首页:架设ES6

上一章:配置Babel6

下一章:Babel的宽松模式