Webpack
3、高级篇
3.1、提升开发体验 —— SourceMap
当使用开发服务器调试代码的时候,可以在浏览器中看到编译后的代码,开发模式下我们是让 css 并入 js 文件因为在配置开发模式的配置文件时没有让 css 单独提取出来
此时如果代码运行出错,我们点击这些错误的链接
会发现它让我们去观察编译后的代码的错误,不经阿这阿这阿这了出来…谁看得懂你编译后这是哪跟哪啊…
甚至是后续一旦将来开发代码文件很多,就更难去发现该错误对应我们原代码中的哪个地方,因此如果能够让这些错误的链接一点击,就能让我们看到是源码的哪里出了错,而不是编译后的文件哪里出了错,来帮助我们更好的调试、修改代码,因此我们可以使用 SourceMap 来解决这个问题
SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。,它会生成一个 xxx.map 文件,里面包含源代码和构建后代码每一行、每一列的映射关系。当构建后代码出错了,会通过 xxx.map 文件,从构建后代码出错位置找到映射后源代码出错位置,从而让浏览器提示源代码文件出错位置,帮助我们更快的找到错误根源
开发环境配置,修改 webpack.dev.js 文件如下
// 在暴露的对象身上添加一个 devtool 配置
devtool: "cheap-module-source-map",
生产环境配置,修改 webpack.prod.js 文件如下
// 在暴露的对象身上添加一个 devtool 配置
devtool: "source-map",
优缺点 | 描述 |
---|---|
cheap-module-source-map | ① 优点:打包编译速度快,只包含行映射 ② 缺点:没有列映射 |
source-map | ① 优点:包含行 / 列映射 ② 缺点:打包编译速度更慢 |
修改完配置后现在重启开发服务器,点击错误这个地方
会发现给我们跳转到源码上出现错误的地方了
再来看一下生产模式下会是什么样的,运行
npm run build
先进行打包,打包之后可以看到 dist/static/js 下多出了一个 main.js.map 的文件,这个文件是一个源映射文件,将打包后的 JavaScript 代码映射回原始的源代码,以及源代码中的位置信息,因此当编译后的代码出错时,我们点击控制台中的链接,就会按照这个映射,给我们跳转到源码上出错的地方了
观察出错的地方,我们可以发现 source-map 对源码的定位是包括行和列的,如果只是行的话,那么 return 下方也会划有红线
3.2、提升打包速度
3.2.1 HotModuleReplacement
在开发过程中,随着项目的体积越来越大,打包的速度会越来越慢,如果在后续项目一大时进行开发,我们有时只需修改了一点点的代码例如某个变量值变一下,然而 Webpack 默认还是会将所有模块全部重新打包编译,导致每次修改一点代码都需要经历漫长的编译等待,体验很差,此时我们可以使用 HotModuleReplacement 来解决这个问题
Hot Module Replacement (HMR) 是 Webpack 提供的一项功能,它允许在运行时替换、添加或删除模块,能够使得只让修改的模块重新打包编译而其他模块不需要进行重新打包编译,且无需完全重新加载整个页面(即不会刷新页面,从而能保留应用的状态如表单输入、滚动位置等会被保留)。这对开发体验有很大的提升,使得开发过程更加流畅和高效
只需要修改开发模式配置文件的devServer配置即可
// webpack.dev.js
devServer: {
host: "localhost", // 启动服务器域名
port: "3002", // 启动服务器端口号
open: true, // 是否自动打开浏览器
hot: true, // 开启HMR功能
},
配置之后更改 css 代码可以发现页面不会重新刷新了,并且在控制台可以看到 [HMR] 开头的提示,这说明其只对修改的 css 模块进行重新编译打包
然而现在修改 js 代码还是会发现页面被刷新,即整个项目重新打包编译,因此还需要做进一步的配置
// 在入口文件 src/main.js 中添加如下代码
if (module.hot) {
module.hot.accept("./js/count.js"); // count模块需要实现热模块替换功能
module.hot.accept("./js/sum.js"); // sum模块需要实现热模块替换功能
}
当我们运行开发服务器的时候,修改 count.js / sum.js 的代码只会重新打包编译相应的模块而不会导致整个模块重新打包编译,注意不是修改 module.hot.accept 函数中的代码,修改了其中的代码,页面依然会刷新、项目依然会重新打包编译,可见 HRM 是帮助我们在修改模块的时候可以更快速地完成打包编译工作
当运行开发服务器后对模块代码进行更改如下
// sum.js 原来的代码
export default function count(x, y) {
return x + y;
}
// 尝试修改并观察浏览器
export default function count(x, y) {
return x + y +1;
}
会发现浏览器并没有刷新,并且控制台输出了 [HMR] 开头的提示信息,这就说明我们的配置成功了
然而在实际的开发中,需要我们一个个模块都这样声明是很麻烦的,因此我们通常会使用一些 loader 来解决,在开发 vue 时可以使用 vue-loader 、在 开发 react 的时候可以使用 react-hot-loader 来帮我们自动地实现这个功能
最后需要注意的是 HMR 是应用在开发模式下的,是为了提高我们的开发速度,让我们可以更快地看到代码修改后的成果,而不是应用在生产模式下的,当代码结束了开发阶段后,还是需要老老实实地从将整个项目重新打包
3.2.2 OneOf
由于每个文件都只会使用一个 rule 中指明地 loader 去进行处理,然而当我们什么都不配置的时候,每个文件都会与配置中间中出现的所有 loader 进行对比,即使已经匹配到了相应的 rule,然是还是不会停下来,会对比完所有的 rule 才结束,这显然是大可不必的,因此处理方法是将所有的 rule 都放在 oneOf 指明的数组里
// webpack.dev.js webpack.prod.js配置同理
// 修改rules配置
rules: [
{
oneOf: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: ["style-loader", "css-loader", "stylus-loader"],
},
{
test: /\.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 50 * 1024}}, //解析
generator: {
filename: "static/imgs/[hash:8][ext][query]"},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
generator: {
filename: "static/media/[hash:8][ext][query]",
},
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules代码不编译
loader: "babel-loader",
},
],
},
],
虽然但是:这个优化看起来提升的效果感觉不是很明显的样子
3.2.3 Include / Exclude
在开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了,而这些文件是不需要编译可以直接使用的,然而当我们没有进行相应的配置进行打包编译我们的 js 文件时,对于引入到我们代码中的第三方库的代码还是会扫一遍,显然是浪费时间的,因此我们可以使用 ESLintPlugin 插件的 exclude 配置来帮我们完成这个功能(我发现怎么之前已经写过exclude了…)
配置(只能二选一) | 描述 |
---|---|
include | 只扫描哪些文件 |
exclude | 排除哪些文件,也就是不扫描它们 |
// webpack.dev.js webpack.prod.js配置同理
// 修改js对应的rule
{
test: /\.js$/,
exclude: /node_modul