引言
在 Webpack 入门篇 里分享了 Webpack 的一些基本配置,掌握那些基本配置已经可以通过 Webpack 搭建项目了。但是对于学习,对于技术的追求,到这还远远不够呀,掌握了基础确实可以搭建项目,但是项目的性能,还有复用性,我们都没有去考虑
所以,在本篇文章我将会对 Webpack 的一些高级配置做一下分享。既是方便自己后续查阅,也能分享给诸位伙伴共同学习~~
前期准备
在正式进入主题之前,再一次啰嗦一下,在 Webpack 入门篇 里面有下载webpack-dev-server
这个依赖,但是一直没用,这里就先做一个简单说明:
这个其实是实现了开发服务器&自动化,让我们不用每次写完代码都需要手动输入指令才能编译代码,通过在 Webpack 配置文件里进行以下配置:
arduino
devServer: {
host: "localhost", // 启动服务器域名
port: "3000", // 启动服务器端口号
open: true, // 是否自动打开浏览器
},
然后,在控制台执行指令:npx webpack serve
即可。只要不修改配置文件,每次修改代码后都很自动编译;如果修改了配置文件就需要重新运行指令了
高级配置
因为本文的关于 Webpack 的配置的出发点在于我们不单单满足于能够搭建项目,我们希望更多,我们需要优化整个过程。那么优化又需要从哪些方面出发呢?下面我将会从下面四个方面出发,来搭建一个我希望得到优化的项目:
- 提升开发体验
- 提升打包构建速度
- 减少代码体积
- 优化代码运行性能
提升开发体验
为什么需要提出这个需求?如果你根据 Webpack 入门篇 学习后搭建了自己的项目,并且在运行后项目还报错了,你在 debug 的时候,点击对应的错误信息跳转后会遇到下面这种情况:
这个情况就是,完全不知道是哪里报错了。它给你索引到的位置,完全就不是你期望的错误位置。如果让你在这个开发环境下去开发,这开发效率肯定是大打折扣呀,debug 都无从下手......
所以,为了提升开发效率,为了能更快开发(摸鱼)。我们这时就会思考,这个 Webpack 有没有给我们提供解决这个问题的一些配置呢?
嘿~还真有,这就是 SourceMap(源代码映射)技术,一个用来生成源代码与构建后代码一一映射的文件的方案。
Webpack 很贴心,直接满足我们的诉求了,我们只需要通过devtool
这个配置项来配置即可。 Webpack Devtool 文档 可以查阅源代码映射的多种情况,这里就主要分享一下开发时需要关注的两个即可
- 开发模式:
cheap-module-source-map
- 优点:打包编译速度快,只包含行映射
- 缺点:没有列映射
java
module.exports = {
mode: "development",
devtool: "cheap-module-source-map",
};
- 生产模式:
source-map
- 优点:包含行/列映射
- 缺点:打包编译速度更慢
java
module.exports = {
mode: "production",
devtool: "source-map",
};
在通过上面的配置之后,我们 debug 时,点击错误提示最右边的链接便可以直接定位到错误代码位置
当然,它的错误提示下面也会有很多相关的错误链接,代码少时可以一个个点着去看,肯定能找到,但是多了属实不是很友好
提升打包构建速度
在提升打包构建速度这块,可以进行的操作是相当多的,只要你能想的到优化的点,就到 Webpack 官网去找找看有没有提供相应的一些配置。那么我就来分享一下目前我所掌握到的一些优化打包构建速度的配置
OneOf
Webpack 配置处理器时,应该会注意到我们配置了很多的 loader,那么在打包时每个文件都需要用到这些 loader 吗?答案肯定是不是。所以,在这一步打包速度就会受到影响了,一个文件多跑一个 loader,上百上千个文件就是多跑更多的 loader,速度自然而然就会变慢
所以,要解决这个问题的关键便是,一个文件只匹配一个 loader 即可,其他的 loader 就不用匹配了。本来一个文件也只需要一个 loader 来处理
这个oneOf
的用处便满足了我们的需求。用法如下:
css
module.exports = {
module: {
rules: [
{
oneOf: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/i,
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
],
},
};
Include / Exclude
当我们在用loader 处理器
或者plugin 插件
处理项目文件时,并不是所有目录或者文件都需要被处理,例如node_modules 文件夹
,我们使用的所有第三方的库或插件都下载在这个文件夹里,但是这些文件是不需要编译就可以直接使用的。所以我们在对 js 文件处理或者Eslint 校验
时,要排除node_modules
下面的文件
- Include:包含,只处理 xxx 文件
- Exclude:排除,除了 xxx 文件以外其他文件都处理
js
plugins: [
new ESLintWebpackPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
}),
],
减少代码体积
Tree Shaking
开发时我们定义了一些工具函数库,或者引用第三方工具函数库及组件库。如果没有特殊处理的话,在打包时会引入整个库,但是实际上可能只用了极小部分的功能。而将整个库都打包进来,体积就太大了
Tree Shaking
是一个术语,通常用于描述移除 JavaScript 中的没有使用上的代码
注意:它依赖 ES Module
,且 Webpack 已经默认开启了这个功能,无需其他配置
Image Minimizer
在开发中如果引用了较多图片,那么图片体积会比较大,会导致网页请求速度比变慢,加载时间更长。因此,可以对图片进行压缩,以减少图片体积
注意:如果项目中的图片都是在线链接,则无需此配置。本地项目静态图片才需要进行压缩
image-minimizer-webpack-plugin
: 用来压缩图片的插件
bash
npm i image-minimizer-webpack-plugin imagemin -D
还有额外需要下载的包,分为两种模式,可根据需求选择:
- 无损压缩
bash
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
- 有损压缩
bash
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D
下面是选择无损压缩模式的配置:
js
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin()
]
}
};
注意:对于优化类的插件,可以放在 plugin 对象下,也可以选择放在 optimization 对象下
优化代码运行性能
Code Split
打包代码时会将所有 js 文件打包到一个文件中,导致文件体积很大。我们如果只要渲染某个页,就应该只加载这页的 js 文件,其他文件不应该被加载
因此,会想到将打包生成的文件进行分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源越少,速度也就更快
这里是使用Code Split 代码分割
技术实现的将打包文件分割成多个,而不是一个大的文件
根据上面的描述,可以大概了解到Code Split
主要完成下面两个功能:
- 分割文件:将打包生成的文件进行分割,生成多个 js 文件
- 按需加载:需要哪个文件就加载哪个文件
对打包文件进行分割可以通过以下方式来实现:
- 多入口:配置了几个入口,至少输出几个 js 文
- 提取重复代码:需要进行
splitChunks
配置
Preload / Prefetch
当加载资源体积很大时,加载需要更长的时间,会导致用户体验不佳,有卡顿现象
为了解决这个问题,提供了两种技术手段,Preload 和 Prefetch:
Preload
:告诉浏览器立即加载资源Prefetch
:告诉浏览器在空闲时才加载资源
Preload 和 Prefetch 区别
Preload
加载优先级高,Prefetch
加载优先级低Preload
只能加载当前页面需要使用的资源,Prefetch
可以加载当前页面资源,也可以加载下一个页面需要使用的资源
配置流程
首先,安装依赖包
bash
npm i @vue/preload-webpack-plugin -D
然后,在配置文件里配置对应内容
js
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
module.exports = {
plugins: [
new PreloadWebpackPlugin({
rel: "preload", // preload兼容性更好
as: "script",
// rel: 'prefetch' // prefetch兼容性更差
}),
],
};
总结
- 当前页面优先级高的资源用
Preload
加载 - 下一个页面需要使用的资源用
Prefetch
加载
Corejs
我们知道用babel
可以对 js 代码进行兼容性处理,通过使用@babel/preset-env
智能预设来处理兼容性问题,它能将ES6
的一些语法进行编译转换,比如:箭头函数
、...运算符
等
但是如果是async 函数
、promise 对象
、数组的一些方法(includes)等,它却没办法处理,因为一些新的ES6及以上的特性,Babel 处理器
并不兼容
而如果想要将 js 兼容性问题彻底解决,则需要使用Corejs
,它是专门用来做 ES6 及 ES6+ API 的polyfill(补丁)
配置流程
首先,下载依赖包core-js
bash
npm i core-js
然后,在入口文件
按需引入core-js
补丁
由于,core-js
是针对Babel
的补丁,因此对代码的编译解析还是需要Babel 处理器
来进行,只是需要在Babel 配置文件
对core-js
做一些配置
java
module.exports = {
presets: [
[
"@babel/preset-env",
// 按需加载core-js的polyfill
{ useBuiltIns: "usage", corejs: { version: "3", proposals: true } },
],
],
};
结语
本篇文章是在了解了Webpack 基础配置
之后的一些更加深入的思考学习,为了提高开发效率
、为了提升性能优化
、为了提高打包速率
、为了减少代码体积
而进行的更加深入的关于Webpack 配置
进阶学习。在学习完后,可以尝试搭建一个自己的前端项目开发脚手架