一、@babel/core與babel-core區別html
@babel/core是babel 7事後的版本標識,babel-core是之前版本的標識。node
二、.babelrc和babel.config.jswebpack
.babelrc和babel.config.js均是babel的配置文件,babel.config.js是bebel 7引入的新的方式。git
三、@babel/polyfill和@babel/plugin-transform-runtime和@babel/runtime和@babel/runtime-corejs2(都是用來轉換新Api的)es6
//使用方法一在entry中添加
module.exports = {
entry: {
main: ["@babel/polyfill", path.resolve(__dirname, "./src/index.js")]
}
}
//使用方式二babel.config.js中設置
module.exports = {
presets: [
"@babel/preset-env", { "useBuiltIns": true }
]
}
複製代碼
module.exports = {
preset: ["@babel/preset-env"],
plugins: [
"@babel/plugin-transform-runtime", { corejs: 2 }
]
}
複製代碼
一、corejs 是一個給低版本的瀏覽器提供接口的庫,如 Promise, map, set 等。在 babel 中你設置成 false 或者不設置,就是引入的是 corejs 中的庫,並且在全局中引入,也就是說侵入了全局的變量。github
二、若是你的全局有一個引入,不要讓引入的庫影響全局,那你就須要引把 corejs 設置成 2。 因此一旦你使用了2這個參數就必須引入@babel/runtime-corejs2web
三、@babel/plugin-transform-runtime是必須裝的,若是corejs設置爲2的話安裝@babel/runtime-corejs2來代替@babel/runtime,反正設置爲false的話就須要@babel/runtime,根據你的設置來安裝便可。npm
四、因此@babel/runtime和@babel/runtime-corejs2區別就是後面那個多了個corejs2的包。與@babel/runtime區別,官網是這樣描述的
Difference from @babel/runtime:This can be used instead of a polyfill for any non-instance methods. It will replace things like Promise or Symbol with the library functions in core-js
json
在babel 7下:segmentfault
默認狀況下.babelrc不做用於子包,那麼在babel.config.js下加入一下babelrcRoots來指定便可。
module.exports = {
babelrcRoots: ['.', './frontend', './backend'] // 容許這兩個子 package 加載 babelrc 相對配置
}
複製代碼
一文讀懂 babel7 的配置文件加載邏輯
對babel-transform-runtime,babel-polyfill的一些理解
babel7中 corejs 和 corejs2 的區別
babel preset env配置
babel學習筆記
首先須要本機安裝node.js,使用npm包管理工具來初始化目錄,本次操做學習都是在Babel 7上進行的,相較於Babel 6仍是有必定區別,單獨使用Babel 7須要CLI來完成,因此先安裝腳手架和核心@babel/core。
npm install @babel/cli @babel/core
複製代碼
安裝完成後,咱們就可使用cli提供的命令來轉換咱們的JS代碼了,好比創建一個test.js的JS文件,裏面包含ES6的內容:
let a = [1, 2, 3];
let b = () => {
console.log('這是箭頭函數!');
}
let c = [...a];
複製代碼
而後來一波命令:
npx babel test.js --watch --out-file test-transform.js
複製代碼
- 注意:npx是npm在5.2.0後附贈的東西,使用這個咱們能夠避免全局安裝這些命令工具,具體你們能夠百度。
- 個人test.js是直接建在跟package.json同級目錄下的。 以後咱們能夠發現輸出的test-transform.js沒改變,沒有轉化,這是由於babel是基於插件來實現的,沒配置插件確定什麼也不會幹,因此須要配置,這裏就不介紹單獨手動引入插件的方式了。
// 轉換前
let a = [1, 2, 3];
let b = () => {
console.log('這是箭頭函數!');
}
let c = [...a];
// 轉換後
let a = [1, 2, 3];
let b = () => {
console.log('這是箭頭函數!');
}
let c = [...a];
複製代碼
不想每次須要什麼插件都去手動引入插件,因此咱們就須要祭出@babel/preset-env,先安裝這個工具。
npm intasll @babel/preset-env
複製代碼
而後在根目錄建一個babel.config.js來配置babel,在文件中加入如下內容:
module.exports = {
presets: [
["@babel/preset-env"]
]
}
複製代碼
以後咱們再運行一次上面的轉換命令,能夠獲得如下代碼:
"use strict";
var a = [1, 2, 3];
var b = function b() {
console.log('這是箭頭函數!');
};
var c = [].concat(a);
複製代碼
這樣ES6新的語法糖就轉換成ES5了。 固然,babel.config.js裏面還能夠指定目標,當知足什麼樣的條件纔去轉換語法,不指定targets的狀況下,默認是把全部的ES6+都轉換成ES5,好比下面的示例:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8"
}]
]
}
複製代碼
這種只有當在大於ie 8以上的瀏覽器不支持的語法纔會轉換。
babel只能轉換通常的語法糖,不能轉換新的API,因此就只能祭出polyfill來彌補。首先安裝下polyfill,而後引入就能夠了。
npm install @babel/polyfill
複製代碼
而後在JS文件裏面引入
import "@babel/polyfill";
複製代碼
對於使用webpack的同窗,能夠直接在main入口直接引入,打包事後直接可使用,以下:
entry: {
main: ["@babel/polyfill", path.resolve(__dirname, "../main.js")]
}
複製代碼
- 注意:這個地方我只是舉個栗子,實際上你這樣單獨操做出來的JS再直接引入某個HTML文件裏面實際上是沒有用的,要結合到打包工具一塊兒使用才行,好比Webpack。
上面的引入方法是徹底引入,致使包很是大,咱們能夠按需引入,這裏又要配置@babel/preset-env,修改babel.config.js代碼以下:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8",
"useBulitIns": "entry"
}]
]
}
複製代碼
而後運行一下會看到這些代碼:
"use strict";
require("core-js/modules/es6.array.copy-within");
require("core-js/modules/es6.array.every");
require("core-js/modules/es6.array.fill");
..........
require("core-js/modules/web.timers");
require("core-js/modules/web.immediate");
require("core-js/modules/web.dom.iterable");
require("regenerator-runtime/runtime");
var a = [1, 2, 3];
var b = function b() {
console.log('這是箭頭函數!');
};
var c = [].concat(a);
b();
var d = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("ok");
}, 2000);
});
d.then(function (res) {
console.log(res);
});
複製代碼
它會一股腦的把全部的包所有引進來,這樣嘿不科學,因此usage參數能夠作到按需引入,它只會引入相關的包,沒使用的ES6+API不會引入相關的包,修改babel.config.js代碼:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8",
"useBuiltIns": "usage"
}]
]
}
複製代碼
轉換事後的代碼以下:
"use strict";
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
var a = [1, 2, 3];
var b = function b() {
console.log('這是箭頭函數!');
};
var c = [].concat(a);
b();
var d = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("ok");
}, 2000);
});
d.then(function (res) {
console.log(res);
});
複製代碼
這樣,咱們能夠看到,個人代碼使用了promise,它就只引入promise相關的代碼。
- 注意:這兒使用usage參數後,JS文件裏面就不要單獨寫
import "@babel/polyfill"
這句話了,畫蛇添足。
到這兒,問題來了,在使用usage參數後使用babel的cli命令工具(也就是這個:npx babel test.js --watch --out-file test-done.js)會給一段提示,告訴咱們要指定core-js@2或者core-js@3,從babel 7.4事後官方就建議這麼作了,就是讓咱們放棄@babel/polyfill,我先卸載掉@babel/polyfill試一試,發現仍是能轉換,不科學,而後查資料和看preset-env文件夾下才發現,人家自帶了polyfill,因此這兒若是有了@babel/preset-env不須要單獨安裝@babel/polyfill了,前提應該是使用了@babel/preset-env配置了babel才行(像前面的徹底引入polyfill仍是須要單獨安裝@babel/polyfill),(注意:這兒我試了使用webpack結合babel-loader在不單獨安裝@babel/polyfill或者core-js這些打包會出問題,"useBuiltIns": "usage"時提示找不到包,使用entry參數打包不報錯,直接不會導入包,因此環境不同不能一律而論)前面有個要咱們指定corejs的提示,也只須要在babel.config.js裏面指定一下就能夠了,這兒個人@babel/perset-env版本是7.6.3,不知道其它版本有沒有集成polyfill,babel.config.js代碼以下:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8",
"useBuiltIns": "usage",
"corejs": 2
}]
]
}
複製代碼
這兒我測試了下指定corejs爲2和3時引入的代碼不同,暫時沒了解到緣由-_-。
接下來走一波不污染全局的配置方式,前面的配置都是要污染全局,仍是不怎麼科學,關於這種方式的優勢和缺點你們上網查一下就能夠了,接下來先安裝好包:
npm install @babel/plugin-transform-runtime -D
複製代碼
上面這個安裝到dev依賴就能夠了,不用於生產環境
npm install @babel/runtime
複製代碼
接下來咱們配置一下babel.config.js,以下:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8",
}]
],
plugins: [
["@babel/plugin-transform-runtime"]
]
}
複製代碼
而後輸出一下
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var a = [1, 2, 3];
var b = function b() {
console.log('這是箭頭函數!');
};
var c = [].concat(a);
b();
var d = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("ok");
}, 2000);
});
d.then(function (res) {
console.log(res);
});
var MM = function MM() { // 這個是我轉換前用class定義的類 class MM {constructor(){}} 這種
(0, _classCallCheck2["default"])(this, MM);
};
複製代碼
發現輸出的代碼裏面沒得polyfill了。若是須要polyfill的話就要單獨安裝如下內容:
npm install @babel/runtime-corejs2
複製代碼
這裏安裝這個包以前把我@babel/runtime給卸載了,安裝完成後再從新配置一下babel.config.js,以下:
module.exports = {
presets: [
["@babel/preset-env", {
"targets": "ie >= 8",
}]
],
plugins: [
["@babel/plugin-transform-runtime", {
"corejs": 2
}]
]
}
複製代碼
而後運行一下,看結果。相比前面的@babel/runtime,這裏的polyfill回來了,多了一句這個
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
複製代碼
babel-runtime VS babel-polyfill
結合Babel 7.4.0 談一下Babel-runtime 和 Babel-polyfill
20191107更新
結合webpack的話,還須要如下幾個東西:
npm install webpack -D
npm install webpack-cli -D
npm install babel-loader -D
複製代碼
babel-loader是加載器,要結合webpack來使用的話,這個必需要,同時,在項目根目錄創建一個webpack.config.js
配置文件(這裏webpack的知識就不介紹了,詳情參考官網)。
首先我仍是先測試了參數爲entry的狀況,配置文件內容以下(注意:這兒我還安裝了@babel/polyfill):
// index.js,是我要轉換的文件
import '@babel/polyfill';
let a = `hello, can you hear me!`;
let func = () => {
console.log('這是箭頭函數');
}
let b = [1, 2, 3];
let c = [...b];
let array = [1];
console.log(array);
let promise_t = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(233);
}, 2000)
});
promise_t.then((res) => {
console.log(res);
})
class Test {
constructor(name) {
this.name = name;
}
print() {
console.log(this.name);
}
}
let t_t = new Test('xiaohong');
t_t.print();
複製代碼
而後是webpack.config.js文件
const path = require('path');
module.exports = {
// 指定模式(這個指定能夠用來區分開發模式和生產模式,可選值有:'devvlopment','production','none')
mode: 'none',
// 入口
entry: {
main: path.resolve(__dirname, './src/index.js')
},
// 出口
output: {
// 出口文件
path: path.resolve(__dirname, './dist'),
// 文件名
filename: './[name].js',
},
// 加載器
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
}
]
}
}
複製代碼
以後再是babel.config.js文件
module.exports = {
presets: [
['@babel/preset-env', {
'useBuiltIns': 'entry',
}]
]
}
複製代碼
這兒我發現,即便個人babel.config.js不配置'useBuiltIns': 'entry',
這句,打包出來的main.js雖然內容有差異,可是仍是能運行成功,IE11親測可用上面js的promise語法。暫時我還沒把useBuiltIns這個屬性搞的特別清楚,只是知道在使用usage
屬性值時能夠按需加載polyfill。 接下來使用'useBuiltIns': 'usage'
來試一試,我發如今保持其餘文件不變的狀況下,(這兒有個問題是,使用usage時在index.js中仍是要寫這句import '@babel/polyfill',否則找不到包,這與我上面單獨使用babel來轉換時說不在單獨引入polyfill有點出入,還沒怎麼明白,後期我會補充)。而後我比較了兩種方式生成的main.js的代碼,使用entry屬性值時,main.js代碼八千多行,大小大概250kb,使用usage參數時,代碼一千多行,大小大概37kb,因此按需引入效果仍是明顯。並且親測在IE11上兩種方式生成的代碼都可正常運行。
官方網站上面說從babel 7.4.0後開始放棄babel/polyfill,轉而使用core-js。這兒咱們又來試一試core-js 首先卸載@babel/polyfill,而後執行如下命令安裝core-js@2:
npm install core-js@2 -S
複製代碼
這兒還有個core-js@3的版本,暫時沒有用過,不知道區別。安裝完成後修改一下babel.config.js
module.exports = {
presets: [
['@babel/preset-env', {
'useBuiltIns': 'usage',
'corejs': 2
}]
]
}
複製代碼
而後你的index.js的上面去掉import '@babel/polyfill'
,這時執行事後的main.js能完美運行在IE11上,並且這兒也不須要手動引入core-js@2,使用usage屬性值時自動按需引入,比較穩。若是我不寫'corejs': 2
這個參數,轉換也能夠成功,可是會報warning,叫我去安裝core-js並制定版本,問題不大,仍是寫上,畢竟官方要求。 而後若是我直接把useBuiltIns的參數值改成entry,發現class這些es6語法會轉換,可是Promise的polyfill沒有引入,看來沒usage參數好使,須要手動引入才行,我在index.js手動引入import 'core-js', 而後執行webpack可是卻報錯,提示Module not found: Error: Can't resolve 'regenerator-runtime/runtime'
,這個就尷尬了,還要安裝regenerator-runtime/runtime,可是使用usage卻沒有出現這個問題,暫時無解,這兒我單獨安裝一次:
npm install regenerator-runtime -D
複製代碼
這兒我單獨安裝一次regenerator-runtime就不會報錯了,暫時沒找到緣由,試着在安裝了regenerator-runtime的狀況下使用usage參數值,同時去除index.js裏面的import 'core-js'這句話,否則會報警告。內容像這樣:When setting useBuiltIns: 'usage'
, polyfills are automatically imported when needed. Please remove the import '@babel/polyfill'
call or use useBuiltIns: 'entry'
instead.。我試了下,使用webpack打包沒得問題,能夠運行。這兒建議把regenerator-runtime安裝一次,避免沒必要要的麻煩。
usage
參數值提示找不到core-js的包,entry
直接不會引入相關的東西,由於包都沒有,會提示你去下載corejs。false
效果跟entry同樣。 二、只安裝了core-js(這兒安裝的core-js@2版本),usage
參數能夠打包成功,可是提示指定core-js版本,這個正常,由於我沒寫那句'corejs: 2'
了,測試在IE11上正常運行。entry
參數須要手動在index.js中引入core-js,打包提示Can't resolve 'regenerator-runtime/runtime'
,打包失敗,false
參數打包成功,可是文件巨大,代碼九千多行-_-,IE11運行成功。 三、安裝core-js和regenerator-runtime,usage
參數能夠打包成功,可是提示指定core-js版本,這個正常,由於我沒寫那句'corejs: 2'
了,測試在IE11上正常運行。entry
參數能夠打包成功,可是提示指定core-js版本,這個正常,由於我沒寫那句'corejs: 2'
了,測試在IE11上正常運行,打包事後文件巨大,我安裝了regenerator-runtime,沒有在index.js裏面手動引入,只引入了core-js,此次打包沒報上面找不到包的錯誤。false
參數能夠打包成功,可是提示指定core-js版本,這個正常,由於我沒寫那句'corejs: 2'
了,測試在IE11上正常運行,打包事後文件巨大。因此我得出一個配置結果 在babel.config.js裏面這樣寫:
module.exports = {
presets: [
['@babel/preset-env', {
'useBuiltIns': 'usage',
'corejs': 2
}]
]
}
複製代碼
package.json裏面包含這些包:
{
"name": "webpack-babel",
"version": "1.0.0",
"description": "practice",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js"
},
"author": "lee",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.7.0",
"@babel/preset-env": "^7.7.1",
"babel-loader": "^8.0.6",
"regenerator-runtime": "^0.13.3",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.9"
},
"dependencies": {
"core-js": "^2.6.10"
}
}
複製代碼
core-js和regenerator-runtime(這個爲了不entry參數時包錯找不到包)都安裝起。這樣就能夠了。
前面使用了@babel/preset-env的useBuiltIns來實現API填充,這兒試一試另外一種方案,首先卸載掉core-js和regenerator-runtime,而後安裝一下兩個包
npm install @babel/plugin-transform-runtime -D
複製代碼
npm install @babel/runtime-corejs2 -S
複製代碼
安裝完成後配置一下babel.config.js
module.exports = {
presets: [
['@babel/preset-env']
],
plugins: [
['@babel/plugin-transform-runtime', {
'corejs': 2
}]
]
}
複製代碼
注意:這兒我是安裝的@babel/runtime-corejs2,因此「'corejs': 2」這個參數不能少,否者會報 Can't resolve '@babel/runtime/helpers/createClass'這種錯誤,上面這種方式不會污染全局,適合第三方開發。
暫時babel就總結到這兒了,順便熟悉了一下webpack,若有不許確的地方還請各位多多指正,文章裏面還有幾個沒理解清楚的地方,後期再琢磨琢磨!這裏附上github的地址供你們參考:地址