前言

使用版本

2020 年 10 月 10 日,Webpack 5 正式发布。

本文撰写之初,所使用版本:

  1. Webpack 5.28.0
  2. Webpack-cli 4.6.0

目录结构

以项目 2048 为例,简单划分如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
├── config                 # 配置目录
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ └── webpack.prod.js

├── dist # 编译目录
│ ├── js
│ │ └── main.js
│ ├── favicon.ico
│ └── index.html

├── src # 源码目录
│ └── index.js

├── favicon.ico

├── index.html

├── package-lock.json

└── package.json

新建项目

创建一个空的目录并进入:

1
2
mkdir 2048_game
cd 2048_game

然后进行初始化:

1
2
3
4
5
npm init

# 或全部使用默认值

npm init -y

执行初始化命令后,终端会进行一些简单问题的询问,比如项目名称、作者信息等,以此来创建 package.json 文件,后续可以在该文件内进行修改。

指令后加上 -y,表示所有选项都为 yes,全部使用默认值。

安装 webpack

webpack:核心包,包含了 webpack 构建过程中要用到的所有 api。

webpack-cli:提供一个简单的 cli 命令,它调用了 webpack 核心包的 api,来完成构建过程。

安装 webpack、webpack-cli:

1
2
3
4
5
# 全局安装
npm i webpack webpack-cli

# 局部安装
npm i webpack webpack-cli -D

命令完成后,项目中会多一个 node_modules 文件夹,用来存放项目中安装的依赖包。

补充:install 可简写为 i--save-dev 可简写为 -D

完善项目目录

三个重要目录

src:source,源码文件,用于存放我们写的源文件

dist:distribution,编译文件,用于存放之后打包的文件

config:配置文件(这个用于后面的配置文件分离)

1
mkdir config dist src

项目入口文件

根目录下:index.html

src 目录下:index.js

1
2
3
touch index.html

cd src && touch index.js

原始配置文件

回到根目录,创建配置文件 webpack.config.js

1
2
3
cd ..

touch webpack.config.js

进行配置

初次尝试

打开 webpack.config.js,先进行基本的配置:

  1. entry:入口文件
  2. output:打包后的文件名和存放目录
  3. mode:编译模式,先设置为开发环境
1
2
3
4
5
6
7
8
9
10
const path = require('path')

module.exports = {
entry: './src/index.js',
output: {
filename: 'js/main.js',
path: path.resolve(__dirname, './dist'),
},
mode: 'development',
}

好了,让我们输入打包指令来尝试一下:

1
npx webpack

编译完成,打开 dist 目录,就会发现多了一个 js 文件夹,里面就是打包输出的 man.js 文件。

devServer

接下来我们配置一个本地开发服务器,可以让浏览器进行实时刷新,查看修改结果。

安装:

1
npm i webpack-dev-server -D

webpack.config.js 中进行配置:

  1. contentBase:为哪一个文件夹提供本地服务,默认是根文件夹
  2. inline:启动页面实时刷新
  3. compress:启动 gzip 压缩,让文件更小,打开速度更快
1
2
3
4
5
6
7
8
module.exports = {
// ...
devServer: {
contentBase: './dist',
inline: true,
compress: true
}
}

启动:

1
npx webpack serve

可以看到它提供了一个本地网址:http://localhost:8080。打开该网址,就可以实时查看页面了。

注意,这个只用于开发环境方便调试,在生产环境是不需要的。

loader配置

概念

loader 主要用于转换某些类型的模块,它是一个转换器。

对于 webpack 本身的能力来说,它只能理解 JavaScript,而对于其他转化是不支持的,比如加载 css、图片,将 ES6 转成 ES5 代码等,此时就需要通过 loader 了。

配置参数:

  1. test:匹配 loaders 所处理文件的拓展名的正则表达式(必须)
  2. loader:loader 的名称(必须)
  3. include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
  4. options:为 loader 提供额外的设置选项(可选)

使用:

  1. 下载:npm 安装需要使用的 loader
  2. 配置:在 webpack.config.js 中的 module 关键字下进行配置

某个文件类型使用多个loader时,执行顺序从右往左。

样式资源

loader:css-loaderstyle-loader

如果还要使用预处理器比如 less,那就还需要 less-loaderless

作用:

  1. css-loader:将 css 文件变成 commonjs 模块加载到 js 中,里面内容是样式字符串。
  2. style-loader:创建一个 <style> 标签,将 js 中的样式资源插入进去,然后添加到 <head> 中生效。
  3. less-loader:加载和转译 less 文件。

下载:

1
2
3
4
npm i css-loader style-loader -D

# 如果还有 less 文件需处理
npm i less less-loader -D

配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
],
},
}

静态资源

webpack5 新增了资源模块类型(asset module type),通过添加 4 种新的模块类型,替换了三个 loader:

  1. asset/resource:发送一个单独的文件并导出 URL。替代了 file-loader
  2. asset/inline:导出一个资源的 data URI。替代了 url-loader
  3. asset/source:导出资源的源代码。替代了 raw-loader
  4. asset:在导出一个 data URI 和发送一个单独的文件之间自动选择:
    • 小于 8kb 的文件,将会视为 inline 模块类型
    • 否则会被视为 resource 模块类型。
    • 之前是通过使用 url-loader,并且配置资源体积限制实现。

配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg|webp)$/,
type: 'asset',
generator: {
filename: 'static/img/[hash][ext][query]',
}
},
{
test: /\.(eot|woff2?|ttf|svg)$/,
type: 'asset',
generator: {
filename: 'static/fonts/[hash][ext][query]',
}
},
],
},
}

img 标签图片

loader:html-withimg-loader

静态资源模块处理的是 cssjs 中的图片路径,但是它并不处理 html 中的图片路径。

所以我们还需要下载一个 loader 来处理。

作用:处理 html 文件的 img 图片。它负责引入图片,从而能被静态资源模块处理。

下载:

1
npm i html-withimg-loader -D

配置:

1
2
3
4
5
6
7
8
9
10
module.exports = {
module: {
rules: [
{
test: /\.html$/,
loader: 'html-withimg-loader'
}
],
},
}

js语法兼容

loader:babel-loader@babel/core@babel/preset-env

作用:用来处理 ES6 语法,将其编译为浏览器可以执行的 js 语法。

下载:

1
npm i -D babel-loader @babel/core @babel/preset-env

配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
// 预设:指示 babel 做怎样的兼容性处理
presets: ['@babel/preset-env']
}
}
}
]
}

注意:@babel/preset-env 只能转换基本语法,高级 API 比如 promise 就不能转换了。

高级语法按需加载处理:

  1. 下载开发依赖(-D):@babel/plugin-transform-runtime
  2. 下载生产依赖:@babel/runtime-corejs3
1
2
3
npm install @babel/plugin-transform-runtime -D

npm install @babel/runtime-corejs3

然后修改配置:

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
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
modules: false,
},
],
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: {
version: 3,
proposals: true,
},
useESModules: true,
},
],
],
},
},
}
]

插件配置

plugin 是对 webpack 现有功能的各种扩展,比如打包优化,文件压缩等。

打包 html 文件

目前我们的 index.html 文件是存放在项目的根目录下的。

在真实发布项目时,发布的是 dist 文件夹中的内容,但是现在 dist 文件夹中还没有 index.html 文件,所以我们需要先把它打包进来。

作用:

  1. 自动生成一个 index.html 文件
  2. 将打包的 js 文件,自动通过 script 标签插入到 body

安装:

1
npm i html-webpack-plugin -D

配置:

  1. template:根据什么模板来生成 index.html 文件。
  2. favicon:网站的 icon。
1
2
3
4
5
6
7
8
9
10
11
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
favicon: 'favicon.ico'
})
],
}

网站图标 favicon 文件需放在根目录下,不需要在源文件里引入,它会自动寻找并打包。

重新打包:

1
npx webpack

然后打开 dist 文件夹,就可以看到多出来一个 index.htmlfavicon.ico文件了。

自动清理 dist 目录

之后每次构建都会重新进行打包,所以需要先清除旧文件,再生成新文件。

安装:

1
npm i clean-webpack-plugin -D

配置:

1
2
3
4
5
6
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
// ...
plugins: [new CleanWebpackPlugin()]
}

以后每次打包之前,都会先删除旧文件。

优化输出日志

打包编译时,很大一部分输出信息是无效信息,所以可以通过插件进行优化,让终端看起来更简洁明了。

安装:

1
npm i @soda/friendly-errors-webpack-plugin -D

配置:

  1. devServer 中增加:quiet: true
  2. 增加 stats 属性,让日志只在报错时显示
1
2
3
4
5
6
7
8
9
10
11
12
13
const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin')

module.exports = {
// ...
plugins: [
new FriendlyErrorsWebpackPlugin({}),
],
devServer: {
// ...
quiet: true,
},
stats: 'errors-only',
}

最后

以上就是使用 webpack5 搭建一个项目的基本配置了,后续还有进阶配置,比如生产环境和开发环境的分离,还有不同环境下的优化配置,我们在下篇文章继续讨论。