Fork me on GitHub

webpack-开发环境构建优化

刚刚对我们前端项目做了一顿分析优化操作,因为接手时每次构建要花两分钟左右的时间,实在忍受不了,只能动手了。通过这次优化,重新温习了下 webpack 的一些知识。接下来会关于 webpack 展开写几篇心得:

  • 构建分析
  • 开发环境构建优化
  • 生产环境构建优化
  • webpack 原理浅析
  • 如何实现一个简易版 webpack
  • 如何手写一个 loader 和 plugin

好了,进入主题,本篇主要是介绍开发环境构建优化(包含速度、体积),如何分析可以看我上一篇。

1. 版本升级

现在,我们已经可以安装最新的 webpack 5 了,不过 v5 还不是正式版本。目前 npm 官网上的最新版本仍然是 v4。由于不是本章重点,后面有机会会详细阐述,感兴趣的可以看下这篇文章了解下,最好能动手玩一玩。

建议更新到最新稳定版本,为什么呢?可以看下官网-构建性能

webapck-5.png

所以别说 v3 了, webpack4.x 的速度要远大于 3.x, v4 的小版本也建议更新到最新稳定版。

另外 webpack 版本也会存在导致本地使用 node 高版本跑项目时,报出一些奇奇怪怪的错误。像我遇到过一次 webpack v4.6、node v12.16.0 就报错了。

webapck-6.png
webapck-7.png

2. devtool

1
2
3
4
module.exports = {
devtool: 'eval-source-map',
// ...
}

开发环境建议使用 eval-source-map, 这会减少你本地构建的时间。

为什么呢?可以看下官网介绍-devtool,这部分的中文是我负责翻译的,有觉得不合理的,欢迎留言。

webapck-8.png

3. resolve

建议配置 alias 和 extensions,同时项目中要使用到 alias,否则配置就毫无意义了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module.exports = {
// ...
resolve: {
alias: {
src: path.resolve(__dirname, '../src'),
page: path.resolve(__dirname, '../src/page'),
mobilepage: path.resolve(__dirname, '../src/mobilepage'),
components: path.resolve(__dirname, '../src/components'),
containerComponents: path.resolve(__dirname, '../src/containerComponents'),
store: path.resolve(__dirname, '../src/store'),
static: path.resolve(__dirname, '../src/static'),
vue: 'vue/dist/vue.js',
utils: path.resolve(__dirname, '../src/utils')
// ...
},
extensions: [".js", ".vue"]
},
// ..
}

可以看下

4. 避免不必要的 plugin 和优化任务

一些plugin比如压缩混淆在开发环境是没有意义的,所以需要写两份不同的配置文件,防止这些插件作用在开发环境。

另外需要防止不必要的优化,可以在开发环境把这些都关掉。

1
2
3
4
5
6
7
8
9
module.exports = {
// ...
optimization: {
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false
},
// ...
}

5. happypack

happypack

在使用 Webpack 对项目进行构建时,会对大量文件进行解析和处理。当文件数量变多之后,Webpack 构件速度就会变慢。由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以 Webpack 需要处理的任务要一个一个进行操作。

而 Happypack 的作用就是将文件解析任务分解成多个子进程并发执行。子进程处理完任务后再将结果发送给主进程。所以可以大大提升 Webpack 的项目构件速度。

这里顺带提一下,在 loader 中最好加上 exclude 和 include 配置,会减少构建时间的。

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
var path = require('path');
var HappyPack = require('happypack');

module.exports = {
module: {
rules: [
// ...
{
test: /\.js$/,
use: 'happypack/loader',
include: [
path.resolve(__dirname, '../src'),
// ...
],
exclude: /node_modules/
},
// ...
]
},
resolve: {
// ...
},
plugins: [
// ...
new HappyPack({
loaders: ['babel-loader'],
threads: 4
}),
]
};

6. 使用 noParse

webpack 打包的时候,有时不需要解析某些模块的加载(这些模块并没有依赖,或者根本没有模块化),我们可以直接加上这个参数,直接跳过这种解析,像 jquery、lodash…

1
2
3
4
module.exports = {
noParse: /node_modules\/(jquery.js)
// ...
}

7. hard-source-webpack-plugin

hard-source-webpack-plugin

这是用于加载缓存,效果很强。

  • 第一次构建将花费正常的时间
  • 第二次构建将显着加快(大概提升90%的构建速度)。

webpack v5 实现了此功能,感兴趣的可以下载试试。

1
2
3
4
5
6
7
8
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

module.exports = {
// ...
plugins: [
new HardSourceWebpackPlugin(), // 缓存,每当程序包依赖性发生变化时,请记住清除缓存
]
};

8. 压缩 js, html, css 文件

要想优化构建后的体积,不断减少静态资源文件的大小,我们希望 webpack 帮助我们尽可能压缩文件的体积。对于 js 脚本文件而言,webpack4.0 在 mode 为 ‘production’ 时,默认会启动代码的压缩。除此之外,我们需要手动对 html 和 css 进行压缩。

针对html 的压缩,只需要对 html-webpack-plugin 进行相关配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
plugins: [
new HtmlWebpackPlugin({
title: 'webpack优化',
filename: 'index.html',
template: path.resolve(__dirname, '../index.html'),
minify: { // 压缩 HTML 的配置
collapseWhitespace: true,
removeComments: true,
useShortDoctype: true
}
}),
]
// ...
}

针对 css 的压缩, webpack4.0 使用 optimize-css-assets-webpack-plugin 来压缩单独的 css 文件。

1
2
3
4
5
6
7
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
plugins: [
new OptimizeCSSAssetsPlugin()
],
}

9. 合并压缩图片

提升性能的一个重要的条件是降低 http 请求数,而应用中经常会有大大小小的图片需要处理,对应用中的小图标来说,css sprite 是首选,将各种图标集合成一张大的图片可以很好的减少网络请求数。而对于需要独立开的图片,且大小在合理范围内时,我们可以将图片转换成 base64 位编码,内嵌到css 中,同样可以减少请求。

处理图片资源时,webpack 提供了 file-loader 和url-loader 两个loaders供选择,file-loader 和url-loader 的作用,可以用来解析项目中图片文件的url引入问题。两者的区别在于,url-loader 可以将小于指定字节的文件转为 DataURL, 大于指定字节 的依旧会使用 file-loader 进行解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
// ..
module: {
rules: [{
test: /\.(png|jpe?g|gif|svg|ttf|woff2|woff)(\?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192,
outputPath: 'assets/fonts/'
}
},
]
},
}

处理完雪碧图和小图片的 base64 转换后,对于大图片来说,webpack还可以做到对图片进行压缩,推荐使用 image-webpack-loader,插件提供了多种形式的压缩。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// webpack.base.js
module.exports = {
module: {
rules: [
{
loader: 'image-webpack-loader',
options: {
optipng: { // 使用 imagemin-optipng 压缩 png,enable: false 为关闭
enabled: true,
},
pngquant: { // 使用 imagemin-pngquant 压缩 png
quality: '65-90',
speed: 4
},
}
}
]
}
}

10. 使用 CDN

在项目的 index.html 中,常规方式引入 CDN 链接,此处以 jquery 为例

1
2
3
4
5
<body>
<div id="app"></div>
<!-- CDN方式引入jquery -->
<script src="https://.../jquery@2.13.2/lib/index.js"></script>
</body>

使用 externals

1
2
3
4
5
6
module.exports = {
//...
externals: {
jquery: 'jQuery'
}
};

使用时

1
2
3
import $ from 'jquery';

$('.my-element').animate(/* ... */);

11. progress-bar-webpack-plugin

progress-bar-webpack-plugin

最后推荐个构建体验插件-构建进度条

1
2
3
4
5
6
7
8
9
var ProgressBarPlugin = require('progress-bar-webpack-plugin');

module.exports = {
// ...
plugins: [
new ProgressBarPlugin(),
//...
]
};

webapck-9

最后,目前说了大概 10 种开发环境构建速度和体积的优化。关于体积部分,生产环境也会用到。

大家还有没有其他的优化黑魔法,欢迎大家留言交流,共同学习成长。

-------------本文结束感谢您的阅读-------------