深入理解babel之配置文件

一:理解 babel之配置文件.babelrc 基本配置項

1. 什么是babel? 它是干什么用的助赞?

ES6是2015年發(fā)布的下一代javascript語言標(biāo)準(zhǔn)康谆,它引入了新的語法和API,使我們編寫js代碼更加得心應(yīng)手映九,比如class梦湘,let,for...of promise等等這樣的,但是可惜的是這些js新特性只被最新版本的瀏覽器支持件甥,但是低版本瀏覽器并不支持捌议,那么低版本瀏覽器下就需要一個轉(zhuǎn)換工具,把es6代碼轉(zhuǎn)換成瀏覽器能識別的代碼引有,babel就是這樣的一個工具瓣颅。可以理解為 babel是javascript語法的編譯器譬正。

2. Babel編譯器
在Babel執(zhí)行編譯的過程中宫补,會從項目的根目錄下的 .babelrc文件中讀取配置。.babelrc是一個json格式的文件曾我。
在.babelrc配置文件中粉怕,主要是對預(yù)設(shè)(presets) 和 插件(plugins) 進(jìn)行配置。.babelrc配置文件一般為如下:

{
  "plugins": [
     [
      "transform-runtime",
      {
        "polyfill": false
      }
     ]
   ],
   "presets": [
     [
       "env",
       {
         "modules": false
       }
     ],
     "stage-2",
     "react"
  ]
}

2.1 plugins
該屬性是告訴babel要使用那些插件抒巢,這些插件可以控制如何轉(zhuǎn)換代碼贫贝。

1. 理解 babel-polyfill 和 babel-runtime 及 babel-plugin-transform-runtime

Babel默認(rèn)只轉(zhuǎn)換新的javascript語法,而不轉(zhuǎn)換新的API蛉谜,比如 Iterator, Generator, Set, Maps, Proxy, Reflect,Symbol,Promise 等全局對象稚晚。以及一些在全局對象上的方法(比如 Object.assign)都不會轉(zhuǎn)碼。
比如說型诚,ES6在Array對象上新增了Array.form方法客燕,Babel就不會轉(zhuǎn)碼這個方法,如果想讓這個方法運(yùn)行狰贯,必須使用 babel-polyfill來轉(zhuǎn)換等也搓。

因此:babel-polyfill和babel-runtime就是為了解決新的API與這種全局對象或全局對象方法不足的問題,因此可以使用這兩個插件可以轉(zhuǎn)換的暮现。

那么他們兩者的區(qū)別是什么还绘?
babel-polyfill 的原理是當(dāng)運(yùn)行環(huán)境中并沒有實(shí)現(xiàn)的一些方法,babel-polyfill會做兼容栖袋。
babel-runtime 它是將es6編譯成es5去執(zhí)行拍顷。我們使用es6的語法來編寫,最終會通過babel-runtime編譯成es5.也就是說塘幅,不管瀏覽器是否支持ES6昔案,只要是ES6的語法尿贫,它都會進(jìn)行轉(zhuǎn)碼成ES5.所以就有很多冗余的代碼。

babel-polyfill 它是通過向全局對象和內(nèi)置對象的prototype上添加方法來實(shí)現(xiàn)的踏揣。比如運(yùn)行環(huán)境中不支持Array.prototype.find 方法庆亡,引入polyfill, 我們就可以使用es6方法來編寫了,但是缺點(diǎn)就是會造成全局空間污染捞稿。

babel-runtime: 它不會污染全局對象和內(nèi)置對象的原型又谋,比如說我們需要Promise,我們只需要import Promise from 'babel-runtime/core-js/promise'即可娱局,這樣不僅避免污染全局對象彰亥,而且可以減少不必要的代碼。

雖然 babel-runtime 可以解決 babel-polyfill中的避免污染全局對象衰齐,但是它自己也有缺點(diǎn)的任斋,比如上,如果我現(xiàn)在有100個文件甚至更多的話耻涛,難道我們需要一個個文件加import Promise from 'babel-runtime/core-js/promise' 嗎废酷?那這樣肯定是不行的,因此這個時候出來一個 叫 babel-plugin-transform-runtime抹缕,
它就可以幫助我們?nèi)ケ苊馐謩右?import的痛苦澈蟆,并且它還做了公用方法的抽離。比如說我們有100個模塊都使用promise卓研,但是promise的polyfill僅僅存在1份丰介。
這就是 babel-plugin-transform-runtime 插件的作用。

2. 理解 babel-plugin-transform-runtime 的配置一些選項

因此通過上面的理解鉴分,我們可以對 transform-runtime 通過如下配置 plugins; 如下代碼:

{
  'plugins': [
    [
      'transform-runtime', 
      {
        'helpers': false,
        'polyfill': false,
        'regenerator': true,
        'moduleName': 'babel-runtime'
      }
    ]
  ]
}

helpers: 默認(rèn)值為true,表示是否開啟內(nèi)聯(lián)的babel helpers(即babel或者環(huán)境本來存在的某些對象方法函數(shù))如:extends带膀,etc這樣的
在調(diào)用模塊名字時將被替換名字志珍。

polyfill:默認(rèn)值為true,表示是否把內(nèi)置的東西(Promise, Set, Map)等轉(zhuǎn)換成非全局污染的垛叨。

regenerator:默認(rèn)值為true伦糯,是否開啟generator函數(shù)轉(zhuǎn)換成使用regenerator runtime來避免污染全局域。

moduleName:默認(rèn)值為 babel-runtime嗽元,當(dāng)調(diào)用輔助 設(shè)置模塊(module)名字/路徑.
比如如下這樣設(shè)置:

{
  "moduleName": "flavortown/runtime"
}

import引入文件如下這個樣子:

import extends from 'flavortown/runtime/helpers/extends';

3 presets
presets屬性告訴Babel要轉(zhuǎn)換的源碼使用了哪些新的語法特性敛纲,presets是一組Plugins的集合。

3.1 理解 babel-preset-env

比如:

babel-preset-es2015: 可以將es6的代碼編譯成es5.
babel-preset-es2016: 可以將es7的代碼編譯為es6.
babel-preset-es2017: 可以將es8的代碼編譯為es7.
babel-preset-latest: 支持現(xiàn)有所有ECMAScript版本的新特性剂癌。

舉個列子淤翔,比如我們需要轉(zhuǎn)換es6語法,我們可以在 .babelrc的plugins中按需引入一下插件佩谷,比如:
check-es2015-constants旁壮、es2015-arrow-functions监嗜、es2015-block-scoped-functions等等幾十個不同作用的plugin:
那么配置項可能是如下方式:

// .babelrc
{
  "plugins": [
    "check-es2015-constants",
    "es2015-arrow-functions",
    "es2015-block-scoped-functions",
    // ...
  ]
}

但是Babel團(tuán)隊為了方便,將同屬ES2015的幾十個Transform Plugins集合到babel-preset-es2015一個Preset中抡谐,這樣我們只需要在.babelrc的presets加入es2015一個配置就可以完成全部ES2015語法的支持了:
如下配置:

// .babelrc
{
  "presets": [
    "es2015"
  ]
}

但是我們隨著時間的推移裁奇,將來可能會有跟多的版本插件,比如 bebel-preset-es2018,.... 等等。
因此 babel-preset-env 出現(xiàn)了麦撵,它的功能類似于 babel-preset-latest刽肠,它會根據(jù)目標(biāo)環(huán)境選擇不支持的新特性來轉(zhuǎn)譯。

首先需要在項目中安裝免胃,如下命令:

npm install babel-preset-env --save-dev

在.babelrc配置文件中 可以如下簡單的配置:

{
  "presets": ['env']
}

我們還可以僅僅配置項目所支持的瀏覽器的配置

1. 支持每個瀏覽器最后兩個版本和safari大于等于7版本所需的polyfill代碼轉(zhuǎn)換音五,我們可以如下配置:

{
  'presets': [
    ['env', {
      'target': {
        'browsers': ['last 2 versions', 'safari >= 7']
      }
    }]
  ]
}

2. 支持市場份額超過5%的瀏覽器,可以如下配置:

{
  'presets': [
    ['env', {
      'target': {
        'browsers': '> 5%'
      }
    }]
  ]
}

3. 指定瀏覽器版本杜秸,可以如下配置:

{
  'presets': [
    ['env', {
      'target': {
        'chrome': 56
      }
    }]
  ]
}

Node.js
如果通過Babel編譯Node.js代碼的話放仗,可以設(shè)置 "target.node" 是 'current', 含義是 支持的是當(dāng)前運(yùn)行版本的nodejs。
如下配置代碼:

{
  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
    }]
  ]
}

理解 babel-preset-env 中的選項配置:
1. targets: {[string]: number | string }, 默認(rèn)為{};
含義是支持一個運(yùn)行環(huán)境的對象撬碟,比如支持node版本诞挨;可以如下配置: node: '6.0';
運(yùn)行環(huán)境: chrome, opera, edge, firefox, safari, ie, ios, android, node, electron

2. targets.browsers <Array | string>
支持瀏覽器的配置項,該配置項使用方式可以到 browserslist來查詢(https://github.com/browserslist/browserslist)
比如上面的 支持每個瀏覽器最后兩個版本和safari大于等于7版本呢蛤。如上配置惶傻。

3. modules
該參數(shù)的含義是:啟用將ES6模塊語法轉(zhuǎn)換為另一種模塊類型。將該設(shè)置為false就不會轉(zhuǎn)換模塊其障。默認(rèn)為 'commonjs'.
該值可以有如下:
'amd' | 'umd' | 'systemjs' | 'commonjs' | false

我們在項目中一般會看到如下配置银室,設(shè)置modules: false, 如下代碼配置:

"presets": [
   'env',
   {
     'modules': false
   }
]

這樣做的目的是:以前我們需要使用babel來將ES6的模塊語法轉(zhuǎn)換為AMD, CommonJS,UMD之類的模塊化標(biāo)準(zhǔn)語法励翼,但是現(xiàn)在webpack都幫我做了這件事了蜈敢,所以我們不需要babel來做,因此需要在babel配置項中設(shè)置modules為false汽抚,因為它默認(rèn)值是commonjs, 否則的話抓狭,會產(chǎn)生沖突。

4. loose, 該參數(shù)值默認(rèn)為false造烁。
含義是:允許它們?yōu)檫@個 preset 的任何插件啟用”loose” 轉(zhuǎn)換否过。

5. include: 包含一些插件,默認(rèn)為 [];
比如包含箭頭函數(shù)惭蟋,可以如下配置:

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      },
      "include": ["transform-es2015-arrow-functions", "es6.map"]
    }]
  ]
}

6. exclude苗桂; 排除哪些插件,默認(rèn)為 [];
比如 排除生成器告组,可以如下配置:

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      },
      "exclude": ["transform-regenerator", "es6.set"]
    }]
  ]
}

3.2 理解 babel-presets-stage-x
官方預(yù)設(shè)(preset), 有兩種煤伟,一個是按年份(babel-preset-es2017),一個是按階段(babel-preset-stage-0)。 這主要是根據(jù)TC39 委員會ECMASCRPIT 發(fā)布流程來制定的持偏。因此到目前為止 有4個不同的階段預(yù)設(shè):

babel-preset-stage-0

babel-preset-stage-1

babel-preset-stage-2

babel-preset-stage-3

以上每種預(yù)設(shè)都依賴于緊隨的后期階段預(yù)設(shè)驼卖,數(shù)字越小,階段越靠后鸿秆,存在依賴關(guān)系酌畜。也就是說stage-0是包括stage-1的,以此類推卿叽。因此 stage-0包含stage-1/2/3的內(nèi)容桥胞。所以如果我們不知道需要哪個stage-x的話,直接引入stage-0就好了考婴。

stage0 (https://babeljs.io/docs/en/babel-preset-stage-0) 只是一個美好激進(jìn)的想法贩虾,一些 Babel 插件實(shí)現(xiàn)了對這些特性的支持 ,但是不確定是否會被定為標(biāo)準(zhǔn).

stage1 (https://babeljs.io/docs/en/babel-preset-stage-1) 值得被納入標(biāo)準(zhǔn)的特性.

stage2 (https://babeljs.io/docs/en/babel-preset-stage-2) 該特性規(guī)范己經(jīng)被起草沥阱,將會被納入標(biāo)準(zhǔn)里.

stage3 (https://babeljs.io/docs/en/babel-preset-stage-3) 該特性規(guī)范已經(jīng)定稿缎罢,大瀏覽器廠商和 Node.js 社區(qū)己開始著手實(shí)現(xiàn).

但是在我們使用的時候只需要安裝你想要的階段就可以了:比如 babel-preset-stage-2, 安裝命令如下:

npm install --save-dev babel-preset-stage-2

二:在webpack中配置babel

在上面了解了babel后考杉,現(xiàn)在我們需要知道如何在webpack中使用它了策精。由于babel所做的事情是轉(zhuǎn)換代碼,所有需要使用loader去轉(zhuǎn)換崇棠,因此我們需要配置babel-loader咽袜。

在安裝babel-loader之前,我們需要安裝babel-core枕稀, 因為babel-core是Babel編譯器的核心询刹,因此也就意味著如果我們需要使用babel-loader進(jìn)行es6轉(zhuǎn)碼的話,我們首先需要安裝 babel-core, 安裝命令如下即可:

npm install --save-dev babel-core

然后我們再安裝 babel-loader, 命令如下:

npm install --save-dev babel-loader

接著我們需要安裝 babel-preset-env, babel-plugin-transform-runtime, babel-preset-stage-2, 如下命令安裝

npm install --save-dev  babel-preset-env babel-plugin-transform-runtime babel-preset-stage-2

因此 .babelrc 配置如下即可:

{
  "plugins": [
     [
      "transform-runtime",
      {
        "polyfill": false
      }
     ]
   ],
   "presets": [
     [
       "env",
       {
         "modules": false
       }
     ],
     "stage-2"
  ]
}

在做demo之前萎坷,我們還是先看下目錄結(jié)構(gòu)變成如下:

### 目錄結(jié)構(gòu)如下:
demo1                                       # 工程名
|   |--- dist                               # 打包后生成的目錄文件             
|   |--- node_modules                       # 所有的依賴包
|   |--- js                                 # 存放所有js文件
|   | |-- demo1.js  
|   | |-- main.js                           # js入口文件
|   |
|   |--- webpack.config.js                  # webpack配置文件
|   |--- index.html                         # html文件
|   |--- styles                             # 存放所有的css樣式文件                              
|   |--- .gitignore  
|   |--- README.md
|   |--- package.json
|   |--- .babelrc                           # babel轉(zhuǎn)碼文件

因此webpack配置中需要添加 babel-loader 配置凹联,如下配置:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules)/, // 排除文件
        loader: 'babel-loader'
      }
    ]
  }
}

webpack 所有配置如下代碼

const path = require('path');
// 提取css的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ClearWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: './js/main.js',
  output: {
    filename: 'bundle.js',
    // 將輸出的文件都放在dist目錄下
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/dist'
  },
  mode: 'development',
  module: {
    rules: [
      {
        // 使用正則去匹配要用該loader轉(zhuǎn)換的css文件
        test: /\.css$/,
        loaders: ExtractTextPlugin.extract({
          // 轉(zhuǎn)換 .css文件需要使用的Loader
          use: ['css-loader']
        })
      },
      {
        test: /\.(png|jpg)$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[ext]'
        }
      },
      {
        test: /\.js$/,
        exclude: /(node_modules)/, // 排除文件
        loader: 'babel-loader'
      }
    ]
  },
  resolve: {
    // modules: ['plugin', 'js']
  },
  externals: {
    jquery: 'jQuery'
  },
  devtool: 'source-map',
  plugins: [
    // new ClearWebpackPlugin(['dist']),
    new ExtractTextPlugin({
      // 從js文件中提取出來的 .css文件的名稱
      filename: `main.css`
    })
  ]
};

package.json 安裝依賴包如下:

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --progress --colors --devtool source-map --hot --inline",
    "build": "webpack --progress --colors"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "babel-preset-stage-2": "^6.24.1",
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^1.0.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^1.1.11",
    "path": "^0.12.7",
    "style-loader": "^0.21.0",
    "uglifyjs-webpack-plugin": "^1.2.7",
    "url-loader": "^1.0.1",
    "webpack": "^4.16.1",
    "webpack-cli": "^3.0.8",
    "webpack-dev-server": "^3.1.4"
  },
  "dependencies": {
    "axios": "^0.18.0",
    "jquery": "^3.3.1"
  }
}

現(xiàn)在我們繼續(xù)在 main.js 代碼內(nèi) 編寫 Generator 函數(shù),代碼如下:

function* g() {
  yield 'a';
  yield 'b';
  yield 'c';
  return 'ending';
}

var gen = g();
console.log(gen.next()); // 返回Object {value: "a", done: false}

for(let a of [1,2,3,4]) {
  console.log(a); // 打印出 1, 2, 3, 4
}

然后重新運(yùn)行打包命令 npm run dev 后哆档,打開瀏覽器運(yùn)行 可以看到控制臺輸出 {value: "a", done: false}匕垫,說明babel已經(jīng)轉(zhuǎn)譯了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虐呻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子寞秃,更是在濱河造成了極大的恐慌斟叼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件春寿,死亡現(xiàn)場離奇詭異朗涩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)绑改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門谢床,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兄一,“玉大人,你說我怎么就攤上這事识腿〕龈铮” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵渡讼,是天一觀的道長骂束。 經(jīng)常有香客問我,道長成箫,這世上最難降的妖魔是什么展箱? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蹬昌,結(jié)果婚禮上混驰,老公的妹妹穿的比我還像新娘。我一直安慰自己皂贩,他們只是感情好栖榨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著先紫,像睡著了一般治泥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遮精,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天居夹,我揣著相機(jī)與錄音,去河邊找鬼本冲。 笑死准脂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的檬洞。 我是一名探鬼主播狸膏,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼添怔!你這毒婦竟也來了湾戳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤广料,失蹤者是張志新(化名)和其女友劉穎砾脑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艾杏,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韧衣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畅铭。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡氏淑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出硕噩,到底是詐尸還是另有隱情假残,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布榴徐,位于F島的核電站守问,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏坑资。R本人自食惡果不足惜耗帕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望袱贮。 院中可真熱鬧仿便,春花似錦、人聲如沸攒巍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柒莉。三九已至闻坚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間兢孝,已是汗流浹背窿凤。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跨蟹,地道東北人雳殊。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像窗轩,于是被迫代替她去往敵國和親夯秃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容