什么是 Babel
Babel 是 JavaScript 的编译器,为了能够在当前或旧的浏览器或者其他环境运行 ECMAScript 2015 以及更新版本的语法,Babel 的主要职责是把其转换成向后兼容的 JavaScript 语法。
为什么需要使用 Babel
当你写的 JavaScript 在 Chrome 中能正常运行的时,把代码拿去 IE 或者其他浏览器再跑一遍时,控制台不停地给你错误的信息,你不得不重新添加兼容性的代码去设配各种浏览器能让代码正常跑起来,Babel 就是来解放你的,只需要简单的配置,让你更高效的编码。
如何使用 Babel
- 新建文件夹
learn-babel
, - 在文件夹下执行
npm init -y
生成package.json
文件 - 新建文件
index.js
- 为了方便测试,我们安装 Redux 库来做实验,执行
npm i --save redux
- 修改
index.js
import { legacy_createStore as createStore } from "redux";
console.log(createStore);
- 修改配置文件
package.json
如下
{
"name": "learnbabel",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"license": "MIT",
"dependencies": {
"redux": "^4.2.0"
}
}
- 然后你执行
npm start
此刻会出现报错信息,说不支持 import 语法
- 我们可以安装 Babel 工具来兼容语法,执行
npm install --save-dev @babel/cli @babel/core @babel/preset-env
包 | 描述 |
---|---|
@babel/cli | 内置的 CLI 命令工具 |
@babel/core | babel 的核心,例如 transform 转换就包含在此包中 |
@babel/preset-env | Babel 智能预设,基本仅需要配置它就可以完成现代JS工程所需要的所有转码要求 |
- 然后新建文件
babel.config.json
{
"presets": ["@babel/preset-env"]
}
- 其次修改配置文件
package.json
如下
{
"name": "learnbabel",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "babel index.js -o dist/index.js"
},
"license": "MIT",
"dependencies": {
"redux": "^4.2.0"
}
}
- 在执行执行
npm start
, 可以看到编译后dist/index.js
如下
"use strict";
var _redux = require("redux");
console.log(_redux.legacy_createStore);
- 当然我们可以选择安装
npm i --save-dev @babel/node
来支持直接运行脚本 - 安装后,只需要修改配置文件
package.json
...
"scripts": {
"start": "babel-node index.js"
},
...
- 执行查看结果和上面一样
Babel 是如何解析的
Babel 的大体编译过程如下
ES6 的代码首先通过 Babel 的解析阶段,解析阶段其中包括词法解析(Lexical Analysis)和句法解析(Syntactic Analysis),解析生成 AST 抽象语法树,然后进入转换阶段,通过深度优先遍历,依靠类型(下图的type)去匹配后替换语法,最后将抽象语法树转为字符串形式的代码进行返回。
index.js
的抽象语法树如下
{
"type": "File",
"start": 0,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 25
}
},
"errors": [],
"program": {
"type": "Program",
"start": 0,
"end": 84,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 2,
"column": 25
}
},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ImportDeclaration",
"start": 0,
"end": 58,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 58
}
},
"specifiers": [
{
"type": "ImportSpecifier",
"start": 9,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 42
}
},
"imported": {
"type": "Identifier",
"start": 9,
"end": 27,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 27
},
"identifierName": "legacy_createStore"
},
"name": "legacy_createStore"
},
"importKind": null,
"local": {
"type": "Identifier",
"start": 31,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 42
},
"identifierName": "createStore"
},
"name": "createStore"
}
}
],
"importKind": "value",
"source": {
"type": "StringLiteral",
"start": 50,
"end": 57,
"loc": {
"start": {
"line": 1,
"column": 50
},
"end": {
"line": 1,
"column": 57
}
},
"extra": {
"rawValue": "redux",
"raw": "\"redux\""
},
"value": "redux"
},
"assertions": []
},
{
"type": "ExpressionStatement",
"start": 59,
"end": 84,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 25
}
},
"expression": {
"type": "CallExpression",
"start": 59,
"end": 83,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 24
}
},
"callee": {
"type": "MemberExpression",
"start": 59,
"end": 70,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 11
}
},
"object": {
"type": "Identifier",
"start": 59,
"end": 66,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 7
},
"identifierName": "console"
},
"name": "console"
},
"computed": false,
"property": {
"type": "Identifier",
"start": 67,
"end": 70,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 11
},
"identifierName": "log"
},
"name": "log"
}
},
"arguments": [
{
"type": "Identifier",
"start": 71,
"end": 82,
"loc": {
"start": {
"line": 2,
"column": 12
},
"end": {
"line": 2,
"column": 23
},
"identifierName": "createStore"
},
"name": "createStore"
}
]
}
}
],
"directives": []
},
"comments": []
}
让 Babel 支持 React
npm i --save react@16 react-dom@16
新建文件夹 src, 在 src 下新建文件 index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
export default function Index() {
return (
<div>Index</div>
)
}
ReactDOM.render(<Index/>,document.getElementById('app'));
修改配置文件 package.json
{
"name": "learnbabel",
"version": "1.0.0",
"scripts": {
"start": "babel-node index.js",
"build": "babel src -d dist"
},
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.17.12",
"@babel/node": "^7.17.10",
"@babel/preset-env": "^7.17.12"
},
"dependencies": {
"react": "^16.14.0",
"react-dom": "^16.14.0",
"redux": "^4.2.0"
}
}
直接运行 npm run build
会报错
添加配置来支持 React
npm i --save-dev @babel/preset-react
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
然后再次运行编译,结果成功编译
验证是否可挂载在 html 正常运行
在根目录下新建 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="dist/index.js"></script>
</body>
</html>
安装 webpack
包来支持 web 构建
npm install --save-dev webpack webpack-cli babel-loader html-webpack-plugin webpack-dev-server
包 | 描述 |
---|---|
webpack-cli | 内置的 CLI 命令工具 |
webpack | webpack 的核心包 |
babel-loader | webpack 与 babel 通讯的桥梁 |
html-webpack-plugin | webpack 生成 html 插件 |
webpack-dev-server | 结合热加载快速开发应用程序 |
新建 webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
module.exports = {
mode:'development',
entry: {
"index": "./src/index.jsx"
},
output: {
"path": path.resolve(__dirname, 'dist'),
"filename": "[name]-[hash:8].js"
},
module: {
"rules": [
{
"test": /\.jsx?$/,
"exclude": /node_modules/,
"use": {
"loader": "babel-loader",
}
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
title: 'learn-babel',
"template": "index.html",
"filename": "index.html",
"inject": true
})
],
devServer:{
"static": path.resolve(__dirname, 'dist'),
"hot": true,
"port": 8080,
}
}
修改配置文件 package.json
"scripts": {
"start": "webpack-dev-server --open",
"build": "babel src -d dist"
},
运行 npm start
修改 index.jsx
的内容会立即刷新,这就是热更新的好处
让 Babel 支持 Typescript
新建文件 src/index.ts
const enum WebDay {
Monday = 1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
class Animal{
private name: string;
constructor(name: string){
this.name = name;
}
public getName(): string{
return this.name;
}
}
console.log(WebDay.Monday);
let dog = new Animal("dog");
console.log(dog.getName());
修改配置 package.json
"scripts": {
"build": "babel src/index.ts -o lib/index.js"
},
运行报错,提示无法识别 Typescript
的枚举类型
同样安装 npm i --save-dev @babel/preset-typescript
然后修改配置文件 babel.config.json
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
]
}
运行 npm start
发现成功编译
Babel 有很多配置集成与工具,你可以通过查看 babeljs 官网学习使用。
致谢
感谢你看到这里,希望本文对你有所帮助,希望大家不要吝啬自己的赞
若有疑问或者建议,欢迎评论区留言,一起互相交流讨论,共同进步!🐶
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。