言成言成啊 | Kit Chen's Blog

webpack从入门到茎痛

webpack官网

powershell使用教程

在cmd中输入powershell即可直接进入,或者通过vscode进入。

发现一个网页的小技巧,即可修改内容

1
document.body.contentEditable=true

关于js的加载顺序理解,script脚本async和defer的区别

今天看极限挑战,慢步人生路,太有感触了。

严敏一句话,“我们少年时期呢,兜里没有很多钱,但是,另一半的生活很精彩”,很真实了。

我大致在知乎上看了一眼极限挑战的前世今生,文章一看就是个写热文蹭流量那种,不过事实也八九不离十。不仅有很多感慨,或许这就是现实吧。

比方说我现在周末想看个电影,一般都是追忆老电影了,像李连杰、吴京、周星驰系列,漫威系列,以及其他一些老电影,现在新出的电影基本不看,电视剧更不看了。现在整个影视行业的流向就是只要能吸引来流量,干啥都行,无底线。

比方说之前翻拍动漫的魔道祖师、斗破苍穹,以及现在正在拍的斗罗大陆,我看了几眼,说实话,真的恶心。但是网上还有大片大片的狂热女粉,或许她们眼里只要人长得好看,拍得烂不烂都无所谓了。

资本决定了影视行业的流向,资本同样影响了大部分人的价值观,在这个纷扰的社会里,做真自己,太难了。

一、webpack初体验

npm i 跟 npm install 类似又不类似,百度即可

1
2
3
4
npm install webpack webpack-cli #普通安装webpack跟webpack-cli
npm install webpack webpack-cli -g #全局安装
npm install webpack webpack-cli -D #安装并添加到开发依赖 --save-dev 写入devDependencies
npm install webpack webpack-cli -S #安装并添加到生产依赖 --save 写入dependencies

卸载的话,只需要将install换成uninstall即可,用法如上

开发环境命令:

1
webpack ./src/index.js -o ./build/build.js --mode=development

webpack会以.src/index.js 为入口文件开始打包,打包后输出到./build/build.js
整体打包环境,是开发环境

生产环境命令:

1
webpack ./src/index.js -o ./build/build.js --mode=production

webpack会以.src/index.js 为入口文件开始打包,打包后输出到./build/build.js
整体打包环境,是生产环境

结论

  1. webpack能处理js/json,不能处理css/img等资源
  2. 生产环境和开发环境将es6模块化编译成浏览器能识别的模块化
  3. 生产环境比开发环境多一个压缩js代码

二、webpack开发环境

2.1 打包样式资源

下载需要用到的包

  • css-loader
  • style-loader
  • less-loader
  • less

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
/*
webpack.config.js webpack的配置文件
作用:指示webpack工作(当运行webpack指令时,会加载里面的配置)
所有构建工具都是基于nodejs平台运行的,src下源码采用es6,而模块化(比如webpack.config.js)默认采用commonjs
*/

// resolve用来拼接路径的方法
const { resolve } = require("path");
module.exports = {
//webpack配置

//入口起点
entry: "./src/index.js",
//输出
output: {
// 输出文件名
filename: "built.js",
// 输出路径 _dirname是nodejs的变量,代表当前文件的目录绝对路径
path: resolve(__dirname, "build")
},
// loader的配置
module: {
rules: [

// 详细的loader配置
// 不同文件必须配置不同loader处理
// 配置css
{
// 正则匹配文件
test:/\.css$/,
// 使用哪些loader进行处理
use:[
// use数组中loader执行顺序:从右到左,从下到上,依次执行
// 创建style标签,将js中的css样式资源插入进去,添加到head中生效
"style-loader",
// 将css文件变成一个commonjs的模块加载到js中,里面的内容是样式的字符串
"css-loader"
]

},
// 配置less
{
test:/\.less$/,
use:[
"style-loader",
"css-loader",
// 将less文件编译为css文件
"less-loader"
]
}
]

},
// plugins的配置
plugins: [
// 详细的plugins配置
],
// 模式
mode: "development",//开发模式
// mode: "production"
}

2.2 打包HTML资源

下载需要用到的包

  • html-webpack-plugin
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
/**
* loader:1.下载 2.使用(配置loader)
* plugins:1.下载 2.引入 3.使用
*
*/

const {resolve}=require("path");
const HtmlWebpackPlugin=require("html-webpack-plugin");
module.exports={
entry:"./src/index.js",
output:{
filename:"built.js",
path:resolve(__dirname,"build"),

},
module:{
rules:[

],

},
plugins:[
// plugins的配置
// html-webpack-plugin
// 功能:默认会创建一个Html文件,引入打包输出的所有资源(js/css)
// 需求:需要有结构的html文件
new HtmlWebpackPlugin({
// 复制"./src/index.html",并自动引入打包输出的所有资源(js/css)
template:"./src/index.html"
})
],
mode:"development"
}

2.3 打包图片资源

下载需要用到的包

  • url-loader
  • file-loader
  • html-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
56
57
58
59
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "built.js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',

]
},
// 问题:处理不了html中的img图片
// 处理图片资源
{
test:/\.(jpg|png|gif)$/,
// 只需使用一个loader即可
// 需要下载url-loader和file-loader
loader:"url-loader",
options:{
// 当发现图片大小,小于8kb时,就会被base64处理
// 优点:减少请求数量,减轻服务器压力
// 缺点:图片体积会变大大(导致文件请求速度变慢,所以一般只处理小图片,8-12kb的图片),之前5kb,转换为base64,就会变成8kb,类似等等
limit:8*1024,
/**
* 问题:因为url-loader的es6模块化,使用commonjs解析,而html-loader引入图片使用的是commonjs
* 解析时会出问题:[Object Module]
* 解决:关闭url-loader的es6模块化,使用commonjs解析
*/
esModule:false,
// 设置图片名字格式
// hash:10 取图片哈希值前5位
// ext 取文件的原扩展名
// 发现重复文件的时候,不会覆盖,而会保留原文件
name:"[hash:5].[ext]"
}
},
{
test:/\.html$/,
//处理html文件的img图片(负责引入图片,从而能被url-loader处理)
loader:"html-loader"

}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode:"development"
}

2.4 打包其他资源

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "built.js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
},
// 打包其他资源(除了HTML/JS/CSS资源以外的资源)
{
// 排除css/js/html/less资源
exclude: /\.(css|js|html|less)$/,
loader: "file-loader",
options:{
name:'[hash:5].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode: "development"
}

2.5 devServer

修改配置文件

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "built.js",
path: resolve(__dirname, "build")
},
module: {
rules: [
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
},
// 打包其他资源(除了HTML/JS/CSS资源以外的资源)
{
// 排除css/js/html/less资源
exclude: /\.(css|js|html|less)$/,
loader: "file-loader",
options: {
name: '[hash:5].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode: "development",
// 开发服务器devServer:用来自动化(自动编译、自动打开浏览器,自动刷新浏览器)
// 特点:只会在内存中编译打包,不会有任何输出
// 启动devServer指令为:npx webpack-dev-server
devServer: {
// 跳过检查
// 如果是false,则只能访问localhost:3000,
// 如果是true,则都可以访问,比方说meethigher.com:3000
disableHostCheck: true,

// 默认打开本地的浏览器
open:true,
contentBase: resolve(__dirname, "build"),
// 启动gzip压缩
compress: true,
// 端口号
port: 8080
}
}

运行命令,即可自动打开浏览器执行

1
npx webpack-dev-server

2.6 开发环境基本配置

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
// 这是开发环境配置:能让代码运行起来,在内存中编译打包
/**
* 运行项目指令:
* webpack 会将打包结果输出去
* npx webpack-dev-server 只会在内存中编译打包,没有输出
*/

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/js/index.js",
output: {
filename: 'js/built.js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// loader的配置
// 处理less资源
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
// 处理css资源
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
// 处理图片资源
{
test: /\.(jpg||png||gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
// 设置使用commonjs,不使用es
esModule: false,
//将图片输出到imgs文件夹
outputPath:"imgs"
}
},
// 处理html中的img资源
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他资源
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
// 将其他资源输出到media文件夹
outputPath:"media"
}
}
]
},
plugins: [
// plugins的配置
// 相当于是引入一个模板
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode:"development",
// devServer
devServer: {
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true
}
}

三、webpack生产环境

3.1 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
const {resolve}=require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

const miniCssExtractPlugin=require("mini-css-extract-plugin");
module.exports={
entry:"./src/js/index.js",
output:{
filename:"./js/built.js",
path:resolve(__dirname,"build"),
},
module:{
rules:[
{
test:/\.css$/,
use:[
// 创建style标签,将样式放入
// "style-loader",
// 这个loader取代style-loader。作用:提取css成单独文件
miniCssExtractPlugin.loader,
"css-loader"
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:"./src/index.html"
}),
new miniCssExtractPlugin({
// 输出文件
filename:"./css/built.css"
})
],
mode:"development"
}

3.2 css兼容性处理

需要安装的插件

1
npm install postcss-loader postcss-preset-env -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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
// process.env.NODE_ENV="development";

const miniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "./js/built.js",
path: resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将样式放入
// "style-loader",
// 这个loader取代style-loader。作用:提取css成单独文件
miniCssExtractPlugin.loader,
"css-loader",
/**
* css兼容性处理
* 需要用到postcss,这需要两个包postcss-loader、postcss-preset-env
* 帮助postcss找到package.json中browserlist里面的配置,通过配置加载指定的css兼容性样式
*/

/**
* 在browserslist配置下面内容,通过process.env.NODE_ENV="development",来配置browserslist的运行模式
* "browserslist":{
* "development":[
* "last 1 chrome version",
* "last 1 firefox version",
* "last 1 safari version"
* ],
* "production":[
* ">0.2%",
* "not dead",
* "no op_mini all"
* ]
* }
*/
//两种写法,第一种是默认配置
// "post-loader",
//第二种修改配置
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
// postcss的插件
require("postcss-preset-env")
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
}),
new miniCssExtractPlugin({
// 输出文件
filename: "./css/built.css"
})
],
mode: "development"
}

关于browserslist的配置,可以在github搜索获得

3.3 压缩css

安装插件

1
npm install optimize-css-assets-webpack-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
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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV="development";

const optimizeCssAssetsWebpack=require("optimize-css-assets-webpack-plugin");

const miniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "./js/built.js",
path: resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 创建style标签,将样式放入
// "style-loader",
// 这个loader取代style-loader。作用:提取css成单独文件
miniCssExtractPlugin.loader,
"css-loader",
/**
* css兼容性处理
* 需要用到postcss,这需要两个包postcss-loader、postcss-preset-env
* 帮助postcss找到package.json中browserlist里面的配置,通过配置加载指定的css兼容性样式
*/

/**
* 在browserslist配置下面内容,通过process.env.NODE_ENV="development",来配置browserslist的运行模式
* "browserslist":{
* "development":[
* "last 1 chrome version",
* "last 1 firefox version",
* "last 1 safari version"
* ],
* "production":[
* ">0.2%",
* "not dead",
* "no op_mini all"
* ]
* }
*/
//两种写法,第一种是默认配置
// "post-loader",
//第二种修改配置
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
// postcss的插件
require("postcss-preset-env")
]
}
}
]
}
]
},
plugins: [
// 打包html
new HtmlWebpackPlugin({
template: "./src/index.html"
}),
//提取css
new miniCssExtractPlugin({
// 输出文件
filename: "./css/built.css"
}),
// 压缩css,直接使用默认配置即可
new optimizeCssAssetsWebpack()
],
mode: "development"
}

3.4 js语法检查

可以参照js规则

1
npm install eslint-config-airbnb-base eslint eslint-plugin-import eslint-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
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {resolve}=require("path");
module.exports={
entry:"./src/js/index.js",
output:{
filename:"js/built.js",
path:resolve(__dirname,"build")
},
module:{
rules:[
/**
* 语法检查,需要安装eslint-loader eslint
* 注意:只检查自己写的源代码,不检查第三方库,通过exclude排除第三方库
* 设置检查规则:package.json中eslintConfig中设置
* 推荐使用airbnb规则->eslint-config-airbnb-base eslint eslint-plugin-import
* 在package.json中进行配置
* "eslintConfig":{
* "extends":"airbnb-base"
* },
*
* 如果某些js代码需要忽略检查,可以通过添加// eslint-disable-next-line,来使下一行检测失效
*/
{
test:/\.js$/,
exclude:/node-modules/,
loader:"eslint-loader",
options:{
// 自动修复eslint的错误
fix:true
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:"./src/index.html"
}),
],
mode:"development"
}

3.5 js兼容性处理

兼容性处理

  1. 基本兼容性
  2. 全部兼容性
  3. 按需兼容性
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
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {resolve}=require("path");
module.exports={
entry:"./src/js/index.js",
output:{
filename:"js/built.js",
path:resolve(__dirname,"build")
},
module:{
rules:[
/**
* js基本兼容性处理:babel-loader @babel/preset-env @babel/core
* 问题:只能转换基本语法,如es6中promise就不能转换
*
* js全部兼容性处理:@babel/polyfill,只需要在index.js中引入即可import "@babel/polyfill";
* 问题:需求是解决部分兼容,但是所有兼容代码都被引入,体积太大
*
* js部分兼容性处理:按需加载-->core-js,不需要在index.js引入import "@babel/polyfill"
*/
{
test:/\.js$/,
//排除
exclude:/node_modules/,
loader:"babel-loader",
options:{
//预设:指示babel做哪些兼容性处理,只有presets:["@babel/preset-env"]这一个表示全部兼容性处理
presets:[
[
"@babel/preset-env",
// 按需加载
{
useBuiltIns:"usage",
// 指定corejs版本
corejs:{
version:3
},
// 指定兼容性做到哪个版本浏览器
targets:{
chrome:"60",
firefox:"50",
ie:"9",
safari:"10",
edge:"17"
}
}
]
],
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:"./src/index.html"
}),
],
mode:"development"
}

3.6 压缩html与js

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
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {resolve}=require("path");
module.exports={
entry:"./src/js/index.js",
output:{
filename:"js/built.js",
path:resolve(__dirname,"build")
},
plugins:[
new HtmlWebpackPlugin({
template:"./src/index.html",
// 压缩html
minify:{
// 移除空格
collapseWhitespace:true,
// 移除注释
removeComments:true
}
}),
],
//生产环境下自动压缩js代码
mode:"production"
}

3.7 生产环境基本配置

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
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
const { resolve } = require("path");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin=require("optimize-css-assets-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";

// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "js/built.js",
path: resolve(__dirname, "build")
},
module: {
rules: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js语法检查
/**
* 正常来讲,一个文件只能被一个loader处理
* 当一个文件要被多个loader处理时,那么一定要指定loader执行的先后顺序
* 先执行eslint,再执行babel
*/
{
// 在package.json中需要配置eslintConfig->airbnb
test:/\.js$/,
exclude:/node_modules/,
loader:"eslint-loader",
// 自动修复语法
options:{
fix:true
},
// 优先执行
enforce:"pre"
},
// js兼容性处理
{
test:/\.js$/,
exclude:/node_modules/,
loader:"babel-loader",
options:{
presets:[
[
"@babel/preset-env",
{
useBuiltIns:"usage",
corejs:{version:3},
targets:{
chrome:"60",
firefox:"50",
ie:"9",
safari:"10",
edge:"17"
}
}
],
]
}
},
// 处理图片
{
test:/\.(jpg|png|gif)$/,
loader:"url-loader",
options:{
limit:8*1024,//8kb以下进行base64处理
name:"[hash:10].[ext]",
outputPath:"imgs",
esModule:false
}
},
// 处理html中的图片
{
test:/\.html$/,
loader:"html-loader",
},
// 处理其他文件
{
exclude:/\.(js|css|less|html|jpg|png|gif)$/,
loader:"file-loader",
options:{
outputPath:"media"
}
}

]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template:"./src/index.html",
// 压缩html
minify:{
collapseWhitespace:true,
removeComments:true
}
})

],
mode: "production",
devServer: {
// 跳过检查
// 如果是false,则只能访问localhost:3000,
// 如果是true,则都可以访问,比方说meethigher.com:3000
disableHostCheck: true,

// 默认打开本地的浏览器
open:true,
contentBase: resolve(__dirname, "build"),
// 启动gzip压缩
compress: true,
// 端口号
port: 8080
}
}

四、webpack优化配置

4.1 HMR

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
87
88
89
90
91
/**
* 问题:只修改部分内容,结果所有内容都重新加载
*
* HMR:hot module replacement 热模块替换/模块热替换
* 作用:一个模块发生变化,只会重新打包这一个模块,而不是打包所有
* 极大地提升构建速度
*
* 样式文件:可以使用HMR,因为style-loader内部实现了
* js文件:默认没HMR功能->需要修改js代码,添加支持HMR功能的代码
* 只能处理非入口js文件
* html文件:默认没HMR功能,同时会导致问题->html不能热更新了(因为实际使用中只有一个index.html,不像js有多个模块,所以不用做hmr功能)
* 解决:修改entry入口,将html文件引入,但是会全部刷新
*/

const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: ["./src/js/index.js","./src/index.html"],
output: {
filename: 'js/built.js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// loader的配置
// 处理less资源
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
// 处理css资源
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
// 处理图片资源
{
test: /\.(jpg||png||gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
// 设置使用commonjs,不使用es
esModule: false,
//将图片输出到imgs文件夹
outputPath:"imgs"
}
},
// 处理html中的img资源
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他资源
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
// 将其他资源输出到media文件夹
outputPath:"media"
}
}
]
},
plugins: [
// plugins的配置
// 相当于是引入一个模板
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode:"development",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot:true
}
}

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import "../css/index.less";
import print from "./print.js"

console.log("index.js被加载了"+new Date().toLocaleString());
function add(x,y){
return x+y;
}
print();
console.log(add(1,2));

// 全局找hot属性,一旦为true,说明开启了HMR功能,->让HMR功能生效
if(module.hot){
// 如果后续还有其他模块,同样的方法
module.hot.accept("./print.js",function (){
// 方法会监听 print.js文件的变化,一旦发生变化,其他模块不会重新打包构建
//会执行后面的回调函数
print();
})
}

4.2 source-map

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
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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: ["./src/js/index.js", "./src/index.html"],
output: {
filename: 'js/built.js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// loader的配置
// 处理less资源
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
// 处理css资源
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
// 处理图片资源
{
test: /\.(jpg||png||gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
// 设置使用commonjs,不使用es
esModule: false,
//将图片输出到imgs文件夹
outputPath: "imgs"
}
},
// 处理html中的img资源
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他资源
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
// 将其他资源输出到media文件夹
outputPath: "media"
}
}
]
},
plugins: [
// plugins的配置
// 相当于是引入一个模板
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
mode: "development",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
},
// source-map:一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射关系可以追踪到源代码错误)
/**
* 参数
* [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
*
* source-map:外部
* 错误代码准确信息和源代码的错误位置
* inline-source-map:内联,只生成一个内联的source-map
* 错误代码准确信息和源代码的错误位置
* hidden-source-map:外部
* 错误代码错误原因,但是没有错误位置,不能追踪到源代码的错误,只能提示到构建后代码的位置
* eval-source-map:也是内联,每一个文件都生成一个source-map
* 错误代码准确信息和源代码的错误位置,文件名后缀多了哈希值
* nosources-source-map:外部
* 错误代码准确信息,没有任何源代码信息
* cheap-source-map:外部
* 错误代码准确信息和源代码的错误位置,错误只能精确到行,不能精确到列
* cheap-module-source-map:外部
* 错误代码准确信息和源代码的错误位置,错误只能精确到行,不能精确到列
* module会将loader的source-map也加进来
*
* 内联和外部:
* 1. 外部生成的文件,内联是没有的
* 2. 内联速度更快
*
* 开发环境:速度快,调试更友好
* 速度快:eval>inline>cheap>...
* eval-cheap-source-map>eval-source-map
* 调试更友好:
* source-map>cheap-module-source-map>cheap-source-map
* 一般使用eval-source-map/eval-cheap-module-source-map
*
* 生产环境:源代码要不要隐藏?调试要不要更友好?
* 内联会让代码体积变大,所以在生产环境不用内联
* 隐藏源代码↓
* nosources-source-map
* hidden-source-map
* 一般使用source-map/cheap-module-source-map
*/
devtool: "inline-source-map"
};

4.3 oneOf

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
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
149
150
151
152
153
154
const { resolve } = require("path");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";

// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "js/built.js",
path: resolve(__dirname, "build")
},
module: {
rules: [
// js语法检查
/**
* 正常来讲,一个文件只能被一个loader处理
* 当一个文件要被多个loader处理时,那么一定要指定loader执行的先后顺序
* 先执行eslint,再执行babel
*/
{
// 在package.json中需要配置eslintConfig->airbnb
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
// 自动修复语法
options: {
fix: true
},
// 优先执行
enforce: "pre"
},
{
//以下loader只会匹配一个,用来优化打包速度
//注意:不能有两个配置处理同一种类型文件,所以需要将重复内容提取出来
oneOf: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: { version: 3 },
targets: {
chrome: "60",
firefox: "50",
ie: "9",
safari: "10",
edge: "17"
}
}
],
]
}
},
// 处理图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,//8kb以下进行base64处理
name: "[hash:10].[ext]",
outputPath: "imgs",
esModule: false
}
},
// 处理html中的图片
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他文件
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: "file-loader",
options: {
outputPath: "media"
}
}

]
}
]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})

],
mode: "production",
devServer: {
// 跳过检查
// 如果是false,则只能访问localhost:3000,
// 如果是true,则都可以访问,比方说meethigher.com:3000
disableHostCheck: true,

// 默认打开本地的浏览器
open: true,
contentBase: resolve(__dirname, "build"),
// 启动gzip压缩
compress: true,
// 端口号
port: 8080
}
}

4.4 缓存

server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**服务器代码
* 启动服务器指令
* npm install nodemon -g
* nodemon server.js
* 或者
* node server.js
*/
const express=require("express");
const app=express();

app.use(express.static("build",{
maxAge:1000*3600
}));
app.listen(8080);

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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* 缓存
* 1. babel缓存
* cacheDirectory:true
* -->让第二次打包构建速度更快
* 2. 文件资源缓存,文件名添加哈希值
* hash
* 问题:因为js和css同时使用一个哈希值,如果重新打包,会导致所有缓存失效(可能只改动了一个文件)
*
* chunkhash:根据chunk生成的hash,如果打包来源于同一个chunk,那么hash就一样
* 问题:js和css的hash还是一样的
* 因为css是在js中被引入的,同属于一个chunk
*
* contenthash:根据文件内容生成hash。不同文件hash一定不一样
* -->让代码上线运行缓存更好使用
*/

const { resolve } = require("path");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";

// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];

module.exports = {
entry: ["./src/js/index.js", "./src/index.html"],
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// js语法检查
/**
* 正常来讲,一个文件只能被一个loader处理
* 当一个文件要被多个loader处理时,那么一定要指定loader执行的先后顺序
* 先执行eslint,再执行babel
*/
{
// 在package.json中需要配置eslintConfig->airbnb
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
// 自动修复语法
options: {
fix: true
},
// 优先执行
enforce: "pre"
},
{
//以下loader只会匹配一个,用来优化打包速度
//注意:不能有两个配置处理同一种类型文件,所以需要将重复内容提取出来
oneOf: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: { version: 3 },
targets: {
chrome: "60",
firefox: "50",
ie: "9",
safari: "10",
edge: "17"
}
}
],
],
// 开启babel缓存
cacheDirectory:true
}
},
// 处理图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,//8kb以下进行base64处理
name: "[hash:10].[ext]",
outputPath: "/imgs",
esModule: false
}
},
// 处理html中的图片
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他文件
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: "file-loader",
options: {
outputPath: "/media"
}
}

]
}
]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.[contenthash:10].css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: "development",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
},
// source-map:一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射关系可以追踪到源代码错误)
devtool: "inline-source-map"
};

4.5 tree shaking

目的:去掉无用的代码

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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
* tree shaking:去除无用代码
* 前提:1. 必须使用es6模块化 2. 开启production环境
* 作用:减少代码体积
*
* 在package.json中配置"sideEffects":false,表示所有代码都没有副作用,都可以进行treeshaking
* 问题:可能会把css/@babel/polyfill干掉,因为没有使用
* 可以进行标记
* "sideEffects":["*.css","*.less"]
*/

const { resolve } = require("path");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";

// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];

module.exports = {
entry: ["./src/js/index.js", "./src/index.html"],
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// js语法检查
/**
* 正常来讲,一个文件只能被一个loader处理
* 当一个文件要被多个loader处理时,那么一定要指定loader执行的先后顺序
* 先执行eslint,再执行babel
*/
{
// 在package.json中需要配置eslintConfig->airbnb
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
// 自动修复语法
options: {
fix: true
},
// 优先执行
enforce: "pre"
},
{
//以下loader只会匹配一个,用来优化打包速度
//注意:不能有两个配置处理同一种类型文件,所以需要将重复内容提取出来
oneOf: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: { version: 3 },
targets: {
chrome: "60",
firefox: "50",
ie: "9",
safari: "10",
edge: "17"
}
}
],
],
// 开启babel缓存
cacheDirectory:true
}
},
// 处理图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,//8kb以下进行base64处理
name: "[hash:10].[ext]",
outputPath: "/imgs",
esModule: false
}
},
// 处理html中的图片
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他文件
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: "file-loader",
options: {
outputPath: "/media"
}
}

]
}
]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.[contenthash:10].css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: "production",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
},
// source-map:一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射关系可以追踪到源代码错误)
devtool: "inline-source-map"
};

4.6 code split

  1. 单入口、多入口输出。单入口输出一个bundle;多入口输出多个bundle
  2. 通过optimization
  3. 通过js动态导入语法

index.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
import $ from "jquery";
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4, 5));
// eslint-disable-next-line
console.log($);

/**
* 通过js代码,让某个文件被单独打包成一个chunk
* import动态导入语法:能将某个文件单独打包
*
* webpackChunkName:'xxx'设置打包之后的名字,如果不设置,默认是以chunk的id值来命名
*/
import(/* webpackChunkName:'js动态导入' */"./test")
.then(({ mul, count }) => {
//文件加载成功
// eslint-disable-next-line
console.log(mul(2, 3));
})
.catch(() => {
// eslint-disable-next-line
console.log("文件加载失败");
});

test.js

1
2
3
4
5
6
export function mul(x, y) {
return x * y;
}
export function count(x, y) {
return x - y;
}

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";



module.exports = {
// 单入口
// entry: "./src/js/index.js",
// 多入口js:有一个入口,最终输出就有一个bundle;有多个,输出就会有多个
entry: {
index: "./src/js/index.js",
test: "./src/js/test.js"
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// loader的配置
// 处理less资源
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
// 处理css资源
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
// 处理图片资源
{
test: /\.(jpg||png||gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
// 设置使用commonjs,不使用es
esModule: false,
//将图片输出到imgs文件夹
outputPath: "imgs"
}
},
// 处理html中的img资源
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他资源
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
// 将其他资源输出到media文件夹
outputPath: "media"
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/**
* 单入口时,可以设置下面代码,将node_modules中代码单独打包成一个chunk最终输出
* 多入口时,自动分析多入口chunk中,有没有公共的文件(如果文件太小,还是会打包成一个整的)。如果有,会打包成一个单独的chunk
*/
optimization:{
splitChunks:{
chunks:"all"
}
},
mode: "production",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
}
};

4.7 js文件懒加载与预加载

关于html的dom加载顺序,可以参照本文最上面的defer与async

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
87
88
89
90
91
92
93
94
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";

module.exports = {
entry: "./src/js/index.js",
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
// loader的配置
// 处理less资源
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader'
]
},
// 处理css资源
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
// 处理图片资源
{
test: /\.(jpg||png||gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
// 设置使用commonjs,不使用es
esModule: false,
//将图片输出到imgs文件夹
outputPath: "imgs"
}
},
// 处理html中的img资源
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他资源
{
exclude: /\.(html|css|js|less|jpg|png|gif)$/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
// 将其他资源输出到media文件夹
outputPath: "media"
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/**
* 单入口时,可以设置下面代码,将node_modules中代码单独打包成一个chunk最终输出
* 多入口时,自动分析多入口chunk中,有没有公共的文件(如果文件太小,还是会打包成一个整的)。如果有,会打包成一个单独的chunk
*/
optimization:{
splitChunks:{
chunks:"all"
}
},
mode: "production",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
}
};

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>开发环境配置</title>
</head>
<body>
<h1 id="title">测试</h1>
<button id="btn">按钮</button>
<div id="box1"></div>
<div id="box2"></div>
<img src="./media/img3.jpg" alt="">
<a href="https://meethigher.obs.cn-north-4.myhuaweicloud.com:443/OBSBrowserPlus-HEC-win64.zip?AccessKeyId=MJXE1SVRAHUR4INU2JVX&Expires=1594782807&Signature=mAW9elrLaTdqoxFk%2BDJDOs42gMg%3D" download="下载.zip">点击下载</a>
</body>
</html>

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log("indexjs文件被加载了");
// import {mul} from "./test";
document.getElementById("btn").onclick = function () {
// 懒加载:当文件需要使用时,才加载文件。这个方法不会进行重复加载,第一次加载之后,就会将数据保存到缓存
// 预加载:会在使用之前,提前加载js文件
/**
* 正常加载可以认为是并行加载,同一时间加载多个js文件,文件即使不用,也会加载
* 预加载是等其他资源加载完毕,浏览器空闲了,再进行加载。兼容性非常差,目前只适用于pc端主流浏览器
*/
import(/*webpackChunkName:"test",webpackPrefetch:true*/"./test").then(({ mul }) => {
console.log(mul(2, 3));
}).catch(() => {
console.log("失败");
});
}

test.js

1
2
3
4
console.log("testjs被加载")
export function mul(x,y){
return x*y;
}

4.8 PWA

参考资料:

  1. Hexo博客部署PWA
  2. Service Workers 实现网站加速和离线缓存

安装

1
npm install workbox-webpack-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
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
149
150
/**
* PWA:渐进式网络开发应用程序(离线可访问)
* workbox(google开源)-->workbox-webpack-plugin
*/
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const workboxWebpackPlugin=require("workbox-webpack-plugin");
const miniCssExtractPlugin=require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin=require("optimize-css-assets-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";
// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];
module.exports = {
entry: "./src/js/index.js",
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js兼容性处理
{
test:/\.js$/,
exclude:/node_modules/,
loader:"babel-loader",
options:{
presets:[
[
"@babel/preset-env",
{
useBuiltIns:"usage",
corejs:{version:3},
targets:{
chrome:"60",
firefox:"50",
ie:"9",
safari:"10",
edge:"17"
}
}
],
]
}
},
// 处理图片
{
test:/\.(jpg|png|gif)$/,
loader:"url-loader",
options:{
limit:8*1024,//8kb以下进行base64处理
name:"[hash:10].[ext]",
outputPath:"/imgs",
esModule:false
}
},
// 处理html中的图片
{
test:/\.html$/,
loader:"html-loader",
},
// 处理其他文件
{
exclude:/\.(js|css|less|html|jpg|png|gif)$/,
loader:"file-loader",
options:{
outputPath:"/media"
}
}

]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
// 使用
/**
* 1. 帮助ServiceWorker快点启动
* 2. 删除旧的ServiceWorker
*
* 最终生成ServiceWorker的配置文件
*/
new workboxWebpackPlugin.GenerateSW({
clientsClaim:true,
skipWaiting:true
})
],
/**
* 单入口时,可以设置下面代码,将node_modules中代码单独打包成一个chunk最终输出
* 多入口时,自动分析多入口chunk中,有没有公共的文件(如果文件太小,还是会打包成一个整的)。如果有,会打包成一个单独的chunk
*/
optimization:{
splitChunks:{
chunks:"all"
}
},
mode: "production",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
}
};

index.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
import "../css/index.less";
console.log("indexjs文件被加载了");
// import {mul} from "./test";
document.getElementById("btn").onclick = function () {
// 懒加载:当文件需要使用时,才加载文件。这个方法不会进行重复加载,第一次加载之后,就会将数据保存到缓存
// 预加载:会在使用之前,提前加载js文件
/**
* 正常加载可以认为是并行加载,同一时间加载多个js文件,文件即使不用,也会加载
* 预加载是等其他资源加载完毕,浏览器空闲了,再进行加载。兼容性非常差,目前只适用于pc端主流浏览器
*/
import(/*webpackChunkName:"test",webpackPrefetch:true*/"./test").then(({ mul }) => {
// eslint-disable-next-line
console.log(mul(2, 3));
}).catch(() => {
// eslint-disable-next-line
console.log("失败");
});
}
// 注册ServiceWorker
// 处理兼容性问题
/**
* 1. exlint不认识window、navigator全局变量
* 解决:需要package.json中eslintConfig配置
* "env":{
* "browser":true
* }
* 2. sw必须运行在服务器上
* 解决:1.nodejs
* 2.npm i server -g
* 通过命令server -s build,启动服务器,将build目录下所有资源作为静态资源暴露出去
*/
if("serviceWorker" in navigator){
window.addEventListener("load",()=>{
navigator.serviceWorker.register("/service-worker.js").then(()=>{
// eslint-disable-next-line
alert("sw注册成功");
}).catch(()=>{
// eslint-disable-next-line
alert("sw注册失败");
});
})
}

问题:

在eslint语法检测时,出现import和export必须放在顶部的错误,该错误暂未解决。

4.9 多进程打包

安装

1
npm install thread-loader -D

将某个loader放到thread-loader的后面,就会对该loader进行多进程打包

下面,以多进程打包js兼容性处理为例

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
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const workboxWebpackPlugin = require("workbox-webpack-plugin");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const optimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");

//设置nodejs的环境变量,此处是用来设置package.json中browserlist以什么模式来兼容
process.env.NODE_ENV = "production";
// 复用loader
const commonCssLoader = [
miniCssExtractPlugin.loader,
"css-loader",
// 兼容性处理
{
// 在package.json中需要配置browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
require("postcss-preset-env")()
]
}
}
];
module.exports = {
entry: "./src/js/index.js",
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, "build")
},
module: {
rules: [
//提取css文件
// 兼容性处理
{
test: /\.css$/,
use: [
...commonCssLoader
]
},
{
test: /\.less$/,
use: [
...commonCssLoader,
"less-loader"
]
},
// js兼容性处理
{
test: /\.js$/,
exclude: /node_modules/,
use: [
/**
* 开启多线程打包
* 进程启动大概为600ms,进程通信也有开销
* 只有工作消耗时间比较长的时候,才需要多进程打包
*/
// "thread-loadaer",
//也可以进行详细配置
{
loader:"thread-loader",
options:{
workers:2 //进程2个
}
},
{
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage",
corejs: { version: 3 },
targets: {
chrome: "60",
firefox: "50",
ie: "9",
safari: "10",
edge: "17"
}
}
],
]
}
}
]
},
// 处理图片
{
test: /\.(jpg|png|gif)$/,
loader: "url-loader",
options: {
limit: 8 * 1024,//8kb以下进行base64处理
name: "[hash:10].[ext]",
outputPath: "/imgs",
esModule: false
}
},
// 处理html中的图片
{
test: /\.html$/,
loader: "html-loader",
},
// 处理其他文件
{
exclude: /\.(js|css|less|html|jpg|png|gif)$/,
loader: "file-loader",
options: {
outputPath: "/media"
}
}

]
},
plugins: [
new miniCssExtractPlugin({
filename: "css/built.css"
}),
//压缩css
new optimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: "./src/index.html",
// 压缩html
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
// 使用
/**
* 1. 帮助ServiceWorker快点启动
* 2. 删除旧的ServiceWorker
*
* 最终生成ServiceWorker的配置文件
*/
new workboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
],
/**
* 单入口时,可以设置下面代码,将node_modules中代码单独打包成一个chunk最终输出
* 多入口时,自动分析多入口chunk中,有没有公共的文件(如果文件太小,还是会打包成一个整的)。如果有,会打包成一个单独的chunk
*/
optimization: {
splitChunks: {
chunks: "all"
}
},
mode: "production",
// devServer
devServer: {
disableHostCheck: true,
contentBase: resolve(__dirname, "build"),
compress: true,
port: 8080,
open: true,
// 开启HMR功能,并重启服务
hot: true
}
};

4.10 externals

可以用来拒绝某些库的打包进入(某些情况下,通过cdn来引入库会更快一点)

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
const {resolve}=require("path");
const HtmlWebpackPlugin=require("html-webpack-plugin");
module.exports={
entry:"./src/js/index.js",
output:{
filename:"js/build.js",
path:resolve(__dirname,"build"),

},
module:{
rules:[

],

},
plugins:[
// plugins的配置
// html-webpack-plugin
// 功能:默认会创建一个Html文件,引入打包输出的所有资源(js/css)
// 需求:需要有结构的html文件
new HtmlWebpackPlugin({
// 复制"./src/index.html",并自动引入打包输出的所有资源(js/css)
template:"./src/index.html"
})
],
mode:"production",
externals:{
// 忽略库名以及对应的npm下载的包名
// 拒绝jquery这个包被打包进来
jquery:"jQuery"
}
}

4.11 dll

dll:动态连接库

对某些库进行打包,并自动添加到html中。可以理解成跟externals相反。

安装

1
npm install add-asset-html-webpack-plugin -D

webpack.dll.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
/**
* 使用dll技术,对某些库(第三方库,如jquery、react、vue...)进行单独打包
* 当使用webpack命令时,默认查找webpack.config.js文件
* 而我们需要运行webpack.dll.js,所以指令要改成 webpack --config webpack.dll.js
*/
const {resolve}=require("path");
const webpack=require("webpack");
module.exports={
entry:{
//最终打包生成的[name]是jquery
//["jquery"]->要打包的库是jquery
jquery:["jquery"]
},
output:{
filename:"[name].js",
path:resolve(__dirname,"dll"),
library:"[name]_[hash]",//打包的库向外暴露出的库的名字
},
plugins:[
// 打包生成manifest.json->提供jquery的映射关系
new webpack.DllPlugin({
name:"[name]_[hash]",//映射库的暴露的内容名称
path:resolve(__dirname,"dll/manifest.json"),//输出文件路径
})
],
mode:"production"
}

运行命令

1
webpack --config webpack.dll.js

4.12 总结

  • 开发环境性能优化
    • 优化打包构建速度
      • HMR:针对css、js文件进行热替换。一个模块发生变化,只会重新打包这一个模块,而不是打包所有
    • 优化代码调试
      • source-map:一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射关系可以追踪到源代码错误)
  • 生产环境性能优化
    • 优化打包构建速度
      • oneOf:其中loader只会匹配一个,用来优化打包速度。就好比搜索内容时,搜索到第一个内容,后面的就不会再考虑了。所以在oneOf中,重复的内容需要单独提取出去。
      • babel缓存
      • 多进程打包
    • 优化代码运行性能
      • 文件缓存:hash->chunkhash->contenthash
      • treeshaking:去除无用代码
      • code split:代码分割
      • 懒加载/预加载
      • pwa:离线可访问技术
      • externals
      • dll

五、webpack配置详解

5.1 entry

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
/**
* entry:入口起点
* 1. string->"./src/index.js" 单入口,打包生成一个chunk。输出一个build文件,此时chunk名称默认为main
* 2. array->["./src/index.js","./src/add.js"] 多入口,所有文件最终只会生成一个chunk,输出出去只有一个bundle文件
* 作用:只有在HMR中,让html热更新生效
* 3. object 多入口,有几个入口文件,就形成几个chunk,并输出几个bundle文件,此时chunk的名称是key
* 特殊用法->看配置
*
* 第1种和第3种使用较多
*
*
*
*/
module.exports={
// entry:["./src/index.js","./src/add.js"],
entry:{
// 特殊用法
index:["./src/index.js","./src/sub.js"],
add:"./src/add.js"
},
output:{
filename:"[name].js",
path:resolve(__dirname,"build")
},
plugins:[
new HtmlWebpackPlugin()
],
mode:"development"
};

5.2 output

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports={
entry:"./src/index.js",
output:{
//文件名称(指定名称+目录)
filename:"[name].js",
// 输出文件目录(将来所有资源输出的公共目录)
path:resolve(__dirname,"build"),
// 所有资源引入公共路径前缀,如引入路径是"imgs/a.jpg"就会变成"/imgs/a.jpg"
publicPath:"/",
// entry中的就是入口chunk,像import这种就是非入口chunk
chunkFilename:"[name]_chunk.js",//非入口chunk的名称,
// 除非使用dll,正常打包一般不用library
// library:"[name]",//将库以变量名暴露出去
// libraryTarget:"window",//将变量名添加到browser上
// libraryTarget:"global",//将变量名添加到node上
},
plugins:[
new HtmlWebpackPlugin()
],
mode:"development"
};

5.3 module

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports={
entry:"./src/index.js",
output:{
filename:"[name].js",
path:resolve(__dirname,"build"),
},
module:{
rules:[
// loader配置
{
test:/\.css$/,
// 多个loader用use
use:["style-loader","css-loader"],

},
{
test:/\.js$/,
// 排除
exclude:/node_modules/,
// 包含
include:resolve(__dirname,"src"),
// pre优先执行,post延后执行,不写中间执行
enforce:"pre",
// 单个loader用loader
loader:"eslint-loader",
// 配置,具体看文档
options:{}
},
{
// 以下配置只会生效一个
oneOf:[]
}
]
},
plugins:[
new HtmlWebpackPlugin()
],
mode:"development"
};

5.4 resolve

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports={
entry:"./src/js/index.js",
output:{
filename:"[name].js",
path:resolve(__dirname,"build"),
},
module:{
rules:[
{
test:/\.css$/,
use:["style-loader","css-loader"],

},
]
},
plugins:[
new HtmlWebpackPlugin()
],
mode:"development",
// webpack本身是个对象,所以写法顺序无所谓的
resolve:{
// 配置解析模块路径别名,优点:写路径时,简写路径。缺点:写代码时没有提示
alias:{
// 配置css的绝对路径
$css:resolve(__dirname,"src/css"),
},
// 配置省略文件路径的后缀名
extensions:[".json",".css"],
// 告诉webpack解析模块时去找哪个目录,绝对路径,再写一个node_modules是为了防止找不到
modules:[resolve(__dirname,"../../node_modules"),"node_modules"]
}
};

5.5 devServer

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
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
entry: "./src/js/index.js",
output: {
filename: "[name].js",
path: resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],

},
]
},
plugins: [
new HtmlWebpackPlugin()
],
mode: "development",
resolve: {
alias: {
$css: resolve(__dirname, "src/css"),
},
extensions: [".json", ".css"],
modules: [resolve(__dirname, "../../node_modules"), "node_modules"]
},
devServer:{
// 运行代码的目录
contentBase:resolve(__dirname,"build"),
// 监视ContentBase目录 目录下的所有文件,一旦文件变化就会reload重载
watchContentBase:true,
// 配置
watchOptions:{
// 忽略文件
ignored:/node_modules/
},
// 启动gzip压缩
compress:true,
// 端口号
port:8080,
// 域名
host:"localhost",
// 自动打开
open:true,
// 开启hmr功能
hot:true,
// 日志,不要显示启动服务器时的日志
clientLogLevel:"none",
// 除了基本启动信息以外,其他内容都不打印
quiet:true,
// 如果出现错误,不要全屏提示
overlay:false,
// 服务器代理,解决开发环境跨域问题
proxy:{
// 一旦服务器8080接收到/api请求,就会自动把请求转发到另一个服务器8000
"/api":{
target:"http://localhost:8000",
// 发送请求时,请求路径重写:将/api/xxx-->/xxx(去掉/api)
pathRewrite:{
"^/api":""
}
}
}
}
};

5.7 optimization

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
87
88
89
90
91
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const terserWebpackPlugin=require("terser-webpack-plugin");

module.exports = {
entry: "./src/js/index.js",
output: {
filename: "js/[name].[contenthash].js",
path: resolve(__dirname, "build"),
chunkFilename:"js/[name].[contenthash].chunk.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],

},
]
},
plugins: [
new HtmlWebpackPlugin()
],
mode: "development",
resolve: {
alias: {
$css: resolve(__dirname, "src/css"),
},
extensions: [".json", ".css"],
modules: [resolve(__dirname, "../../node_modules"), "node_modules"]
},
optimization:{
splitChunks:{
chunks:"all",
// 以下这些都是默认值,一般也不会修改。所以也可以不写
// 分割的chunk最小是30kb
minSize:30*1024,
// 0表示最大没有限制
maxSize:0,
// 要提取的chunk最少被引用一次,如果未被引用,不会提取
minChunks:1,
// 按需加载时,并行加载的文件最大数量为5
maxAsyncRequests:5,
// 入口js文件最大并行请求数量为3个
maxInitialRequests:3,
// 名称连接符是~
automaticNameDelimiter:"~",
// 可以使用命名规则
name:true,
// 分割chunk的组
cacheGroups:{
// node_modules中的文件会被打包到vendors这个chunk中。命名-->vendors~xxx.js
// 同时,也要满足上面的公共规则
vendors:{
test:/[\\/]node_modules[\\/]/,
// 优先级
priority:-10
},
default:{
// 要提取的chunk最少被提取两次
minChunks:2,
// 优先级
priority:-20,
// 代码能复用。如果当前要打包的模块和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
reuseExistingChunk:true
}
}
},
/**
* index.js中引用a.js,若a.js发生变化,hash就会变,那么引用a.js的index.js也会变化
* 下面的代码作用是:将当前模块记录其他模块的hash单独打包成一个文件,叫runtime,这样index.js就不用改了
* index.js直接引用runtime中的带有hash的内容即可
*/
runtimeChunk:{
name:entrypoint=>`runtime-${entrypoint.name}`
},
// 配置生产环境的压缩方案:js和css
// 将来压缩js就使用这个
minimizer:[
new terserWebpackPlugin({
// 开启缓存
cache:true,
// 开启多进程打包
parallel:true,
// 启动source-map
sourceMap:true,
})
]

}
};

六、webpack5

虽然目前还没发布,先了解

1
npm init -y # 初始化node_modules,并且使用默认配置,-y代表yes

安装webpack5测试版

1
npm install webpack@next webpack-cli -D

此版本重点关注以下内容:

  • 通过持久缓存提高构建性能.
  • 使用更好的算法和默认值来改善长期缓存.
  • 通过更好的树摇和代码生成来改善捆绑包大小.
  • 清除处于怪异状态的内部结构,同时在 v4 中实现功能而不引入任何重大更改.
  • 通过引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 v5.

6.1 下载

  • npm i webpack@next webpack-cli -D

6.2 自动删除 Node.js Polyfills

早期,webpack 的目标是允许在浏览器中运行大多数 node.js 模块,但是模块格局发生了变化,许多模块用途现在主要是为前端目的而编写的。webpack <= 4 附带了许多 node.js 核心模块的 polyfill,一旦模块使用任何核心模块(即 crypto 模块),这些模块就会自动应用。

尽管这使使用为 node.js 编写的模块变得容易,但它会将这些巨大的 polyfill 添加到包中。在许多情况下,这些 polyfill 是不必要的。

webpack 5 会自动停止填充这些核心模块,并专注于与前端兼容的模块。

迁移:

  • 尽可能尝试使用与前端兼容的模块。
  • 可以为 node.js 核心模块手动添加一个 polyfill。错误消息将提示如何实现该目标。

6.3 Chunk 和模块 ID

添加了用于长期缓存的新算法。在生产模式下默认情况下启用这些功能。

chunkIds: "deterministic", moduleIds: "deterministic"

6.4 Chunk ID

你可以不用使用 import(/* webpackChunkName: "name" */ "module") 在开发环境来为 chunk 命名,生产环境还是有必要的

webpack 内部有 chunk 命名规则,不再是以 id(0, 1, 2)命名了

6.5 Tree Shaking

  1. webpack 现在能够处理对嵌套模块的 tree shaking
1
2
3
4
5
6
7
8
9
10
11
// inner.js
export const a = 1;
export const b = 2;

// module.js
import * as inner from './inner';
export { inner };

// user.js
import * as module from './module';
console.log(module.inner.a);

在生产环境中, inner 模块暴露的 b 会被删除

  1. webpack 现在能够多个模块之前的关系
1
2
3
4
5
6
7
8
9
import { something } from './something';

function usingSomething() {
return something;
}

export function test() {
return usingSomething();
}

当设置了"sideEffects": false时,一旦发现test方法没有使用,不但删除test,还会删除"./something"

  1. webpack 现在能处理对 Commonjs 的 tree shaking

6.6 Output

webpack 4 默认只能输出 ES5 代码

webpack 5 开始新增一个属性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代码.

如:output.ecmaVersion: 2015

6.7 SplitChunk

webpack4中

1
2
// webpack4
minSize: 30000;

webpack5中

1
2
3
4
5
// webpack5
minSize: {
javascript: 30000,
style: 50000,
}

6.8 Caching

1
2
3
4
5
6
7
8
9
// 配置缓存
cache: {
// 磁盘存储
type: "filesystem",
buildDependencies: {
// 当配置修改时,缓存失效
config: [__filename]
}
}

缓存将存储到 node_modules/.cache/webpack

6.9 监视输出文件

之前 webpack 总是在第一次构建时输出全部文件,但是监视重新构建时会只更新修改的文件。

此次更新在第一次构建时会找到输出文件看是否有变化,从而决定要不要输出全部文件。

6.10 默认值

  • entry: "./src/index.js
  • output.path: path.resolve(__dirname, "dist")
  • output.filename: "[name].js"

6.11 更多内容

https://github.com/webpack/changelog-v5

七、总结

7.1 参考

npm打包那些事

我想上传代码到github,但是其中node_modules数据太大了,所以需要在git中忽略掉。

git忽略某个目录或文件不上传

7.2 小结

发布:2020-07-24 16:00:01
修改:2020-07-25 07:31:56
链接:https://meethigher.top/blog/2020/webpack/
标签:web js 
付款码 捐助 分享
阅读量