Babel github :https://github.com/babel/babel/tree/master/packages
Babel 在線轉化:https://www.babeljs.cn/repl
Babel 是干嘛的
用於將 ECMAScript 2015+ 版本的代碼轉換為向后兼容的 JavaScript 語法,以便能夠運行在當前和舊版本的瀏覽器或其他環境中。下面列出的是 Babel 能為你做的事情:
- 語法轉換
- 通過 Polyfill 方式在目標環境中添加缺失的特性 (通過 @babel/polyfill 模塊)
- 源碼轉換 (codemods)
npx
在Babel使用之前先介紹一下npx,因為后面用到npx,注意不是npm
npx是啥
npx是一種在npm中安裝工具,也可以被單獨的下載使用
在npm 5.2.0 的時候發現會買一送一,自動安裝了npx。
也就是說 npm5.2之后,會自動安裝
npx是解決什么問題的
再也不需全局安裝任何工具只需要npx <commang>
為什么使用npx
全局安裝劣勢:
-
占用本機空間
npm會在machine上創建一個目錄(mac是
/usr/local/lib/node_modules
)存放所有global安裝的包, 其實node_module占用的空間比較大的 -
版本問題:
假如一個項目中的某一個dependency是全局安裝的,也就意味着不同的開發人員使用的這個dependency版本完全基於本地的版本,也就會導致不同的開發人員使用不同的版本
使用npx的優勢也就凸顯出來了:
-
當在執行
npx <command>
的時候,npx會做什么事情?
- 幫你在本地(可以是項目中的也可以是本機的)尋找這個 command
- 找到了: 就用本地的版本
- 沒找到: 直接下載最新版本,完成命令要求
- 使用完之后不會在你的本機或者項目留下任何東西
- 幫你在本地(可以是項目中的也可以是本機的)尋找這個 command
因此優勢總結:
- 不會污染本機
- 永遠使用最新版本的dependency
Babel使用
配置Node項目環境
執行
npm init -y
然后項目目錄下就會創建一個package.json,如
下載相應的包的命令
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill
或者簡寫:
npm install -D @babel/core @babel/cli @babel/preset-env
npm install @babel/polyfill
(--save-dev(簡寫-D)表示該版本只適用於開發環境中,命令會自動幫你寫在package.json的devDependencies中
--save(或者不寫)則表示該版本適用於生產環境中,命令會自動幫你寫在package.json的dependencies中 )
如:
使用Babel前要下載的包的意義和用法
@babel/core
Babel 的核心功能在 @babel/core模塊,如果某些代碼需要調用Babel的API進行轉碼,則就需要此模塊。
用法如下
var babel = require('@babel/core');
// 字符串轉碼
babel.transform('code();', options);
// => { code, map, ast }
// 文件轉碼(異步)
babel.transformFile('filename.js', options, function(err, result) {
result; // => { code, map, ast }
});
// 文件轉碼(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }
// Babel AST轉碼
babel.transformFromAst(ast, code, options);
// => { code, map, ast }
@babel/polyfill
模塊包括core-js和自定義regenerator runtime 來模擬完整的 ES2015+ 環境。
Babel默認只轉換新的JavaScript句法(syntax),而不轉換新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局對象,以及一些定義在全局對象上的方法(比如Object.assign
)都不會轉碼。
舉例來說,ES6在Array
對象上新增了Array.from
方法。Babel就不會轉碼這個方法。如果想讓這個方法運行,必須使用babel-polyfill
,為當前環境提供一個墊片
@babel/preset-env
根據你需要支持的環境(配合targets中的瀏覽器信息)自動決定適合你的 Babel 插件
@babel/cli
@babel/cli是一個允許你從終端使用 babel 的工具。即用於命令行轉碼
全局安裝命令
npm install -D @babel/cli -g
基本用法如下。
# 轉碼結果輸出到標准輸出(字符串形式輸出)
$ babel example.js
# 轉碼結果寫入一個文件
# --out-file 或 -o 參數指定輸出文件
$ babel example.js --out-file compiled.js
# 或者
$ babel example.js -o compiled.js
# 整個目錄轉碼
# --out-dir 或 -d 參數指定輸出目錄
$ babel src --out-dir lib
# 或者
$ babel src -d lib
# -s 參數生成source map文件
$ babel src -d lib -s
創建配置文件
使用以下內容在項目的根目錄中創建名為 babel.config.js 的配置文件:(配置文件很重要)
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
useBuiltIns: "usage"
}]
];
const plugins = [];
return {
presets,
plugins
}
}
//target表示你想要支持的瀏覽器的最低型號
// useBuiltIns: "usage" ——由於polyfill包很臃腫,Babel 的此設置將檢查你的所有代碼,以查找目標環境中缺少的功能,並僅包含所需的 polyfill。
開始使用
創建src文件夾,再在里面創建index.js文件,並輸入
(x => x * 2)(1)
在命令行中輸入
//表示src整個目錄轉碼到dist目錄下
npx babel src -d dist
結果如下
可以看到已經被成功編譯
es6相關特性編譯問題
class 不支持
上面安裝了@babel/polyfill
包 編譯Promise等全局對對象沒問題,但是你會發現class類 這個特性編譯不了
如
這是因為還缺少一個插件@babel/plugin-proposal-class-properties
安裝
npm install @babel/plugin-proposal-class-properties -D
在配置文件中加入插件配置
const plugins = [
'@babel/plugin-proposal-class-properties'
];
此時的babel.config.js
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
},
useBuiltIns: "usage"
}]
];
const plugins = [
'@babel/plugin-proposal-class-properties'
];
return {
presets,
plugins
}
}
執行編譯
npx babel src -d dist
編譯結果
class 編譯之后出現 require()
如果你的類比較復雜,如
class A {
constructor() {
console.log('A構造方法');
}
}
class B extends A{
constructor() {
super();
console.log('B構造方法')
}
}
你運行編譯命令之后,你會發現,編譯完成的文件是這樣的
npx babel src -d dist
你會發現居然出現了require(),這不是node的嗎,為什么編譯之后會出現這個?並且你會發現直接注釋掉也可以引入運行,如
找不到require()里面的相關文件
你順着它引入的文件去模塊里面去找,你會發現這些文件你都找不到,這是為什么,怎么解決?
這時候你再用Babel編譯一次,你會發現
npx babel src -d dist
編譯有個警告
大概意思就是沒有指定corejs的版本,就是這個的原因
首先安裝corejs
npm install --save core-js@3
然后在配置文件babel.config.js中加入corejs : 3
的設置選項
這時候配置文件是這樣的
module.exports = function(api){
api.cache(true)
const presets = [
["@babel/env", {
targets: {
ie:"10",
edge: "17",
firefox: "60",
chrome: "60",
safari: "11.1"
},
useBuiltIns: "usage",
corejs : 3
}]
];
const plugins = [
'@babel/plugin-proposal-class-properties',
];
return {
presets,
plugins
}
}
再次執行Babel編譯命令
npx babel src -d dist
沒有警告了
再次打開,發現可以找到相關文件了
但是require()還是有,瀏覽器不可能支持require()。babel 是怎么編譯es6的模塊的,怎么會出現require()?
其實就一句話:
babel 統一將 js 模塊化語法轉為 commonJS 風格。
從Babel 6.0開始,不再直接提供瀏覽器版本,需要配合webpack等構建工具使用。如果你的項目相當簡單,並不需要使用構建工具,而你又想在Web項目中使用ES6的語法,Babel+Browserify可以滿足你的需求。
安裝Browserify
github:https://github.com/browserify/browserify
npm install browserify -D
執行Browserify編譯
npx browserify ./dist/testClass.js -o test.js
結果如下
編譯是編譯完了,還是有require(),但是好像自己實現了,那html頁面引入怎么用呢?
看了下生成的結構
這是自調用的閉包,頁面直接引入不可能可以調用的,那怎么在html直接引入調用呢?出現這種情況是為什么呢?這是因為
默認情況下,Browserify不允許從瀏覽器序列化代碼之外訪問模塊。如果要調用瀏覽器序列化模塊中的代碼,則應該將代碼與模塊一起瀏覽
參考:https://cloud.tencent.com/developer/ask/109752
npx browserify ./dist/testClass.js --standalone Main -o testClass.js
設置導出到全局的模塊
來到我們使用Babel編譯后的文件
加入模塊導出語句
例:
module.exports = B;
執行編譯
其實就是將我們導出的模塊掛載到window對象下,使我們頁面能夠直接訪問
#npx browserify [Babel編譯后的文件路徑] --standalone 導出的模塊名 -o 導出的文件位置
npx browserify ./dist/testClass.js --standalone B -o testClass.js
頁面引入執行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--<script src="./dist/testClass.js"></script>-->
<script src="testClass.js"></script>
</head>
<body>
<script>
console.log(B);
</script>
</body>
</html>
運行結果