当下,每个写 JavaScript 的猿可能都在或多或少地使用 Babel。借助 Babel,我们可以使用最新的 ECMAScript 特性,而不用太关注浏览器支持。Babel 在背后进行了许多复杂的转换,我们要做的,就是写配置文件,告诉 Babel 我们想要什么。下面就来看看一些配置技巧吧。
在 .babelrc
中使用 JS
All Babel API options except the callbacks are allowed (because
.babelrc
files are serialized as JSON5).
Babel 使用 JSON5 解析 .babelrc
,也就是说可以在 .babelrc
中使用宽松的语法,可以添加注释什么的,不过,真的可以像 ESLint 的 .eslintrc.js
直接使用 JS 配置吗?截止目前的最新版本(Babel 6),并不会解析 .babelrc.js
之类的文件,不过可以变通一下。
首先,建一个 .babelrc.js
文件:
const ES = process.env.BABEL_ENV === 'es'
module.exports = {
presets: [
[
'env', { modules: !ES }
],
'react',
'stage-2',
],
};
接下来,再建一个 Babel 认识的 .babelrc
文件:
{
"presets": ["./.babelrc.js"]
}
或者,嫌多一个文件麻烦的话,加在 package.json
里面也没问题:
{
"babel": {
"presets": [
"./.babelrc.js"
]
}
}
通过 JS 编写配置文件,不仅可以给一些参数复杂的插件传递正则、函数等参数,还可以根据环境变量设置不同的参数,产出不同的代码。
减少冗余代码
babel-plugin-transform-runtime
以下面的源代码为例:
class Person {
constructor(options) {
this.options = Object.assign({}, Person.DEAULTS, options);
}
sayHi() {
return `Hi, this is ${this.options.name}`;
}
}
Person.DEAULTS = {
name: 'anonymous',
};
.babelrc
配置为:
{
"presets": [
"es2015"
],
"plugins": ["transform-object-assign"]
}
转换后的代码为:
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Person = function () {
function Person(options) {
_classCallCheck(this, Person);
this.options = _extends({}, Person.DEAULTS, options);
}
_createClass(Person, [{
key: 'sayHi',
value: function sayHi() {
return 'Hi, this is ' + this.options.name;
}
}]);
return Person;
}();
Person.DEAULTS = {
name: 'anonymous'
};
就是说,如果源代码中有 10 个类似的模块,就会有 10 份重复的 _extends
、_createClass
、_classCallCheck
代码分布在各个文件中,太多冗余。通过 babel-plugin-transform-runtime
可以有效解决这一问题。
安装并配置 Runtime transform 插件:
{
"presets": [
"es2015"
],
"plugins": [
"transform-object-assign",
"transform-runtime"
]
}
转换出来的代码会引用公共的模块,干净多了:
'use strict';
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Person = function () {
function Person(options) {
(0, _classCallCheck3.default)(this, Person);
this.options = (0, _extends3.default)({}, Person.DEAULTS, options);
}
(0, _createClass3.default)(Person, [{
key: 'sayHi',
value: function sayHi() {
return 'Hi, this is ' + this.options.name;
}
}]);
return Person;
}();
Person.DEAULTS = {
name: 'anonymous'
};
记得把 babel-runtime
也加到依赖中。如果需进一步定制,可参考官方文档。
生产环境中移除 React PropTypes 定义
React PropTypes 定义可以在开发时帮助我们校验传入的属性,但在构建生产环境代码时,完全可以移除,以减小文件体积,节省宽带。babel-plugin-transform-react-remove-prop-types 就是干这事的,具体参见文档,不再赘述。