前言

我觉得事情不大对,好像我之前几篇,太长了,以后我尽量控制下长度

babel

官网:https://babeljs.io/
中文网(非官方):https://www.babeljs.cn/

babel是一个编译器,可以把不同标准书写的语言,编译为统一的、能被各种浏览器识别的语言

babel转化的方式和postcss差不多,都是本身只提供一些分析的功能,具体的转化依靠的是插件

2020-02-07-10-27-30

安装babel

babel可以和构建工具联合使用,也可以独立使用

如果要独立的使用babel,需要安装下面两个库:

  • @babel/core:babel核心库,提供了编译所需的所有api
  • @babel/cli:提供一个命令行工具,调用核心库的api完成编译
1
npm install @babel/core @babel/cli -D

@babel/cli提供了一个命令babel

1
2
3
4
5
# 按文件编译
babel 要编译的文件 -o 编辑结果文件

# 按目录编译
babel 要编译的整个目录 -d 编译结果放置的目录

比如说

1
babel ./src/index.js -o ./src/script/index.js

但是现在没有插件,做不了什么,只是原样输出而已

配置文件

babel转化代码要依托于babel插件babel预设来完成,那我们就需要一个配置文件来告诉babel使用哪些插件和预设,这个配置文件默认是.babelrc

新建.babelrc

1
2
3
4
{
"presets": [],
"plugins": []
}

babel预设

babel有多种预设,最常见的预设是@babel/preset-env

@babel/preset-env 文档 https://www.babeljs.cn/docs/babel-preset-env#options

@babel/preset-env可以让你使用最新的JS语法,而无需针对每种语法转换设置具体的插件

安装

1
npm install @babel/preset-env -D

配置

1
2
3
4
{
"presets": ["@babel/preset-env"],
"plugins": []
}

使用

1
let a = 3 ** 4;

转化后变成

1
2
3
"use strict";

var a = Math.pow(3, 4);

但是只是这样还有一个问题,那就是现在只会对新语法进行处理,而不对新的API进行处理

比如说Promise是不会进行转化的

image-20210114192847152

如果遇到没有Promise构造函数的旧版本浏览器,该代码就会报错

因此我们要进行一些配置

1
2
3
4
5
6
7
8
9
10
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}
]
],
"plugins": []
}

而配置usebuiltins可以在编译结果中注入这些新的API,它的值默认为false,表示不注入任何新的API,可以将其设置为usage,表示根据API的使用情况,按需导入API

重新执行babel命令

image-20210114193635374

从打包结果看出,我们还需要安装一个corejs

1
npm install core-js

安装后就可以运行了

image-20210114194410625

注意,配置usebuiltins后,即使不安装core-js也可以转化成一样的打包结果,但是不安装core-js就无法运行

顺带一提,如果要转化async和await,需要再安装一个库regenerator-runtime

1
npm install regenerator-runtime

加了后就可以了

image-20210114195426869

另外,@babel/preset-env需要根据兼容的浏览器范围来确定如何编译,和postcss一样,可以使用文件.browserslistrc来描述浏览器的兼容范围

1
2
3
last 3 version
> 1%
not ie <= 8

babel插件

通常情况下,@babel/preset-env只转换那些已经形成正式标准的语法,对于某些处于早期阶段、还没有确定的语法不做转换。

如果要转换这些语法,就要单独使用插件,下面介绍一些插件

安装

1
2
cnpm install @babel/plugin-proposal-class-properties @babel/plugin-proposal-function-bind @babel/plu
gin-proposal-optional-chaining babel-plugin-transform-remove-console @babel/plugin-transform-runtime
1
cnpm install --save @babel/runtime

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "usage",
"corejs": 3
}]
],
"plugins": [
["@babel/proposal-class-properties", {
"loose": true
}],
"@babel/proposal-function-bind",
"@babel/proposal-optional-chaining",
"transform-remove-console",
"@babel/transform-runtime"
]
}

@babel/plugin-proposal-class-properties

该插件可以让你在类中书写初始化字段

1
2
3
4
5
6
class A {
a = 1;
constructor(){
this.b = 3;
}
}

@babel/plugin-proposal-function-bind

该插件可以让你轻松的为某个方法绑定this

1
2
3
4
5
6
7
8
9
function Print() {
console.log(this.loginId);
}

const obj = {
loginId: "abc"
};

obj::Print(); //相当于:Print.call(obj);

@babel/plugin-proposal-optional-chaining

支持?.语法

1
2
3
4
5
6
7
8
9
10
11
const obj = {
foo: {
bar: {
baz: 42,
},
},
};

const baz = obj?.foo?.bar?.baz; // 42

const safe = obj?.qux?.baz; // undefined

babel-plugin-transform-remove-console

该插件会移除源码中的控制台输出语句

1
2
console.log("foo");
console.error("bar");

编译后

1

@babel/plugin-transform-runtime

用于提供一些公共的API,比如下面的代码

1
2
3
4
5
class A {
constructor(name) {
this.name = name;
}
}

转化后

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";

require("core-js/modules/es.function.name.js");

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

// let a = 3 ** 4;
var A = function A(name) {
_classCallCheck(this, A);

this.name = name;
};

如果使用了这个库

转化后

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

require("core-js/modules/es.function.name.js");

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var A = function A(name) {
(0, _classCallCheck2.default)(this, A);
this.name = name;
};

可以看出来,需要的辅助函数都从外部引入了,这样就可以避免一些重复代码,比如如果你有10个类,不使用这个库的话,_classCallCheck这个函数是会重复出现在10个文件里的,就会影响打包后的代码大小

在webpack里使用

安装

1
npm install --save-dev babel-loader @babel/core

如果你是在新项目里使用,必须要安装@babel/core,因为babel-loader要调用它

配置一波

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const path = require("path");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const webpack = require("webpack");
const cssLoaderConfig = {
loader: "css-loader",
options: {
modules : {
localIdentName: "[local]-[hash:5]"
}
}
};
module.exports = {
entry: {
index: "./index.js"
},
mode: "development",
// devtool: "source-map",
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/[name].[chunkhash:5].js",
publicPath: "/"
},
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
port: 9000,
open : true,
},
context: path.resolve(__dirname, "src"),
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
cssLoaderConfig,
"postcss-loader",
"sass-loader",
]
},
{
test: /\.less$/i,
use: [
MiniCssExtractPlugin.loader,
cssLoaderConfig,
"postcss-loader",
"less-loader",
]
},
{
test: /\.p?css$/i,
use: [
MiniCssExtractPlugin.loader,
cssLoaderConfig,
"postcss-loader",
]
},
{
test: /\.(png)|(gif)|(jpg)$/,
use: [{
loader: "url-loader",
options: {
limit: 10 * 1024,
name: "imgs/[name].[contenthash:5].[ext]"
}
}]
}],
noParse: /jquery/
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html",
filename: "html/index.html",
chunks: ["index"]
}),
new CopyWebpackPlugin({
patterns: [
{
from: "./assets",
to: "./assets"
},
],
}),
new webpack.ProvidePlugin({
$ : 'jquery'
}),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash:5].css"
})
],
resolve: {
alias: {
"@": path.resolve(__dirname, 'src')
}},
externals: {
jquery : "$"
}
}

好的,这样就可以让babel处理我们在项目中的js文件了

后记

我没咕咕咕,耶