Babel 入门真的有这么丝滑吗

367

什么是 Babel

Babel 是 JavaScript 的编译器,为了能够在当前或旧的浏览器或者其他环境运行 ECMAScript 2015 以及更新版本的语法,Babel 的主要职责是把其转换成向后兼容的 JavaScript 语法。

为什么需要使用 Babel

当你写的 JavaScript 在 Chrome 中能正常运行的时,把代码拿去 IE 或者其他浏览器再跑一遍时,控制台不停地给你错误的信息,你不得不重新添加兼容性的代码去设配各种浏览器能让代码正常跑起来,Babel 就是来解放你的,只需要简单的配置,让你更高效的编码。

如何使用 Babel

  1. 新建文件夹 learn-babel,
  2. 在文件夹下执行 npm init -y 生成 package.json 文件
  3. 新建文件 index.js
  4. 为了方便测试,我们安装 Redux 库来做实验,执行 npm i --save redux
  5. 修改 index.js
import { legacy_createStore as createStore } from "redux";
console.log(createStore);
  1. 修改配置文件 package.json 如下
{
  "name": "learnbabel",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "license": "MIT",
  "dependencies": {
    "redux": "^4.2.0"
  }
}
  1. 然后你执行 npm start

610541068-62866ef3aaf21_fix732.webp

此刻会出现报错信息,说不支持 import 语法

  1. 我们可以安装 Babel 工具来兼容语法,执行 npm install --save-dev @babel/cli @babel/core @babel/preset-env
描述
@babel/cli内置的 CLI 命令工具
@babel/corebabel 的核心,例如 transform 转换就包含在此包中
@babel/preset-envBabel 智能预设,基本仅需要配置它就可以完成现代JS工程所需要的所有转码要求
  1. 然后新建文件 babel.config.json
{
    "presets": ["@babel/preset-env"]
}
  1. 其次修改配置文件 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"
  }
}
  1. 在执行执行 npm start , 可以看到编译后 dist/index.js 如下
"use strict";

var _redux = require("redux");

console.log(_redux.legacy_createStore);

3311608818-861bab2e8a90b412.webp

  1. 当然我们可以选择安装 npm i --save-dev @babel/node 来支持直接运行脚本
  2. 安装后,只需要修改配置文件 package.json
...
  "scripts": {
    "start": "babel-node index.js"
  },
...
  1. 执行查看结果和上面一样

1117215663-6286733b885e5_fix732.webp

Babel 是如何解析的

Babel 的大体编译过程如下

81931016-62899fde617c5_fix732.webp

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 会报错

902925034-6289d7b652189_fix732.webp

添加配置来支持 React

npm i --save-dev @babel/preset-react

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}

然后再次运行编译,结果成功编译

551981314-6289d92502b7a_fix732.webp

3311608818-861bab2e8a90b412.webp

验证是否可挂载在 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 命令工具
webpackwebpack 的核心包
babel-loaderwebpack 与 babel 通讯的桥梁
html-webpack-pluginwebpack 生成 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

869939540-628a00be42834_fix732.webp

修改 index.jsx 的内容会立即刷新,这就是热更新的好处

1731496293-628a01c97ce5a.webp

让 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 的枚举类型

1759693352-628a048259af6_fix732.webp

同样安装 npm i --save-dev @babel/preset-typescript

然后修改配置文件 babel.config.json

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react",
        "@babel/preset-typescript"
    ]
}

运行 npm start 发现成功编译

Babel 有很多配置集成与工具,你可以通过查看 babeljs 官网学习使用。

致谢

感谢你看到这里,希望本文对你有所帮助,希望大家不要吝啬自己的赞 若有疑问或者建议,欢迎评论区留言,一起互相交流讨论,共同进步!🐶