简介

webpack 是代码编译工具,有入口、出口、loader 和插件。webpack 是一个用于现代JavaScript应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle

参考资料

简介安装配置

简介

  • webpack 是一个模块打包器(构建工具)。它的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)或包裹(package)任何资源(resource or asset)。
  • 官网: https://webpack.js.org/
  • 中文文档:https://webpack.docschina.org/

官网简介图

webpack原理和概念

  • 树结构: 在一个入口文件中引入所有资源,形成所有依赖关系树状图
  • 模块:模块就是模块可以是ES6模块也可以是commonJS或者AMD模块,对于webpack来说,所有的资源(css,img…)
  • chunk:打包过程中被操作的模块文件叫做chunk,例如异步加载一个模块就是一个chunk
  • bundel:bundle是最后打包后的文件,最终文件可以和chunk长的一模一样,但是大部分情况下他是多个chunk的集合
  • 为了优化最后生产出的bundle数量可能不等于chunk的数量,因为有可能多个chunk被组合到了一个Bundle中。

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
graph LR
A(webpack工作原理) -->B1[png]
A-->B2[JPG]
A-->B3[CSS]
A-->B4[JS]
B[chuck为打包过程bundle为打包结果]
subgraph 资源
B1 --> A1((A1))
B1 --> A2((A2))
B2 -->A3((B1))
B2 -->A4((B1))
end
subgraph 代码
B3
B4
end
subgraph dist
main.js
end
A1 -->|chuck1| bundle1-->main.js
A2 --> |chuck1|bundle1
A3 -->|chuck1| bundle1
A4 --> |chuck1|bundle1

A4 --> |chuck2|bundle2-->main.js
B3 --> |chuck2|bundle2
B4 --> |chuck2|bundle2

webpack环境安装

1
2
3
4
5
6
7
8
#安装webpack、webpack-cli至开发环境 i=install -D=--save-dev 注意看看pack.json webpack版本5+ webpack-cli4+
sudo npm i webpack webpack-cli -D -g
sudo yarn add webpack webpack-cli -D -g
webpack -v
#打包 --mode指定模式 development开发模式(文件较大,包含注释等信息),production生产模式(无注释,无空格全部在一行) 最终会在生成dist文件夹下有个main.js
#生成模式打包后的文件更小,里面也没有多余的说明和注释等信息,默认是打包 src 下的文件,如果没有该文件夹会报错
webpack --mode development
webpack --mode production

webpack基础配置

  • 项目根目录下,新建webpack.config.js文件(就用这个名字,换其它的名字需要在执行 webpack 命令的时候重新指定一遍,默认会读取这个名字的文件不需要指定)
  • 该文件为执行 webpack 命令默认读取的配置文件
  • webpack默认打包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
//node中的包,可获取当前项目的根路径
const {resolve} = require("path");

// webpack 的核心有五个: 1.entry 入口 2.output 输出 3.loader 4.plugin 插件 5.module
module.exports = {
// entry指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的.默认值是 ./src/index.js,入口配置3选一
//单入口:如果只有一个入口文件,使用字符串指定入口文件,打包一个chunk,名称是默认的(output中的filename的值build.js)输出一个bundle
entry: "./src/main.js",
//多入口:Array数组可多个入口文件,所有的入口文件生成一个chunk,名称是默认的(output中的filename的值build.js)输出一个bundle
entry:["./src/main.js","./src/index.js"],
//多入口:Object对象,通过Key:Value,配置多个入口,有几个入口文件就有几个chunk,并输出几个bundle,chunk的名称是key(output中的filename的值要写成"[name].js")
entry:{
test:'./src/one.js',
index:'./src/index.js',
main:'./src/main.js'
}
//混合模式
entry:{
//Array数组的多个打成1个test,其它的单独生成一个,filename的值还是写成[name].js
test:["./src/main.js","./src/index.js"],
index:'./src/index.js',
main:'./src/main.js'
}
// output告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹
output: {
//如果entry是object时,filename的值要写成"[name].js"
filename: "[name].js",
path: resolve(__dirname,"build")
},
// loader webpack 只能理解 JavaScript 和 JSON 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中
module: {
rules: []
},
//plugin loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
plugins: [],
//模式(mode)指示webpack使用相应的配置,开发模式(development):配置比较简单,能让代码本地调试运行的环境 生产模式(production):代码需要不断优化达到性能最好,能让代码优化上线运行的环境
//都会自动启用一些插件,生产模式使用插件更多
mode: "development",
// mode: "production",
}

html资源打包配置

由于webpack默认只能打包js资源,我们想要打包html资源需要在开发环境安装html-webpack-plugin插件

插件安装

插件3大步骤:

1.下载 npm i html-webpack-plugin -D

2.引入 const htmlWebpackPlugin = require(‘html-webpack-plugin’);

3.使用 new htmlWebpackPlugin();

1
2
3
4
#方式一:npm安装插件
npm i html-webpack-plugin -D
#方式二:yarn安装插件
yarn add html-webpack-plugin -D

配置webpack.config.js文件

  • 打包 html 文件
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
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
// webpack 的核心有五个: 1.entry 入口 2.output 输出 3.loader 4.plugin 插件 5.module
module.exports = {
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: []
},
entry: './src/index.js',
//plugin loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
plugins: [
//默认会创建一个空的,会自动引入 js 文件
new htmlWebpackPlugin(
{
//源文件(不指定template 就会自动生成一个空的 html 文件)
template: "./src/index.html",
//目标文件名(不指定filename 就会使用 template 的文件作为文件名,如果template也没有指定就会使用系统默认的 index.html)
filename: "demo.html",
// 压缩
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
}
)
],
mode: "development",
}

分开打包 html 文件

  • 不同的 html 文件需要引入不同的 js 文件,因此需要对不同的 js 文件分别或组合打包成一个bundle,在不同的页面中引用
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
//模拟真实打包
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: "development",

entry: {
// 将 common 和 jquery 依赖打包在一起,剩下的两个单独打包在一起
vendor: ['./src/js/common.js', 'jquery'],
index: "./src/js/index.js",
cart: "./src/js/cart.js"
},

output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: []
},

//plugin loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
plugins: [
new htmlWebpackPlugin({
//源文件(不指定template 就会自动生成一个空的 html 文件)
template: "./src/view/index.html",
//目标文件名(不指定filename 就会使用 template 的文件作为文件名,如果template也没有指定就会使用系统默认的 index.html)
filename: "demo.html",
chunks: ['index','vendor'], // chunks 中的值为 entry 中的键,多个bundle之间有依赖关系,从右往左写,数组中最后一个最先引入
// 压缩
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
}),
new htmlWebpackPlugin({
template: "./src/view/cart.html",
filename: "demo2.html",
chunks: ['cart','vendor'],
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
})
]

}

分别打包 html

css资源打包

内联打包

  • 实现原理:先用css-loader把 css 样式打包到 js 的一个bundle 然后用style-loader创建了一个>标签引入样式,属于内联式打包
  • 开发环境安装插件:css-loader style-loader
    • css-loader:把css资源打包捆绑到js文件中(作用是处理css中的 @import 和 url 这样的外部资源)
    • style-loader:把css加载引入到html中(作用是把样式插入到 DOM中,方法是在head中插入一个style标签,并把样式写入到这个标签的 innerHTML里)
1
2
3
4
#方式一:npm 安装插件
npm i css-loader style-loader -D
#方式二:yarn 安装插件
yarn add css-loader style-loader -D

css资源打包到html

  • webpack配置module标签
  • 打包的 js 导入css文件(import/require)

    1
    2
    3
    4
    5
    //打包index的时候会通过css-loder把css打到index.js中
    require('./style.css')
    require('./lessstyle.less')
    require('./sassstyle.scss')
    console.log("这是入口文件");

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
//打包 css
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [{
// 两个斜杠表示正则,中间的.css$表示所有的.css结尾的文件 "\"是用来转移"."的
test:/\.css$/,
//注意顺序,一定是style-loader在css-loader的左边,因为加载规则的时候是从右边到左
//1.通过css-loader把正则中的(这里也就是所有的css文件)打包到js中
//2.打包后再通过style-loader把这些插入到html中
use: ['style-loader','css-loader']
}]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
})
]

}

css 样式打包到 html

Less/Sass资源打包

  • 因为css只是单纯的属性描述,它并不具有变量、条件语句等,css的特性导致了它难组织和维护。
  • Sass和Less都属于CSS预处理器,定义了一种新的语言,其基本思想是用一种专门的编程语言,为
  • CSS增加一些编程的特性,将CSS作为目标生成文件,然后开发者使用这种语言进行CSS编码工作.
  • Less需要使用npm下载less包和less- loader
  • Sass需要使用npm下载node-sass包和sass- loader
  • 需要在打包的 js 文件中引如 less sass

插件安装

1
2
3
4
5
6
#Less的插件(开发环境)
npm i less less-loader -D
yarn add less less-loader -D
#Sass的插件(开发环境)
npm i node-sass sass-loader -D
yarn add node-sass sass-loader -D

webpack.config.js配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module: {
rules: [
{
// 两个斜杠表示正则,中间的.css$表示所有的.css结尾的文件 "\"是用来转移"."的
test: /\.css$/,
//注意顺序,一定是style-loader在css-loader的左边,因为加载规则的时候是从右边到左
//1.通过css-loader把正则中的(这里也就是所有的css文件)打包到js中
//2.打包后再通过style-loader把这些插入到html中
use: ['style-loader', 'css-loader']
},
//先通过less-loader转成css,然后通过css-loader打包到入口文件js中,style-loader插入到html中,顺序从后往前
{test: /\.less$/,use: ['style-loader', 'css-loader','less-loader']},
//sass原理一致,只是文件后缀名称是scss,所以正则的时候别写错了
{test: /\.scss$/,use: ['style-loader', 'css-loader', 'sass-loader']
}
]
},

less/sass 语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//less语法
//全局变量用@符号定义和引用
@color: red;
@background: yellow;
@width: 200px;
@height: 300px;
#lessBox {
//局部变量
color: @color;
width: @width*0.5;
height: @height*0.33333;
background: @background;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//sass语法
// sass 样式是以 scss 结尾的文件 定义变量用 $
//全局变量用$符号定义和引用
$color: blue;
$background: black;
$width: 200px;
$height: 300px;
#sassBox {
//局部变量
color: $color;
width: $width*0.8;
height: $height*0.5;
background: $background;

}

单独打包样式文件

把less,sass,css等资源打包成一个独立的资源文件

下载插件

插件3大步骤:

1.下载 npm i mini-css-extract-plugin -D

2.引入 const miniCssExtractPlugin = require(‘mini-css-extract-plugin’);

3.使用 new miniCssExtractPlugin()

1
2
3
4
# npm 下载
npm i mini-css-extract-plugin -D
# yarn 下载
yarn add mini-css-extract-plugin -D

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
//将css less sass 资源 单独打包 成独立的文件 不嵌入在 js 中
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
// 将 style-loader 换成 MiniCssExtractPlugin.loader
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],}
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
}),
new MiniCssExtractPlugin({
//指定单独打包的 css 文件的路径和文件名 output标签的 path 下的 ./css/demo.css
filename:'./css/demo.css'})
]

}

css兼容性处理

  • 通过插件确保所有的css样式中的属性在所有类型的浏览器大多数浏览器的大多数版本都支持,且显示效果一致
  • 需要使用postcss处理,下载两个包postcss-loader和postcss-preset-env
  • posters会找到 package json中的 browserslist里面的配置,通过配置加载css的兼容性
  • 修改loader的配置, 新版需要写postcss.config.js, less和sass兼容性同理

兼容转换效果

插件安装

1
2
3
4
# npm 安装postcss-loader,postcss-preset-env 安装至开发环境
npm i postcss-loader postcss-preset-env -D
# yarn 安装
yarn add postcss-loader postcss-preset-env -D

配置文件

  • 需要新建 postcss.config.js文件、package.json中新增 browserslist 标签、webpack.config.js中使用 postcss-loader

新建 postcss 配置文件

  • 项目根路径新建 postcss.config.js 文件,该文件为 postcss 的默认配置文件
1
2
3
4
5
6
// postcss 配置文件,该配置文件引入 postcss-preset-env 插件-->该插件会读取 package.json文件下的 browserslist
module.exports ={
plugins: [
require('postcss-preset-env')()
]
}

package.json文件配置信息

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
{
"devDependencies": {
"css-loader": "^6.6.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.5.3",
"node-sass": "^7.0.1",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.3.3",
"sass-loader": "^12.4.0",
"style-loader": "^3.3.1",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"jquery": "^3.6.0"
},
"browserslistcomment": "支持80%以上的浏览器,支持最后两个版本,忽略已经死掉的浏览器",
"browserslist": [
"> 0.2%",
"last 2 version",
"not dead"
]
}

webpack.config.js配置

  • 执行 webpack 打包时如果 less scss 文件中有注释会出现如下截图报错,删除注释即可

less 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
//解决css less sass 兼容问题
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
// 'css/less/sass-loader' 后新增 'postcss-loader' (postcss-loader 会去找到对应的配置文件 postcss.config.js--->package.json下的browserslist属性)
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader','postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader','postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader','postcss-loader'],}
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true, // 移除空格(结构中的空格,文字间的还是保留的)
removeComments: true // 移除注释
}
}),
new MiniCssExtractPlugin({
//指定单独打包的 css 文件的路径和文件名 output标签的 path 下的 ./css/demo.css
filename:'./css/demo.css'})
]

}

压缩 css

  • 下载插件 optimize-css-assets-webpack-plugin
  • 引入插件:const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
  • 使用插件: plugins: [ new OptimizeCssAssetsWebpackPlugin() ]

下载插件

1
2
3
4
# npm 引入插件(开发环境)
npm i optimize-css-assets-webpack-plugin -D
# yarn 引入插件(开发环境)
yarn add optimize-css-assets-webpack-plugin -D

webpack.config.js 配置

  • 引入:const OptimizeCssAssetsWebpackPlugin = require(‘optimize-css-assets-webpack-plugin’);
  • 创建对象:new OptimizeCssAssetsWebpackPlugin()
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
//压缩 css
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader','postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader','postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader','postcss-loader'],}
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename:'./css/demo.css'}),
// 用于压缩 css 的,开发环境下可以先不要压缩,不然格式不太好看
new OptimizeCssAssetsWebpackPlugin()
]

}

图片资源打包

css中引入图片

实现方式

  • webpack4 需要用 file-loader url-loader 这两个插件(需要下载)
  • webpack5 直接使用 assets-module 因为在v5url-loader已经被废弃(该模块不需要下载)

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
//打包图片资源(css html中引入)
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', 'postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', 'postcss-loader'],},
//打包图片的规则配置,只有一个 loader 可以直接写,不用写在 use 里面
{
test: /\.(jpg|png|gif|jpeg)$/,
type: "asset",
//解析
parser: {
dataUrlCondition: {
maxSize: 25 * 1024, // 超过25kb不转base64
}
},
generator: {
//文件生成路径及规则(超出 maxSize 的会在output标签下的 path下,也就是自己定义的 build 下生成 img/文件名.hash值.图片后缀)
filename: 'img/[name].[hash:6][ext]',
},
},
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: './css/demo.css'
}),
// 用于压缩 css 的,开发环境下可以先不要压缩,不然格式不太好看
new OptimizeCssAssetsWebpackPlugin()
]

}

图片资源打包

html中引入图片

实现方式

  • 使用 html-loader 插件实现
1
2
3
4
# npm 安装(开发环境)
npm i html-loader -i
# yarn 安装(开发环境)
yarn add html-loader -D

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
//打包图片资源(css html中引入)
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', 'postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', 'postcss-loader'],},
//打包图片的规则配置,只有一个 loader 可以直接写,不用写在 use 里面
{
test: /\.(jpg|png|gif|jpeg)$/,
type: "asset",
//解析
parser: {
dataUrlCondition: {
//超过25kb不转base64
maxSize: 25 * 1024,
}
},
generator: {
//文件生成路径及规则(超出 maxSize 的会在output标签下的 path下,也就是自己定义的 build 下生成 img/文件名.hash值.图片后缀)
filename: 'img/[name].[hash:6][ext]',
},
},
{test: /\.html$/,loader:'html-loader',} // html中引入的图片打包
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: './css/demo.css'
}),
// 用于压缩 css 的,开发环境下可以先不要压缩,不然格式不太好看
new OptimizeCssAssetsWebpackPlugin()
]

}

html中引入图片

打包其它资源

  • 不需要优化和压缩处理,直接输出的资源,称为其他资源,如字体

字体icon资源打包

流程

  • iconfont 图标库下载对应的资源后将【.css .ttf .woff .woff2】文件 copy 至项目下
  • 入口 js 中引入 iconfont.css require('../font/iconfont.css')
  • webpack5 直接使用 asset/resource 模块(无需下载)
  • webpack 配置 asset/resource 规则

下载及 copy 字体文件

下载字体到项目中

入口 js 中引入 iconfont

  • 在入口 js 文件中引入 iconfont.css 文件
  • require('../font/iconfont.css')

入口文件引入iconfont.css

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
//打包字体资源
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', 'postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', 'postcss-loader'],},
{
test: /\.(jpg|png|gif|jpeg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 25 * 1024,
}
},
generator: {
filename: 'img/[name].[hash:6][ext]',
},
},
{test: /\.html$/,loader:'html-loader',}, // html中引入的图片打包
//打包字体资源
{
test:/\.ttf|eot|woff2?$/,
type:"asset/resource",
generator:{
filename:"font/[name].[hash:6][ext]"
}

},
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: './css/demo.css'
}),
new OptimizeCssAssetsWebpackPlugin()
]

}

打包字体效果

eslint

简介

  • eslint 是一个开源的 js 代码检查工具,初衷是为了让程序员可以创建自己的检测规则。实际生产中,团队内往往会制订一套统一的标准,让整个团队的编码风格达到一致
  • eslint 其实与 webpack 没有任何关系,两者并不互相依赖,甚至一般情况下我们并不会在 webpack 中进行 eslint 的配置,可以单独使用。
  • 语法检查使用eslint-loader, 并基于eslint包,只用来检查js语法。(eslint-loader –> eslint-webpack-plugin )
  • 注意只检查自己写的js源代码, 第三方库是不用检查的, 可以在npmjs.com中查看规则。
  • 需要使用js来的规则库来检查代码 “airbnb”, 需要eslint-config-airbnb-base和eslint-plugin-import 两个包
  • eslin进行检查需要依赖eslint-loader,同时告诉它用什么标准去检查 常用的就是 airbnb airbnb 又依赖 eslint-config-airbnb-base和eslint-plugin-import 两个包

安装插件包

  • 有很多视频在使用 eslint-loader 我在 webpack5.68.0 使用时会有如下报错,网上说 eslint-loader 已经弃用了 采用 eslint-webpack-plugin 插件

    Module build failed (from ./node_modules/eslint-loader/dist/cjs.js):

    TypeError: Cannot read properties of undefined (reading ‘getFormatter’)

1
2
3
4
# npm 安装(开发环境)
npm i eslint eslint-config-airbnb-base eslint-plugin-import eslint-webpack-plugin -D
# yarn 安装(开发环境)
yarn add eslint eslint-config-airbnb-base eslint-plugin-import eslint-webpack-plugin -D
  • 如果在安装的插件的时候有提示 Expected version “^12.22.0 || ^14.17.0 || >=16.0.0” ,需要更换 node 版本
  • 我是在 node 官网下载最近的一个稳定版本重新安装的就可以了 v16.14.0

配置文件

  • const ESLintPlugin = require(‘eslint-webpack-plugin’); 引入插件
  • new ESLintPlugin({fix: true }) 使用插件,自动修复不合理写法,规则会根据 package.json 中的 eslintConfig 下 extends 对应的属性去检查
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
// eslint 语法规范检查
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {
mode: "development",

entry: './src/demo/js/index.js',
output: {
filename: "[name].js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', 'postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', 'postcss-loader'],},
{
test: /\.(jpg|png|gif|jpeg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 25 * 1024,
}
},
generator: {
filename: 'img/[name].[hash:6][ext]',
},
},
{test: /\.html$/, loader: 'html-loader',}, // html中引入的图片打包
//打包字体资源
{
test: /\.ttf|eot|woff2?$/,
type: "asset/resource",
generator: {
filename: "font/[name].[hash:6][ext]"
}

}
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "demo.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: './css/demo.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
//js语法检查
new ESLintPlugin({
fix: true // 自动修复不合理的写法
})
]

}
  • “scripts”: { “eslint”: “eslint src” } 在控制台可通过执行 npm run eslint 或者 yarn eslint 会去检查 src目录下的 js 规范
  • “eslintConfig”: { “extends”: “airbnb-base” } 定义的检查规范为 airbnb-base
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
{
"scripts": {
"eslint": "eslint src"
},
"devDependencies": {
"css-loader": "^6.6.0",
"eslint": "^8.9.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-webpack-plugin": "^3.1.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.5.3",
"node-sass": "^7.0.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.3.3",
"sass-loader": "^12.4.0",
"style-loader": "^3.3.1",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2"
},
"dependencies": {
"jquery": "^3.6.0"
},
"browserslistcomment": "支持80%以上的浏览器,支持最后两个版本,忽略已经死掉的浏览器",
"browserslist": [
"> 0.2%",
"last 2 version",
"not dead"
],
"eslintConfig": {
"extends": "airbnb-base"
}
}

eslint检查

特殊配置

  • 有的时候想针对某行代码跳过检查只需要在该行代码上添加 // eslint-disable-next-line 即可跳过对下一行的检查(只针对下一行有效)

跳过语法检查

热部署

简介

  • 在前面的章节中,我们每次写完程序或者修改了内容后都需要通过 webpack 进行打包到 build 目录,这种情况一般是用在生产环境,开发完了打包测试上线,在实际的工作中我们更加希望我们每次修改完代码后就能够自动刷新对应的 html css js 等内容便于我们实时的查看调试,这也就本次记录的内容热部署
  • devServer给我们提供了开发过程中的服务器,是一个使用了express的Http服务器,它的作用主要是为了监听资源文件的改变,该http服务器和client使用了websocket通信协议,只要资源文件发生改变,webpack-dev-server就会实时的进行编译。
  • 只会在内存中编译,不会有任何输出,下载webpack-dev-server包
  • webpack-dev-server并不能读取你的webpack.config.js的配置output 也就是说每次修改了配置文件需要手动重启一下,修改其它的 html css js 会自动刷新
  • 启动devServer指令为: npx webpack serve 本目录执行
  • webpack5无法自动刷新,解决:添加配置:target: ‘web’

流程

  • 下载 webpack-dev-server 包
  • webpackage.config.js 下新增 devServer 属性用于指定端口等信息
  • package.json 中指定启动命令

示例

下载包

1
2
3
4
# npm 安装(开发环境)
npm i webpack-dev-server -D
# yarn 安装(开发环境)
yarn add webpack-dev-server -D

webpack.config.js 配置

  • 每次配置文件 webpack.config.js 发生了变化需要重启 devServer 服务器(因为配置文件是在启动时生效,发生改变不能修改启动时的参数设置这些)
  • 注释了 eslint 检查(开发环境不方便)
  • 去除了 mode: "development" 更改为在启动命令 scripts 中指定
  • 新增 target devServer
  • htmlWebpackPlugin filename 需要指定为 index.html 不然会报错 404(应该是热部署启动后默认去读取 index.html 文件)
  • 如果自动刷新无效的话注意一般是开启了HMR(devServer中 hot:true) 看 entry属性下有没有配置需要监听的html(entry: [‘./src/demo/js/index.js’,’./src/demo/index.html’]) 这里的./src/demo/index.html 就是需要自动刷新的页面
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
// 热部署 htmlWebpackPlugin  filename 需要指定为 index.html 不然会报错 404
const {resolve} = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {

entry: ['./src/demo/js/index.js','./src/demo/index.html'],
output: {
filename: "[name].js",
path: resolve(__dirname, "./build")
},
module: {
rules: [
{test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']},
{test: /\.less$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader', 'postcss-loader']},
{test: /\.scss$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader', 'postcss-loader'],},
{
test: /\.(jpg|png|gif|jpeg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 25 * 1024,
}
},
generator: {
filename: 'img/[name].[hash:6][ext]',
},
},
{test: /\.html$/, loader: 'html-loader',}, // html中引入的图片打包
//打包字体资源
{
test: /\.ttf|eot|woff2?$/,
type: "asset/resource",
generator: {
filename: "font/[name].[hash:6][ext]"
}

}
]
},

plugins: [
new htmlWebpackPlugin({
template: "./src/demo/index.html",
filename: "index.html",
chunks: ['main'],
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: './css/demo.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
//js语法检查
/*new ESLintPlugin({
fix: true // 自动修复不合理的写法
})*/
],
// 在webpack5 需要加上这个配置项才可以自动刷新,如果自动刷新无效的话注意一般是开启了HMR(devServer中 hot:true) 看 entry属性下有没有配置需要监听的html
target: "web",
devServer: {
port:3001,
compress:true,
open:true,
hot:true
}

}
  • content-base //设定webpack-dev-server的director根目录。如果不进行设定的话,默认是在当前目录下。
  • quiet: //控制台中不输出打包的信息,开发中一般设置为false,进行 打印,这样查看错误比较方面
  • no-info: // 不显示任何信息
  • colors: //对信息进行颜色输出
  • no-colors: //对信息不进行颜色输出
  • compress: //开启gzip压缩
  • host <hostname/ip>: //设置ip
  • port : //设置端口号,默认是:8080
  • inline: //webpack-dev-server会在你的webpack.config.js的入口配置文件中再添加一个入口,
  • hot: //开发热替换
  • open: //启动命令,自动打开浏览器
  • history-api-fallback: //查看历史url

package.json

  • scripts下新增 dev build 通过命令指定开发模式启动或者打包,并且携带参数指定 mode 这样就不需要在 webpack.config.js 中指定 mode
  • 命令行中的比配置文件中参数的优先级高
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
{
"scripts": {
"eslint": "eslint src",
"dev": "webpack serve --mode development",
"build": "webpack --mode production"
},
"devDependencies": {
"css-loader": "^6.6.0",
"eslint": "^8.9.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4",
"eslint-webpack-plugin": "^3.1.1",
"html-loader": "^3.1.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.5.3",
"node-sass": "^7.0.1",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss-loader": "^6.2.1",
"postcss-preset-env": "^7.3.3",
"sass-loader": "^12.4.0",
"style-loader": "^3.3.1",
"webpack": "^5.68.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4"
},
"dependencies": {
"jquery": "^3.6.0"
},
"browserslistcomment": "支持80%以上的浏览器,支持最后两个版本,忽略已经死掉的浏览器",
"browserslist": [
"> 0.2%",
"last 2 versions",
"not dead"
],
"eslintConfig": {
"extends": "airbnb-base"
}
}

环境优化

  • 开发环境的优化:打包构建速度(比如我们只更新了一个js文件重新编译的时候只编译这一个 js 文件,热加载)、优化代码调式
  • 生产环境的优化:代码运行的性能(例如尽量减小代码文件的大小,只打包引用到了的 css js )

开发环境HMR(模块热替换)

  • 热模块替换一般是针对开发环境的优化
  • 模块热替换(Hot Module Replacement 即 HMR)是 webpack 提供的最有用的功能之一, 它允许在运行时更新各种模块, 而无需进行完全刷新
  • 启用这个功能,只需要修改一下 webpack.config.js 的配置, 使用 webpack 内置的 HMR 插件就可以了, 在devServer中使用hot参数(hot:true)
  • 启用 webpack 内置的 HMR插件后, module.hot 接口就会暴露在 index.js 中, 接下来需要在 index.js 中配置告诉 webpack 接受HMR的模块。

样式文件

  • 样式文件(css less sass)在使用HMR功能的时候,开发环境中使用style-loader(之前使用的 MiniCssExtractPlugin.loader 把所有 css less sass 打包成一个单独的文件,这样 HMR 就没有意义了因为更新了这个所有打包一起的文件比较大,开发环境使用 style-loader 就不会打包成单独的文件,这样就能做到只更新这一个样式文件 )
  • 这里我没去实践,一般是会根据配置什么的去设置比如开发环境用 style-loader 线上用 MiniCssExtractPlugin.loader 打包成一个 css 文件

HMR-css

html

  • HTML 的HMR功能,默认也没有HMR功能(不用做HMR功能)需要在entry入口中引入html文件(entry:[‘./src/demo/js/index.js’,’./src/demo/index.html’])

HMR-html

js

  • js的HMR功能,默认没有HMR功能,只能处理非入口文件的js文件
  • 启用 webpack 内置的 HMR插件后, module.hot 接口就会暴露在 index.js 中, 接下来需要在 index.js 中配置告诉 webpack 接受HMR的模块(通过代码 module.hot.accept

HMR-js配置前

  • 如上图所示当一个 js 文件发生变化时,所有的 js 都会去执行,如果想要去实现只更新我们自己修改了的 js 文件需要在入口文件中通过代码指定文件示例如下
1
2
3
4
5
6
7
if (module.hot) {
//告诉 webpack 接受热替换的模块为 ./print.js
module.hot.accept('./print.js', function() {
//服务器检测到了 print.js 的代码变化后需要执行的 module.hot.accept 的回调函数
console.log('./print.js 这个文件有发生变化');
})
}
  • 修改 print.js 中将 【111】改为 【33333】 后并未执行 index.js 中的打印语句(打包 css样式的 js 文件这句话),只执行了module.hot.accept的回调函数

  • 修改 print.js后并未再次打印这句话,也就证明热加载只加载了 print.js

  • HMR 中只监听了 print.js

  • 服务器检测到了 print.js 的代码变化后需要执行的 module.hot.accept 的回调函数

HMR-js配置后

线上环境(去除死代码)

  • 该内容是针对线上环境 且指的是 js css 这类文件
  • html文件 不需要,因为如果不需要的 html 我们会注释掉,然后打包的时候会去压缩注释掉的内容,但是 js css 这些可能会留着暂时不注释,可能以后会用,那么我们就期望打包的时候 没有引用的 js css 这些东西不打包进去(比如去网上 copy 了一个一万行的js 但是我们只用了其中的一部分,但是又不敢乱删除,以前的方法就会把所有的一万行打包进去,优化了的话它自动就会去找到这一万行代码中我们使用到的 js 打包进去)
  • 或者说引入的第三方的BootStrap jQuery 我们也期望只把我们项目使用到的js css 打包进去多余的就不要

js

  • Webpack通过 tree-shaking 去掉了实际上并没有使用的js代码来减少包的大小
  • tree-shaking 是 webpack 自带的功能不需要下载其它的包(tree-shaking:树摇,摇晃树子把黄了的叶子摇下来不要)
  • 前提条件:必须使用es6模块化 开启production环境(mode中指定)

css

下载插件

1
2
3
4
# npm 安装(开发环境)
npm i purgecss-webpack-plugin -D
# yarn 安装(开发环境)
yarn add purgecss-webpack-plugin -D

webpack.config.js 配置

  • plugins下新增以下内容 四个引入 const 一个 new
1
2
3
4
5
6
7
//const {resolve, join} = require('path');
//const PurgecssPlugin = require('purgecss-webpack-plugin');
//const glob = require('glob');
//const PATHS = { src: join(__dirname, 'src')}
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, {nodir: true}),
}),