webpack的高级配置其实就是进行优化,让代码在编译运行的时候性能更好。一般情况下我们从以下几个方面来入手:
- 提升开发体验
- 提升打包构建的速度
- 减少代码体积
- 优化代码的运行性能
下面来详细聊一聊
1.提升开发体验
使用SourceMap(源码映射)
为什么要用SourceMap呢,因为我们在开发的过程中运行的代码是webpack打包压缩过的,一般长这样:
里面除了代码,还有非常多的注释信息,可阅读性很差,如果代码运行出错的话,错误提示给出的代码出错位置我们很难看明白是哪里出现了问题,这里我们可以简单测试一下。
我们故意在代码后面加上(),运行,在浏览器控制台查看报错,然后点击查看代码出错的位置
通过上图可以看到,我们难以快速清晰地发现这个错误到底对应着开发阶段源代码的那个位置,所以,为了解决这个问题,我们需要应用一个好的工具,SourceMap。
什么是SourceMap
它是一个用来构建源代码和构建后的代码一一映射的文件的方案 它会生成一个xxx.map文件,这个文件包含着源代码和构建后的代码每一行、每一列的映射关系,如果构建后的代码出错了,则会通过xxx.map文件。从构建后代码的出错位置找到源代码出错的位置,然后会让浏览器显示源代码的出错位置,最终方便程序员快速定位错误,提升开发体验。
如何使用SourceMap
简单来说,我们可以直接在webpack配置文件中加入相应配置,Dectool选项控制着是否生成source map,以及里面具体的细节
我们可以这样配置:
开发模式:cheap-module-source-map
module.exports = {
// 其他省略
mode: "development",
devtool: "cheap-module-source-map",
};
使用cheap-module-source-map,优点是打包编译速度快,只包含行映射,缺点就是没有列映射。
加入配置后,重新启动开发服务器,打开网页,F12查看效果
可以看到, 报错的文件已经精准了, 指向了源代码中的sum.js文件,点开以后,可以看到是哪一行出现了问题
因为不分析哪一列,所以从报错提示我们看不出来这一行的那个地方有问题,不过这已经能够大大提升体验,精准提示出错位置了。
生产模式:source-map
module.exports = {
// 其他省略
mode: "production",
devtool: "source-map",
};
优点:包含行/列映射, 缺点:打包编译速度更慢
我们打包一下,看看效果如何,报错提示文件,很准
点开后发现是第二行的后半部分出错,因为加入了列的映射,所以更加精准
2.提升打包构建的速度
2.1使用HotModuleReplacement
开发时,如果我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。
所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快。
HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。简单来说就是局部更新。
使用方式
module.exports = {
// 其他省略
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)
},
};
这样我们就能开启HMR了,css 样式经过 style-loader 处理,已经具备 HMR 功能了。 但是 js 还具备HMR,需要再进行配置。 在main.js中,我们可以这样写,哪个模块需要HMR,我们就把它配置过来
// 判断是否支持HMR功能
if (module.hot) {
module.hot.accept("./js/count.js", function (count) {
const result1 = count(2, 1);
console.log(result1);
});
module.hot.accept("./js/sum.js", function (sum) {
const result2 = sum(1, 2, 3, 4);
console.log(result2);
});
}
打开页面,我们做一些修改,看一下页面和控制台的反应,页面做到了无刷新改变,控制台也出现了相应提示
事实上,在实际的开发中,并不采用上述方式进行js的HMR,我们可以借助vue或者react的loader来实现。
2.2使用OneOf
我们在配置文件中已经设置好了很多的配置规则,在打包过程中,每个文件都要依次验证所有的规则,是不是要被处理,事实上这样子是低效的,因为每个文件只需要被其中一个规则处理就可以,OneOf可以帮我们实现这个。
只需要在rules数组里面加入对象,对象里面OneOf数组,将之前的规则放进OneOf数组即可
2.3使用Include/Exclude
开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。而这些文件是不需要编译可以直接使用的。
所以我们在对 js 文件处理时,要排除 node_modules 下面的文件。
-
include 包含,只处理 xxx 文件
-
exclude 排除,除了 xxx 文件以外其他文件都处理
有一点需要注意,include和exclude不能同时用,用一个就好了
在配置文件的js规则处
eslint也可以这样用
以上是开发模式的配置,生产模式也是如此
2.4Eslint和Babel使用Cache缓存
每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。
我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了。
找到Eslint和Babel的配置项,设置缓存
这里我们关闭了缓存文件的压缩,因为压缩会耽误一些时间,并且缓存文件也不是我们最终需要的,因此要关闭压缩。
开发生产模式都是一样的。
打包一下,也能看到缓存目录
2.5多进程打包
当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。
我们想要继续提升打包速度,其实就是要提升 js 的打包速度,因为其他文件都比较少。
而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具,所以我们要提升它们的运行速度。
我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了。我们启动进程的数量就是我们 CPU 的核数。
下面展示如何进行多进程打包
首先要下载包
npm i thread-loader -D
接着获取CPU核数
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
然后加入配置
js压缩terser也开启多进程
const TerserPlugin = require("terser-webpack-plugin");