官方解釋,是下一代JavaScript 語法的編譯器。javascript
既然是下一代Javascript的標準,瀏覽器因版本的不一樣對此會有兼容性問題,JavaScript的新的方法都不能使用,可是目前咱們在項目開發一直提倡使用最新的語法糖編寫,不但能減小代碼量,並且async,await等新特性還解決了回調的編寫機制,減輕了代碼維護成本。vue
Babel就所以而生,它可讓你放心使用大部分的JavaScript的新的標準的方法,而後編譯成兼容絕大多數的主流瀏覽器的代碼。在項目工程腳手架中,通常會使用.babelrc文件,經過配置一些參數配合webpack進行打包壓縮。也經過網上了解,寫法各有不一樣,參數也大不相同,所以,我從新整理一份資料,詳細的介紹下各個配置項的意義所在,以便清晰瞭解若是使用。java
如下配置主要正對webpack3+寫法。node
在.babelrc配置文件中,主要是對預設(presets)和插件(plugins)進行配置,所以不一樣的轉譯器做用不一樣的配置項,大體可分爲如下三項:react
1.語法轉義器。主要對javascript最新的語法糖進行編譯,並不負責轉譯javascript新增的api和全局對象。例如let/const就能夠被編譯,而includes/Object.assign等並不能被編譯。經常使用到的轉譯器包有,babel-preset-env、babel-preset-es201五、babel-preset-es201六、babel-preset-es201七、babel-preset-latest等。在實際開發中能夠只選用babel-preset-env來代替餘下的,可是還須要配上javascirpt的製做規範一塊兒使用,同時也是官方推薦jquery
{
"presets": ["env", {
"modules": false
}],
"stage-2"
}
複製代碼
2.補丁轉義器。主要負責轉譯javascript新增的api和全局對象,例如babel-plugin-transform-runtime這個插件可以編譯Object.assign,同時也能夠引入babel-polyfill進一步對includes這類用法保證在瀏覽器的兼容性。Object.assign 會被編譯成如下代碼:webpack
__WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default()
複製代碼
3.jsx和flow插件,這類轉譯器用來轉譯JSX語法和移除類型聲明的,使用Rect的時候你將用到它,轉譯器名稱爲babel-preset-reactgit
主要經過npm安裝babel-preset-xx插件來配合使用,例如經過 npm install babel-preset-stage-2 babel-preset-env --save-dev 安裝,會有相應以下配置。es6
{
"presets": [
["env", options],
"stage-2"
]
}
複製代碼
babel主要提供如下幾種轉義器包,括號裏面是對應配置文件的配置項github
babel-preset-stage-0(stage-0)
babel-preset-stage-1(stage-1)
babel-preset-stage-2(stage-2)
babel-preset-stage-3(stage-3)
複製代碼
不一樣階段的轉譯器之間是包含的關係,preset-stage-0轉譯器除了包含了preset-stage-1的全部功能還增長了transform-do-expressions插件和transform-function-bind插件,一樣preset-stage-1轉譯器除了包含preset-stage-2的所有功能外還增長了一些額外的功能。
官方推薦使用babel-preset-env來替代一些插件包的安裝(es2015-arrow-functions,es2015-block-scoped-functions等等),而且有以下幾種配置信息,介紹幾個經常使用的,
更多配置能夠參考官網https://babeljs.io/docs/plugins/preset-env/
{
"targets": {
"chrome": 52,
"browsers": ["last 2 versions", "safari 7"],
"node":"6.10"
}
"modules": false
}
複製代碼
targets能夠制定兼容瀏覽器版本,若是設置了browsers,那麼就會覆蓋targets本來對瀏覽器的限制配置。
targets.node正對node版本進行編譯
modules一般都會設置爲false,由於默認都是支持CommonJS規範,同時還有其餘配置參數:"amd" | "umd" | "systemjs" | "commonjs",systemjs我還不知道規範寫法是什麼,amd和umd以及commonjs相對比較熟悉,下面簡要列舉下書寫規範。
amd代碼規範,在ng1中會用到比較多,主要用於依賴注入:
define(['jquery'], function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
})
複製代碼
commonjs規範,也是node環境中尊崇的一種規範:
var $ = require('jquery');
// 方法
function myFunc(){};
// 暴露公共方法(一個)
module.exports = myFunc;
{% endcodeblock %}
>umd規範,兼容amd以及commonjs規範,目前在第三方插件編寫使用比較多:
{% codeblock lang:javascript %}
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之類的
module.exports = factory(require('jquery'));
} else {
// 瀏覽器全局變量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
}));
複製代碼
插件配置項同預設配置項同樣,須要搭配babel相應的插件進行配置,能夠選擇配置插件來知足單個需求,例如早期咱們會有以下配置:
{
"plugins": [
"check-es2015-constants",
"es2015-arrow-functions",
"es2015-block-scoped-functions",
// ...
]
}
複製代碼
可是這些插件從維護到書寫極爲麻煩,後來官方統一推薦使用env,所有替代了這些單一的插件功能,能夠簡化配置以下,也就是我前面提到了babel-preset-env:
{
"presets": [
"es2015"
]
}
複製代碼
這裏主要介紹兩款經常使用插件,分別是babel-plugin-transform-runtime,babel-plugin-syntax-dynamic-import。
基本配置代碼以下:
{
"plugins": [
"syntax-dynamic-import",["transform-runtime"]
]
}
複製代碼
爲了解決這種全局對象或者全局對象方法編譯不足的狀況,纔出現了transform-runtime這個插件,可是它只會對es6的語法進行轉換,而不會對新api進行轉換。若是須要轉換新api,也能夠經過使用babel-polyfill來規避兼容性問題。
對Object.assign進行編譯,配置與未配置通過webpack編譯後的代碼片斷以下:
// 未設置代碼片斷:
__webpack_require__("ez/6");
var aaa = 1;
function fna() {
var dd = 33333;
var cc = Object.assign({ key: 2 });
var xx = String.prototype.repeat.call('b', 3);
if ("foobar".String.prototype.includes("foo")) {
var vv = 1;
}
return dd;
}
複製代碼
// 設置代碼片斷:
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign__);
__webpack_require__("ez/6");
var aaa = 1;
function fna() {
var dd = 33333;
var cc = __WEBPACK_IMPORTED_MODULE_1_babel_runtime_core_js_object_assign___default()({ key: 2 });
var xx = String.prototype.repeat.call('b', 3);
if ("foobar".String.prototype.includes("foo")) {
var vv = 1;
}
return dd;
}
複製代碼
對class定義類會進行編譯,配置與未配置通過webpack編譯後的代碼片斷以下:
// 未設置代碼片斷:
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Canvas = function Canvas(height, width) {
_classCallCheck(this, Canvas);
this.height = height;
this.width = width;
};
var Canvas2 = function Canvas2(height, width) {
_classCallCheck(this, Canvas2);
this.height = height;
this.width = width;
};
複製代碼
// 設置代碼片斷:
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck__);
var Canvas = function Canvas(height, width) {
__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, Canvas);
this.height = height;
this.width = width;
};
var Canvas2 = function Canvas2(height, width) {
__WEBPACK_IMPORTED_MODULE_0_babel_runtime_helpers_classCallCheck___default()(this, Canvas2);
this.height = height;
this.width = width;
};
複製代碼
對Generator函數也有同上的編譯效果,目前項目中使用該函數較小,通常使用promise替代,以及async await因此未對該函數作測試。
官方說對promise也會產生編譯,可是實際測試結果卻沒有效果
通過webpack打包最終測試,引入transform-runtime該配置項後,打包入口js文件大小會略微增大,並不像官方說的可以縮小文件體積
未配置的最終打包效果:
配置後的最終打包效果:
雖然文件大小會有所增大,可是解決一些兼容性的問題,同時,從以上給出的測試代碼例子來看,使用transform-runtime後,能夠減小內部全局函數的定義,從結構上看尊崇了webpack的模塊化思想,因此仍是建議使用該插件。
這個插件主要解決動態引入模塊的問題
function nDate() {
import('moment').then(function(moment) {
console.log(moment.default().format());
}).catch(function(err) {
console.log('Failed to load moment', err);
});
}
nDate();
複製代碼
若是.babelrc配置項中使用了"stage-2",也能夠不實用該插件,一樣支持動態模塊引入。
否則就會報如下錯誤:
Module build failed: SyntaxError: 'import' and 'export' may only appear at the top level, or (import 和 export只能在最外層,也就是不能用在函數或者塊中)
Module build failed: SyntaxError: Unexpected token, expected {
主要做用就是能夠指定不編譯那些代碼
{
"ignore":["./module/a.js"]
}
複製代碼
let,Object.assign,class定義都未編譯,編譯效果以下:
__webpack_require__("ez/6");
const aaa = 1;
function fna () {
let dd = 33333
let cc = Object.assign({key:2})
let xx = String.prototype.repeat.call('b', 3)
if ("foobar".String.prototype.includes("foo")) {
let vv = 1
}
return dd
}
function fna2 () {
return fna() + aaa + __WEBPACK_IMPORTED_MODULE_0__b__["a" /* default */]
}
class Canvas {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class Canvas2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
複製代碼
主要設置編譯後是不是壓縮,boolean類型,若是使用babel-cli進行打包編譯文件這個配置項可以起到做用,可是目前大部分仍是會依賴第三方打包工具,例如webpack,因此這個配置參數通常不用設置,webpack插件中的UglifyJsPlugin作了壓縮的工做。
在生成的文件中,不產生註釋,boolean類型,webpack插件中的UglifyJsPlugin也一樣集成了這個功能。
基本配置以下:
{
"env": {
// test 是提早設置的環境變量,若是沒有設置BABEL_ENV則使用NODE_ENV,若是都沒有設置默認就是development
"test": {
"presets": ["env", "stage-2"],
// instanbul是一個用來測試轉碼後代碼的工具
"plugins": ["istanbul"]
}
}
}
複製代碼
Babel默認只轉換新的JavaScript語法,而不轉換新的API,好比Iterator、Generator、Set、Maps、Promise等等全局對象,以及一些定義在全局對象上的方法(好比Object.assign)都不會轉碼,具體的能夠參考babel-plugin-transform-runtime模塊的definitions.js文件。
這裏主要涉及到babel編譯後依然會存在瀏覽器兼容性問題,通常會使用transform-runtime和babel-polyfill配合使用,對於後者只須要在項目入口文件require引入便可。
固然在使用相似Object.assign函數功能時,可使用lodash庫來替代,promise可使用Q.js替代等等方案,這樣依賴能夠不須要引入以上插件,具體能夠根據項目具體安排
.babelrc配置文件主要仍是以presets和plugins組成,經過和webpack配合進行使用,分享下咱們在項目中經常使用的配置。以上都是經過學習總結出來的,有什麼不對的地方但願指出。
vue項目開發使用的配置以下:
{
"presets": [
["env", {
"modules": false
}],
"stage-2"
],
// 下面指的是在生成的文件中,不產生註釋
"comments": false,
"plugins": ["transform-runtime","syntax-dynamic-import"],
"env": {
// test 是提早設置的環境變量,若是沒有設置BABEL_ENV則使用NODE_ENV,若是都沒有設置默認就是development
"test": {
"presets": ["env", "stage-2"],
// instanbul是一個用來測試轉碼後代碼的工具
"plugins": ["istanbul"]
}
}
}
複製代碼
react項目開發使用的配置以下:
{
"presets": [
["env", { "modules": false }],
"stage-2",
"react"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
複製代碼
stage-3包括如下插件:
transform-async-to-generator 支持async/await
transform-exponentiation-operator 支持冪運算符語法糖
stage-2包括stage-3的全部插件,額外還包括如下插件:
syntax-trailing-function-commas 支持尾逗號函數,額...很雞肋
transform-object-reset-spread 支持對象的解構賦值
stage-1包括stage-2全部插件,額外還包括如下插件:
transform-class-constructor-call 支持class的構造函數
transform-class-properties 支持class的static屬性
transform-decorators 支持es7的裝飾者模式即@,這實際上是頗有用的特性,對於HOC來講這是一個不錯的語法糖
transform-export-extensions 支持export方法
stage-0包括stage-1全部插件,額外還包括如下插件:
transform-do-expressions 支持在jsx中書寫if/else
transform-function-bind 支持::操做符來切換上下文,相似於es5的bind
感謝@丹哥一號同窗提出問題,通過測試當使用webpack版本4.20.2及以上的時候(4以上的其餘版本暫時沒測),不須要這個插件,同時也不須要stage-2的配置,一樣能夠支持import以及動態import,基本用法根參考如下示例:
function nDate() {
import('moment').then(function(moment) {
console.log(moment.default().format());
}).catch(function(err) {
console.log('Failed to load moment', err);
});
}
nDate();
複製代碼