如今JavaScript
代碼主要採用ES6
編寫,但並非全部瀏覽器都支持ES6
語法,所以,在其中須要某種轉化機制,也就是將ES6+
語法轉化爲ES5
語法,babel7
能夠幫助咱們作到這件事。
babel-loader
是一個webpack
的加載器,用於將ES6+
轉譯成ES5
,要開始使用babel-loader
,咱們須要安裝一些依賴項,以babel7
爲例,有這麼一些依賴:javascript
下面細說如下這些依賴具備是幹什麼的:
@babel/core
這是babel編譯庫的核心包
@babel/preset-env
這個包是指編譯時會自動按照最新的轉譯規則去編譯,除了這個包外還有一些規則包,好比babel-preset-es2015
(將es6
的javascript
代碼轉化瀏覽器兼容javascript
代碼), babel-preset-es2016
(將es7
的javascript
代碼轉化瀏覽器兼容javascript
代碼), babel-preset-es2017
(將es8
的javascript
代碼轉化瀏覽器兼容javascript
代碼)等。
@babel/polyfill
接下來咱們繼續說babel/polyfill
是個什麼東東。babel
官網上寫了很明確一句話,babel
只負責對語法進行編譯。當咱們寫尖頭函數,babel
會幫你把它編譯成普通函數,這沒有任何問題,可是,好比說咱們代碼裏使用了promise
,babel
打包出來的代碼其實仍是promise
,在低版本瀏覽器裏,promise
並不支持,可是babel
並不會幫你處理,由於這不是語法編譯層面須要作的事情。不轉換新的API
包括,好比Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise
等全局對象。
因而,若是咱們要讓打包出來的代碼能兼容低版本瀏覽器,還要考慮到promise,Set
這樣的新語法低版本瀏覽器不兼容的問題,這時候babel/polyfill
就出場了。你只須要全局安裝一下babel/polyfill
:java
npm install --save-dev @babel/polyfill
而後在項目中使用一下它,你的代碼就不存在剛纔提到的兼容性問題了。node
import '@babel/polyfill'
可是,直接用babel-polyfill
會有一些坑,第一個坑是污染全局環境,好比說低版本瀏覽器沒有Set
,可是babel-polyfill
會在全局變量里加一個Set
。再一個問題是,會形成代碼冗餘,舉個例子,多個模塊用到Promise
,每一個模塊裏都有可能獨立存在一個對Promise
作兼容性的代碼。因此,使用babel-polyfill
能夠解決兼容性問題,但並非最佳方案,因而,出現了babel-plugin-transform-runtime
,使用這個插件,就能夠解決上面的問題了。webpack
@babel/plugin-transform-runtime
爲了避免污染全局對象和內置的對象原型,可是又想體驗使用新鮮語法的快感。就能夠配合使用babel-runtime
和babel-plugin-transform-runtime
。 好比當前運行環境不支持promise
,能夠經過引入babel-runtime/core-js/promise
來獲取promise
, 或者經過babel-plugin-transform-runtime
自動重寫你的promise
。也許有人會奇怪,爲何會有兩個runtime
插件,實際上是有歷史緣由的:剛開始開始只有babel-runtime
插件,可是用起來很不方便,在代碼中直接引入helper
函數,意味着不能共享,形成最終打包出來的文件裏有不少重複的helper
代碼。因此,Babel
又開發了babel-plugin-transform-runtime
,這個模塊會將咱們的代碼重寫,如將Promise
重寫成_Promise
(只是打比方),而後引入_Promise helper
函數。這樣就避免了重複打包代碼和手動引入模塊的痛苦。git
在使用@babel/plugin-transform-runtime
以前須要安裝@babel/runtime
,由於前者依賴後者。es6
用了babel-runtime
就能夠不用 babel-polyfill
了,連接https://babeljs.io/docs/en/babel-plugin-transform-runtime/有說明github
① 安裝依賴web
npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime @babel/polyfill @babel/runtime--save-dev
② 在項目的根目錄中建立名爲 .babelrc 的新文件來配置 Babel:npm
{ "presets": ["@babel/preset-env"], "plugins": ["@babel/plugin-transform-runtime"] }
③ webpack 配置 loader(加載器)promise
module: { rules: [ { test: /\.js$/, // 使用正則來匹配 js 文件 exclude: /node_modules/, // 排除依賴包文件夾 use: { loader: 'babel-loader' // 使用 babel-loader } } ] }
webpack.config.js 最終配置:
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = { entry: './babel7轉義ES6.js', output: { path: path.resolve(__dirname, 'build'), filename: 'bundle.js', publicPath: __dirname + '/build/' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader' } } ] }, plugins: [ new CleanWebpackPlugin() // 會刪除上次構建的文件,而後從新構建 ] }
④ 在 app.js 全局引入 @babel/polyfill 並寫入 ES6 語法,並執行 npm run build 打包
// 測試 ES6 語法是否經過 babel 轉譯 import '@babel/polyfill' const array = [1, 2, 3] const isES6 = () => console.log(...array) isES6() const arr = [new Promise(() => {}), new Promise(() => {})] arr.map(item => { console.log(item) })
全局引入 @babel/polyfill 的這種方式可能會導入代碼中不須要的 polyfill,從而使打包體積更大
更改 .babelrc,只轉譯咱們使用到的
/** * babel配置文件 */ { "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage",// 按需引入 "corejs": "3.3.2" } ] ], "plugins": ["@babel/plugin-transform-runtime"] }
同時,將全局引入這段代碼註釋掉,再次打包
// 全局引入 // import '@babel/polyfill'
參考文章:
https://zhuanlan.zhihu.com/p/35378233
http://www.javashuo.com/article/p-ambqyqxk-ev.html
https://www.jianshu.com/p/7bc7b0fadfc2
https://github.com/SunshowerC/blog/issues/4