前言

若文章有误,欢迎读者留言反馈

💻Installation

1
git clone https://github.com/coding327/learn_webpack5.git

webpack-babel工具

这里我们先引入一个工具babel

babel官网

  • 事实上,在开发中我们很少直接去接触babel,但是babel对于前端开发来说,目前是不可缺少的一部分:
    • 开发中,我们想要使用ES6+的语法,想要使用TypeScript,开发React项目,它们都是离不开Babel的;
    • 所以,学习Babel对于我们理解代码从编写到线上的转变过程至关重要;
  • 那么,Babel到底是什么呢?
    • Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript;
    • 包括:语法转换、源代码转换等;
      1
      2
      3
      4
      5
      [1,2,3].map((n) =>n+ 1);

      [123].map(function(n) {
      return n + 1;
      });

Babel命令行使用[不推荐]

  • babel本身可以作为一个独立的工具(和postcss一样),不和webpack等构建工具配置来单独使用。
  • 如果我们希望在命令行尝试使用babel,需要安装如下库:
    • @babel/core: babel的核心代码,必须安装;
    • @babel/cli: 可以让我们在命令行【如果是在webpack中配置使用是不需要安装的】使用babel;
  • 使用babel来处理我们的源代码:
    • src∶ 是源文件的目录;
    • --out-dir: 指定要输出的文件夹dist;
    • --out-file: 指定要输出的文件如demo.js

安装以上两个库

1
npm install @babel/core @babel/cli -D

我们在项目根目录下创建一个demo.js文件,在里面写点ES6代码

1
2
3
4
5
6
// 书写ES6代码

const message = "Hello World"
const names = ["abc", "cba", "nba"]

names.forEach(item => console.log(item))

这里我们想用babel把以上ES6代码转换为ES5代码,局部安装babel,它是在咱们的node_modules/.bin下的

1
npx babel demo.js --out-dir dist

但是会发现dist下的demo.js依旧还是之前ES6代码
主要是因为在我们使用babel的时候,如果你想要把我们的某些语法做一个转化,这个时候的话你必须对应的使用一个插件

babel工具插件的使用

比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件:

1
npm install @babel/plugin-transform-arrow-functions -D

使用该插件:

1
npx babel demo.js --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

这时候我们再去看dist下的demo.js,发现箭头函数就被转换为ES5代码了
但是const没有做转换,这时候我们也可以使用以下这个插件【转换let、const这种块级作用域的定义的关键字】来做转换

1
npm install @babel/plugin-transform-block-scoping -D

使用该插件:

1
2
# 多个插件用,隔开
npx babel demo.js --out-dir dist --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping

这时我们就发现转换成功了

但是ES6语法这么多还有ES7ES8ES9ES10等等,一个一个插件安装太费劲了
正是因为麻烦,所以babel它给我们提供了另外一个东西preset

babel的预设preset

把我们常用的那些插件相当于集合到了一起
安装@babel/preset-env预设:

1
npm install @babel/preset-env -D

使用预设:

1
2
# 预设可能是有多个的,所以后面会有个s,像react的预设或者ts的预设,它们都有对应的预设的
npx babel demo.js --out-dir dist --presets=@babel/preset-env

为了方便观察,可以把dist删掉,再执行,发现转换成功

Babel的底层原理

babel是如何做到将我们的一段代码(ES6TypeScriptReact)转成另外一段代码(ES5)的呢?

  • 从一种源代码(原生语言)转换成另一种源代码(目标语言),这是什么的工作呢?
  • 就是编译器,事实上我们可以将babel看成就是一个编译器。
  • Babel编译器的作用就是将我们的源代码,转换成浏览器可以直接识别的另外一段源代码;
    Babel也拥有编译器的工作流程:
  • 解析阶段(Parsing)
  • 转换阶段(Transformation)
  • 生成阶段(Code Generation)

Babel编译器执行原理

Babel的执行阶段

10176

当然,这只是一个简化版的编译器工具流程,在每个阶段又会有自己具体的工作:

10177

webpack中如何配置babel

认识babel-loader

webpack并没有将我们的ES6代码转为ES5代码

这里我们可以验证一下:
把之前demo.js文件里的代码添加到main.js文件中

1
2
3
4
5
6
7
// 书写ES6代码

const message = "Hello World"
const names = ["abc", "cba", "nba"]

names.forEach(item => console.log(item))
console.log(message)

然后我们打包试一下,在打包文件夹下找到main.js文件,直接搜索message就能找到,发现仍然是ES6代码,webpack并没有帮我们做转换
因为这不属于webpack的工作,webpack是一个模块化的打包工具,它是不负责语法转换这个工作的,但是它负责每个文件当成一个模块,支持esmodulecommonjsamd
这个时候我们就需要使用babel,将ES6及以上的语法转换为ES5代码
那么什么时候使用babel呢?
很显然就是在webpack解析【加载】我们的js代码时,使用这个babel-loader

安装babel-loader

1
npm install babel-loader -D

回到webpack.config.js配置文件中,配置rules

1
2
3
4
5
6
7
8
9
10
11
12
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
plugins: [
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-block-scoping",
]
}
}
}, // 加载js所需要规则【配置项未抽离版】

然后再打包,就发现语法转换成功
但是有个弊端,每次写插件过于麻烦,我们可以使用预设preset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
// plugins: [
// "@babel/plugin-transform-arrow-functions",
// "@babel/plugin-transform-block-scoping",
// ]
presets: [
"@babel/preset-env"
// ["@babel/preset-env", {
// // 配置项
// }] // 这个写法是补充的,因为有可能在其它地方需要传入配置项
]
}
}
}, // 加载js所需要规则【配置项未抽离版】

重新打包发现也是转换成功了

之前postcss我们把配置可以抽离到独立的文件里,babel也是可以的

Babel的配置文件

像之前一样,我们可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写︰

  • babel.config.json(或者js.cjs , .mjs )文件;
  • .babelrc.json(或者.babelrc , .js , .cjs , .mjs )文件;
    以上第二个多个rc,这个rc可以理解为runtime compiler,运行时编译

它们两个有什么区别呢﹖目前很多的项目都采用了多包管理的方式( babel本身、element-plusumi等);

  • .babelrc.json ( 早期 ): 早期使用较多的配置方式,但是对于配置Monorepos项目是比较麻烦的;
  • babel.config.json ( babel7开始 ): 可以直接作用于Monorepos项目的子包,更加推荐;

编写babel的配置文件

在项目根目录下新建babel.config.js文件,当然也可以是json后缀名,个人比较喜欢js

1
2
3
4
5
module.exports = {
presets: [
"@babel/preset-env"
]
}

回到webpack.config.js文件中重新进行配置,由于配置被抽离出去了,只需要使用loader即可

1
2
3
4
{
test: /\.js$/,
loader: "babel-loader" // 这里没写use用loader让阅读性更强
}, // 加载js所需要规则【配置项抽离版】

再次打包,发现转换成功