webpack

本质上,webpack是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

静态模块:指的是编写代码过程中的,html,css,js,图片等固定内容的文件

为什么要使用webpack

开发时,我们会使用框架(React、Vue),ES6模块化语法,Less/sass 等 css 预处理器等语法进行开发。
这样的代码要想在浏览器运行必须经过编译成浏览器能识别的JS、Css 等语法,才能运行。
所以我们需要打包工具帮我们做完这些事。
除此之外,打包工具还能压缩代码、做兼容性处理、提升代码性能等。

使用webpack

资源目录

1
2
3
4
5
6
webpack_code # 项目根目录(所有指令必须在这个目录运行)
└── src # 项目源码目录
├── js # js文件目录
│ ├── count.js
│ └── sum.js
└── main.js # 项目主文件

创建测试代码文件

根目录下创建src文件夹,创建如下两个js文件

1
2
3
4
// src/sub.js
export function sub(x, y) {
return x - y
}
1
2
3
4
// src/sum.js
export function sum(arr) {
return arr.reduce((sum, item) => sum + item, 0)
}

创建main.js文件

1
2
3
4
5
6
// main.js
import {sub} from './src/sub'
import {sum} from './src/sum'

console.log(sub(2,1))
console.log(sum([1,2,3,4]))

下载相关依赖

打开终端,初始化package.json

1
npm init -y

需要注意的是 package.jsonname 字段不能叫做 webpack, 否则下一步会报错

安装webpack依赖

1
npm i webpack webpack-cli -D

启用 Webpack

  • 开发模式
1
npx webpack ./main.js --mode=development
  • 生产模式
1
npx webpack ./main.js --mode=production

npx webpack: 是用来运行本地安装 Webpack 包的。

./main.js: 指定 Webpackmain.js 文件开始打包,不但会打包 main.js,还会将其依赖也一起打包进来。

--mode=xxx:指定模式(环境)。

观察输出文件

默认 Webpack 会将文件打包输出到 dist 目录下,我们查看 dist 目录下文件情况就好了

webpack的基本配置

五大核心概念

  1. entry(入口)
    • 指示 Webpack 从哪个文件开始打包
  2. output(输出)
    • 指示 Webpack 打包完的文件输出到哪里去,如何命名等
  3. loader(加载器)
    • webpack 本身只能处理 js、json 等资源,其他资源需要借助 loader,Webpack 才能解析
  4. plugins(插件)
    • 扩展 Webpack 的功能
  5. mode(模式)主要由两种模式:
    • 开发模式:development
    • 生产模式:production

配置文件

在项目根路径下创建配置文件webpack.config.js,内容如下

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "main.js",
},
// 加载器
module: {
rules: [],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

运行打包命令

1
npx webpack

开发模式介绍

开发模式顾名思义就是我们开发代码时使用的模式。

这个模式下我们主要做两件事:

  1. 编译代码,使浏览器能识别运行

    开发时我们有样式资源、字体图标、图片资源、html 资源等,webpack 默认都不能处理这些资源,所以我们要加载配置来编译这些资源

  2. 代码质量检查,树立代码规范

    提前检查代码的一些隐患,让代码运行时能更加健壮。

    提前检查代码规范和格式,统一团队编码风格,让代码更优雅美观。

处理样式资源

建议去官方文件寻找loader使用

css-loader文档地址:css-loader | webpack 中文文档 | webpack中文文档 | webpack中文网 (webpackjs.com)

处理css资源

下载loader包

1
npm i css-loader style-loader -D

功能介绍

  • css-loader:负责将 Css 文件编译成 Webpack 能识别的模块
  • style-loader:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "main.js",
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

添加css资源

webpack会入口文件找引用了什么资源,将引用的资源进行打包

所以我们如果想要看到css资源被打包,需要在入口文件引入这个css

1
2
3
4
5
.box {
width: 100px;
height: 100px;
background-color: red;
}

创建一个css文件,添加一些样式,然后在main.js中引入

执行打包命令

1
npx webpack

处理less资源

less-loader文档地址:less-loader | webpack 中文文档 | webpack中文文档 | webpack中文网 (webpackjs.com)

下载loader包

1
npm install less less-loader --save-dev

功能介绍

  • less-loader:负责将 Less 文件编译成 Css 文件

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "main.js",
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

添加less资源

1
2
3
4
5
.box2 {
width: 100px;
height: 100px;
background-color: pink;
}

执行打包命令

1
npx webpack

处理Sass Scss资源

下载包

1
npm i sass-loader sass -D

功能介绍

  • sass-loader:负责将 Sass 文件编译成 css 文件
  • sasssass-loader 依赖 sass 进行编译

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "main.js",
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

添加Sass Scss资源

1
2
3
4
.box3
width: 100px
height: 100px
background-color: yellow
1
2
3
4
5
.box4 {
width: 100px;
height: 100px;
background-color: pink;
}

执行打包命令

1
npx webpack

处理stylus资源

下载包

1
npm i stylus-loader -D

功能介绍

  • stylus-loader:负责将 Styl 文件编译成 Css 文件

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "main.js",
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

添加资源

1
2
3
4
.box5
width 100px
height 100px
background-color beige

执行打包命令

1
npx webpack

处理图片资源

过去在 Webpack4 时,我们处理图片资源通过 file-loaderurl-loader 进行处理

现在 Webpack5 已经将两个 Loader 功能内置到 Webpack 里了,我们只需要简单配置即可处理图片资源

配置

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
const path = require("path");

module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
},
],
},
plugins: [],
mode: "development",
};

输出资源情况输出资源情况

此时如果查看 dist 目录的话,会发现多了三张图片资源

因为 Webpack 会将所有打包好的资源输出到 dist 目录下

  • 为什么样式资源没有呢?

因为经过 style-loader 的处理,样式资源打包到 main.js 里面去了,所以没有额外输出出来

对图片资源进行优化对图片资源进行优化

将小于某个大小的图片转化成 data URI 形式(Base64 格式)

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
const path = require("path");

module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
}
},
],
},
plugins: [],
mode: "development",
};
  • 优点:减少请求数量
  • 缺点:体积变得更大

此时输出的图片文件就只有两张,有一张图片以 data URI 形式内置到 js 中了 (注意:需要将上次打包生成的文件清空,再重新打包才有效果)

修改输出文件的目录

配置如下:

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
}
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

打包自动清空上次打包资源

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
}
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

处理字体图标资源

添加字体资源

image-20240829165931924

配置

type: "asset/resource"type: "asset"的区别:

  1. type: "asset/resource" 相当于file-loader, 将文件转化成 Webpack 能识别的资源,其他不做处理
  2. type: "asset" 相当于url-loader, 将文件转化成 Webpack 能识别的资源,同时小于某个大小的资源会处理成 data URI 形式
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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
],
},
// 插件
plugins: [],
// 模式
mode: "development", // 开发模式
};

处理其他资源

在处理字体图标资源基础上增加其他文件类型,统一处理即可

处理JS资源

有人可能会问,js 资源 Webpack 不能已经处理了吗,为什么我们还要处理呢?

原因是 Webpack 对 js 处理是有限的,只能编译 js 中 ES 模块化语法,不能编译其他语法,导致 js 不能在 IE 等浏览器运行,所以我们希望做一些兼容性处理。

其次开发中,团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业的工具来检测。

  • 针对 js 兼容性处理,我们使用 Babel 来完成
  • 针对代码格式,我们使用 Eslint 来完成

我们先完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理

Eslint

可组装的 JavaScript 和 JSX 检查工具。

这句话意思就是:它是用来检测 js 和 jsx 语法的工具,可以配置各项功能

我们使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查

配置文件

配置文件由很多种写法:

  • .eslintrc.*:新建文件,位于项目根目录
    • .eslintrc
    • .eslintrc.js
    • .eslintrc.json
    • 区别在于配置格式不一样
  • package.jsoneslintConfig:不需要创建文件,在原有文件基础上写

ESLint 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

具体配置

我们以 .eslintrc.js 配置文件为例:

1
2
3
4
5
6
7
8
9
10
module.exports = {
// 解析选项
parserOptions: {},
// 具体检查规则
rules: {},
// 继承其他规则
extends: [],
// ...
// 其他规则详见:https://eslint.bootcss.com/docs/user-guide/configuring
};
parserOptions 解析选项
1
2
3
4
5
6
7
parserOptions: {
ecmaVersion: 6, // ES 语法版本
sourceType: "module", // ES 模块化
ecmaFeatures: { // ES 其他特性
jsx: true // 如果是 React 项目,就需要开启 jsx 语法
}
}
rules 具体规则
  • "off"0 - 关闭规则
  • "warn"1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error"2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
1
2
3
4
5
6
7
8
9
10
11
12
rules: {
semi: "error", // 禁止使用分号
'array-callback-return': 'warn', // 强制数组方法的回调函数中有 return 语句,否则警告
'default-case': [
'warn', // 要求 switch 语句中有 default 分支,否则警告
{ commentPattern: '^no default$' } // 允许在最后注释 no default, 就不会有警告了
],
eqeqeq: [
'warn', // 强制使用 === 和 !==,否则警告
'smart' // https://eslint.bootcss.com/docs/rules/eqeqeq#smart 除了少数情况下不会有警告
],
}

更多规则详见:规则文档open in new window

extends 继承

开发中一点点写 rules 规则太费劲了,所以有更好的办法,继承现有的规则。

现有以下较为有名的规则:

1
2
3
4
5
6
7
8
9
// 例如在React项目中,我们可以这样写配置
module.exports = {
extends: ["react-app"],
rules: {
// 我们的规则会覆盖掉react-app的规则
// 所以想要修改规则直接改就是了
eqeqeq: ["warn", "smart"],
},
};

在webpack中使用

下载包
1
npm i eslint-webpack-plugin eslint -D
定义配置文件

.eslintrc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
// 继承 Eslint 规则
extends: ["eslint:recommended"],
env: {
node: true, // 启用node中全局变量
browser: true, // 启用浏览器中全局变量
},
parserOptions: {
ecmaVersion: 6,
sourceType: "module",
},
rules: {
"no-var": 2, // 不能使用 var 定义变量
},
};
配置webpack
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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "src"),
}),
],
// 模式
mode: "development", // 开发模式
};
vscode eslint插件

打开 VSCode,下载 Eslint 插件,即可不用编译就能看到错误,可以提前解决

但是此时就会对项目所有文件默认进行 Eslint 检查了,我们 dist 目录下的打包后文件就会报错。但是我们只需要检查 src 下面的文件,不需要检查 dist 下面的文件。

所以可以使用 Eslint 忽略文件解决。在项目根目录新建下面文件:

  • .eslintignore
1
2
# 忽略dist目录下所有文件
dist

Babel

js编译器,主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中

配置文件

配置文件由很多种写法:

  • babel.config.*:新建文件,位于项目根目录
    • babel.config.js
    • babel.config.json
  • .babelrc.*:新建文件,位于项目根目录
    • .babelrc
    • .babelrc.js
    • .babelrc.json
  • package.jsonbabel:不需要创建文件,在原有文件基础上写

Babel 会查找和自动读取它们,所以以上配置文件只需要存在一个即可

具体配置

我们以 babel.config.js 配置文件为例:

1
2
3
4
module.exports = {
// 预设
presets: [],
};
presets 预设

简单理解:就是一组 Babel 插件, 扩展 Babel 功能

  • @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
  • @babel/preset-react:一个用来编译 React jsx 语法的预设
  • @babel/preset-typescript:一个用来编译 TypeScript 语法的预设

在 Webpack 中使用

下载包
1
npm i babel-loader @babel/core @babel/preset-env -D
定义 Babel 配置文件

babel.config.js

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

配置webpack.config.js

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "./src"),
}),
],
// 模式
mode: "development", // 开发模式
};

处理HTML资源

下载包

1
npm i html-webpack-plugin -D

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "./src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "./public/index.html"),
}),
],
// 模式
mode: "development", // 开发模式
};

开发服务器&自动化

每次写完代码都需要手动输入指令才能编译代码,太麻烦了,我们希望一切自动化

下载包

1
npm i webpack-dev-server -D

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "./src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "./public/index.html"),
}),
],
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
// 模式
mode: "development", // 开发模式
};

运行指令启动服务器

1
npx webpack serve

注意运行指令发生了变化

并且当你使用开发服务器时,所有代码都会在内存中编译打包,并不会输出到 dist 目录下。

开发时我们只关心代码能运行,有效果即可,至于代码被编译成什么样子,我们并不需要知道。

生产模式介绍

生产模式是开发完成代码后,我们需要得到代码将来部署上线。

这个模式下我们主要对代码进行优化,让其运行性能更好。

优化主要从两个角度出发:

  1. 优化代码运行性能
  2. 优化代码打包速度

生产模式准备

我们分别准备两个配置文件来放不同的配置

1
2
3
4
5
6
7
8
9
10
11
12
├── webpack-test (项目根目录)
├── config (Webpack配置文件目录)
│ ├── webpack.dev.js(开发模式配置文件)
│ └── webpack.prod.js(生产模式配置文件)
├── node_modules (下载包存放目录)
├── src (项目源码目录,除了html其他都在src里面)
│ └── 略
├── public (项目html文件)
│ └── index.html
├── .eslintrc.js(Eslint配置文件)
├── babel.config.js(Babel配置文件)
└── package.json (包的依赖管理配置文件)

修改 webpack.dev.js

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: undefined,// 开发模式没有输出,不需要指定目录
// filename: 输出文件名
filename: "static/js/main.js",
// clean: true, // 开发模式没有输出,不需要清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
],
// 开发服务器
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
// 模式
mode: "development", // 开发模式
};

运行开发模式的指令

1
npx webpack serve --config ./config/webpack.dev.js

修改 webpack.prod.js

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "../dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
'style-loader',
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
],
// 模式
mode: "production", // 开发模式
};

运行生产模式的指令

1
npx webpack --config ./config/webpack.prod.js

配置运行指令

为了方便运行不同模式的指令,我们将指令定义在 package.json 中 scripts 里面

1
2
3
4
5
6
7
8
9
// package.json
{
// 其他省略
"scripts": {
"start": "npm run dev",
"dev": "npx webpack serve --config ./config/webpack.dev.js",
"build": "npx webpack --config ./config/webpack.prod.js"
}
}

以后启动指令:

  • 开发模式:npm startnpm run dev
  • 生产模式:npm run build

CSS处理

提取CSS成单独的文件

Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式

这样对于网站来说,会出现闪屏现象,用户体验不好

我们应该是单独的 Css 文件,通过 link 标签加载性能才好

下载包

1
npm i mini-css-extract-plugin -D

配置

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
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "../dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
// 模式
mode: "production", // 开发模式
};

运行命令

1
npx webpack --config ./config/webpack.prod.js

css兼容性处理

下载包

1
npm i postcss-loader postcss postcss-preset-env -D

配置

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "../dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
],// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: [
// compiles Less to CSS
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
'less-loader',
],
},
{
test: /\.s[ac]ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
"sass-loader"
],
},
{
test: /\.styl$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
"stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
// 模式
mode: "production", // 开发模式
};

合并配置

可以通过封装函数的方式来简化重复的配置

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
109
110
111
112
113
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
preProcessor,
].filter(Boolean);
};


module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "../dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: getStyleLoaders(),// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
// 模式
mode: "production", // 开发模式
};

设置兼容性

我们可以在 package.json 文件中添加 browserslist 来控制样式的兼容性做到什么程度。

1
2
3
4
{
// 其他省略
"browserslist": ["ie >= 8"]
}

想要知道更多的 browserslist 配置,查看browserslist 文档open in new window

以上为了测试兼容性所以设置兼容浏览器 ie8 以上。

实际开发中我们一般不考虑旧版本浏览器了,所以我们可以这样设置:

1
2
3
4
{
// 其他省略
"browserslist": ["last 2 version", "> 1%", "not dead"]
}

执行打包命令

1
npm run build

CSS压缩

下载包

1
npm i css-minimizer-webpack-plugin -D

配置

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
109
110
111
112
113
114
115
116
// Node.js的核心模块,专门用来处理文件路径
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

// 获取处理样式的Loaders
const getStyleLoaders = (preProcessor) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
preProcessor,
].filter(Boolean);
};


module.exports = {
// 入口
// 相对路径和绝对路径都行
entry: "./main.js",
// 输出
output: {
// path: 文件输出目录,必须是绝对路径
// path.resolve()方法返回一个绝对路径
// __dirname 当前文件的文件夹绝对路径
path: path.resolve(__dirname, "../dist"),
// filename: 输出文件名
filename: "static/js/main.js",
clean: true, // 自动将上次打包目录资源清空
},
// 加载器
module: {
rules: [
{
test: /\.css$/i,
use: getStyleLoaders(),// 执行loader的顺序是从又往左
},
{
test: /\.less$/i,
// loader: "less-loader", loader这种配置方式只能配置一个加载器
// use这种配置方式可以配置多个
use: getStyleLoaders('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders('sass-loader'),
},
{
test: /\.styl$/,
use: getStyleLoaders('stylus-loader'),
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb的图片会被base64处理
}
},
generator: {
// 将图片文件输出到 static/imgs 目录中
// 将图片文件命名 [hash:8][ext][query]
// [hash:8]: hash值取8位
// [ext]: 使用之前的文件扩展名
// [query]: 添加之前的query参数
filename: "static/imgs/[hash:8][ext][query]",
}
},
// 处理字体资源
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
// 插件
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
}),
new HtmlWebpackPlugin({
// 以 public/index.html 为模板创建文件
// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
// css压缩
new CssMinimizerPlugin()
],
// 模式
mode: "production", // 开发模式
};

执行打包命令

1
npm run build

html 压缩

默认生产模式已经开启了:html 压缩和 js 压缩

不需要额外进行配置