Skip to content

Commit a4ede1c

Browse files
committed
自定义插件和loader
1 parent ee6cc6c commit a4ede1c

File tree

6 files changed

+572
-6
lines changed

6 files changed

+572
-6
lines changed

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ socket
103103

104104
[webpack性能优化](https://github.com/fltenwall/JavaScript_Interview_Question/blob/main/notes/前端工程化/打包工具/Webpack/webpack性能优化.md)
105105

106+
[webpack打包速度优化](https://github.com/fltenwall/JavaScript_Interview_Question/blob/main/notes/前端工程化/打包工具/Webpack/webpack打包速度优化.md)
107+
106108
前端监控
107109

108110

@@ -172,7 +174,7 @@ Nust
172174

173175
[事件总线](https://github.com/fltenwall/JavaScript_Interview_Question/blob/main/notes/手写实现/事件总线.md)
174176

175-
[apply/call/bind](https://github.com/fltenwall/JavaScript_Everything/blob/main/notes/%E6%89%8B%E5%86%99%E5%AE%9E%E7%8E%B0/call-apply-bind.md)
177+
[apply/call/bind](https://github.com/fltenwall/JavaScript_Everything/blob/main/notes/手写实现/call-apply-bind.md)
176178

177179
new
178180

@@ -249,14 +251,20 @@ underscore.js
249251

250252
构建工具
251253

252-
#### 包管理
254+
### 包管理
253255

254256
npx
255257

256258
npnm
257-
#### 打包工具
259+
### 打包工具
260+
261+
#### webpack
262+
263+
[webpack性能优化](https://github.com/fltenwall/JavaScript_Interview_Question/blob/main/notes/前端工程化/打包工具/Webpack/webpack性能优化.md)
264+
265+
[webpack打包速度优化](https://github.com/fltenwall/JavaScript_Interview_Question/blob/main/notes/前端工程化/打包工具/Webpack/webpack打包速度优化.md)
266+
258267

259-
webpack
260268

261269
Gulp
262270

notes/前端工程化/打包工具/Webpack/webpack性能优化.md

Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,198 @@ import(/* webpackChunkName:'about' */'./router/about')
8181

8282
### preload和prefetch
8383

84-
文件预加载
84+
prefetch预获取:在父包加载结束后,浏览器空闲时下载文件
85+
86+
```javascript
87+
import(/* webpackPrefetch:true */'./about.js')
88+
```
89+
90+
preload预加载:同主包文件一起下载,以并行方式加载
8591

8692

8793
### CDN 加速服务器配置
8894

95+
1. 打包的所有静态资源都放到 CDN 服务器
96+
2. 一些第三方资源放在 CDN 服务器
97+
8998
### CSS 样式单独抽取
9099

100+
`style-loader`, `css-loader`
101+
102+
`mini-css-extract-plugin`将css提取到单独文件
103+
104+
```javascript
105+
{
106+
module:{
107+
rules:[
108+
{
109+
test:'\.css$',
110+
use:[
111+
'style-loader',
112+
MiniCssExtractPlugin.loader, // 将css以link插入到js
113+
'css-loader',
114+
]
115+
}
116+
],
117+
},
118+
plugins:[
119+
new MiniCssExtractPlugin({
120+
// filename:'[chunkhash]'.css,
121+
filename:'[contenthash]'.css,
122+
chunkFilename:'[name]_chunk'.css, // 对动态导入的css进行命名
123+
})
124+
]
125+
}
126+
```
127+
128+
#### hash命名的不同方式
129+
130+
`hash`的生成和项目有关,项目中一个文件发生变化,会影响其他文件hash的命名变化
131+
132+
`chunkhash`根据不同入口生成hash,但如果主包发生变化,主包中引入的文件也会被重命名重新打包
133+
134+
`contenthash`只与内容有关,如果只是主包变化,只对主包进行重命名和重新打包,不影响主包引入的文件
135+
91136
### Terser
92137

93-
webpack本身是不会对代码就行压缩的,利用`terser`插件进行压缩
138+
webpack本身是不会对代码就行压缩的,默认利用`terser`插件进行压缩和代码混淆
139+
140+
### CSS 压缩
141+
142+
```javascript
143+
{
144+
optimization: {
145+
new CSSMinimizerplugin(
146+
parallel:true, //多进程进行压缩
147+
)
148+
}
149+
}
150+
```
151+
152+
### 区分环境,配置分离
153+
154+
`webpack-merge`合并webpack配置文件
155+
156+
package.json
157+
```javascript
158+
{
159+
"scripts":{
160+
"build":"webpack --config ./config/common.config.js --env producation",
161+
"serve":"webpack serve --config ./config/common.config.js --env development",
162+
}
163+
}
164+
```
165+
166+
common.config.js
167+
```javascript
168+
const {merge} = require('webpack-merge')
169+
const prodConfig = require('./prod.config')
170+
const devConfig = require('./dev.config')
171+
const commonConfig = function(isProduction){
172+
return {
173+
...,
174+
module:{
175+
rules:[
176+
{
177+
test:'\.css$',
178+
use:[
179+
isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
180+
'css-loader',
181+
]
182+
}
183+
],
184+
},
185+
186+
}
187+
}
188+
189+
// 判断环境
190+
module.exports = function(env){
191+
let mergeConfig = env.production ? prodConfig : devConfig;
192+
return merge(commonConfig, mergeConfig)
193+
}
194+
```
195+
196+
### Tree-Shaking
197+
198+
默认只对主文件进行了Tree-Shaking,去除了无用代码。`生产环境会自动开启`
199+
200+
js的Tree-Shaking
201+
202+
```javascript
203+
{
204+
optimization:{
205+
usedExports:true, // 分析无用代码并标识出
206+
},
207+
minimizer:[
208+
new TerserPlugin({
209+
extractComments: true,
210+
terserOptions: {
211+
compress:{
212+
arguments:true,
213+
unused: true
214+
},
215+
mangle:true,
216+
keep_fnames:true
217+
}
218+
})
219+
],
220+
}
221+
```
222+
223+
CSS 的Tree-Shaking
224+
225+
`purgecss-webpack-plugin`
226+
227+
使用`glob`三方模块匹配文件夹下的所有指定文件
228+
229+
```javascript
230+
const glob = import('glob') // 匹配文件夹下的所有指定文件
231+
232+
233+
{
234+
plugins:[
235+
new PurgeCSSPlugin({
236+
paths:glob.sync(`${path.resolve(__dirname, "../src")}/**/*`, {nodir:true}),
237+
safelist:function(){
238+
return{
239+
standard:['body']
240+
}
241+
}
242+
})
243+
]
244+
}
245+
```
246+
247+
### 作用域
248+
249+
将函数合并到同一个作用域.
250+
251+
开发环境下不会开启,生成环境下会自动开启
252+
253+
### 文件压缩
254+
255+
`gzip`压缩。浏览器会自动对压缩文件进行解压。
256+
257+
HTTP 压缩流程:
258+
259+
1. HTTP数据在服务器发送之前就已经被压缩
260+
2. 兼容的浏览器在向服务器发送请求时,会告知服务器支持哪些压缩格式`Accept-Encoding:gzip, deflate`
261+
3. 服务器在浏览器支持的压缩格式下,直接返回对应的压缩后的文件,并且在响应头中告知浏览器`Content-Encoding:gzip`
262+
263+
支持的压缩格式`deflate`,`gzip`,`br`
264+
265+
使用插件`compression-webpack-plugin`进行文件压缩
266+
267+
HTML入口文件默认在生产模式下,会由`html-webpack-plugin`进行压缩
268+
```javascript
269+
{
270+
plugins:[
271+
new HTMLWebpackPlugin({
272+
template:'./index.html',
273+
cache:true, // html文件发生改变时才重新打包
274+
minify:true, // 默认生产环境下为true
275+
})
276+
]
277+
}
278+
```
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
#### 打包时间分析
3+
4+
对每个`loader``plugin`打包时间进行分析:`speed-measure-webpack-plugin`
5+
6+
```javascript
7+
const smp = new SpeedMeasureWebpackPlugin()
8+
9+
...
10+
11+
const commonConfig = function(env){
12+
return {
13+
module:{
14+
rules:[
15+
{
16+
test:/\.jsx?$/,
17+
exclude:/node_modules/, // 三方包一般会自行处理
18+
use:{
19+
loader:"babel-loader",
20+
}
21+
}
22+
],
23+
},
24+
}
25+
26+
...
27+
}
28+
29+
let mergeConfig = env.production ? prodConfig : devConfig;
30+
return smp.wrap(merge(commonConfig, mergeConfig))
31+
```
32+
33+
#### 打包后文件分析
34+
35+
1. 生成一个`stats.json`文件,分析每个包大小
36+
37+
配置`package.json`
38+
```javascript
39+
{
40+
"scripts":{
41+
"build":"webpack --config ./config/common.config.js --env producation --profile --json=stats.json",
42+
"serve":"webpack serve --config ./config/common.config.js --env development",
43+
}
44+
}
45+
```
46+
查看 `stats.json`
47+
48+
2. `webpack-bundle-analyzer`
49+
50+
当成插件进行使用
51+
52+
```javascript
53+
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
54+
module.exports={
55+
plugins:[
56+
new BundleAnalyzerPlugin(),
57+
]
58+
}
59+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
#### 编译入口文件分析
3+
4+
```javascript
5+
const config = require('./webpack.config')
6+
const compiler = webpack(config)
7+
8+
compiler.run((err, stats)=>{
9+
10+
})
11+
```
12+
13+
创建`compiler`文件,调用`compiler.run()`开始进行编译和打包。从主入口文件开始,生成依赖图。
14+
15+
#### 注册所有的plugins
16+
17+
```javascript
18+
for(const plugin of options.plugins){
19+
if(typeof plugin === 'function'){
20+
plugin.call(compiler, compiler)
21+
}else{
22+
// plugin是对象
23+
plugin.apply(compiler)
24+
}
25+
}
26+
```
27+
28+
可以使用`compiler`取到`hooks`进行事件监听
29+
30+
`loader`外,`entry`,`output`,`devtool`等配置选项也是转为插件进行处理
31+
32+
```javascript
33+
new WebpackOptionsApply().process(options, compiler);
34+
compiler.hooks.initialize.call();
35+
return compiler;
36+
```
37+
38+
```javascript
39+
apply(compiler){
40+
...
41+
compiler.hooks.make.tapAsync('EnterPlugin',(compiler,callback)=>{
42+
compiler.addEntry(context,dep, options,err=>{
43+
callback(err)
44+
})
45+
})
46+
}
47+
```
48+
49+
开始编译模块:
50+
51+
将入口作为模块加入图结构
52+
```javascript
53+
this.addMoudleTree({
54+
55+
})
56+
```
57+
58+
创建为模块并查找依赖,将依赖模块进行分解,逐一向下进行依赖查找。将模块加入队列中
59+
60+
加载loader,执行模块的转化 利用三方包`loader-runner`进行处理
61+
62+
```javascript
63+
runloader(){}
64+
```
65+
66+
webpack => compiler => hooks => 注册所有插件 => compilization(addEntry => factoryModule => addModule => needBild => buildModule => buildQueue => _build => module.build => do_Build => runloader() ) => seal => 输入文件 => emitAssets 输入结果

0 commit comments

Comments
 (0)