高级也就是相对于基础的优化。从以下角度进行优化: 提升开发体验; 提升打包构建速度 减少代码体积 优化代码运行性能
提升开发体验
SourceMap
为什么
SourceMap用来生成源代码与与构建后的代码--映射的文件的方案。 Source map可以理解为一个地图, 通过它可以获知编译后的代码 对应编译前的代码位置。这样当代码遇到异常, 我们就可以通过报错信息定位至准确的位置。 同时在浏览器 sources 也可以查看到源码。
是什么
开发模式
- cheap-module-source-map
优点:打包编译速度快,只包含行映射 缺点:无列映射
怎么用
在开发模式下配置
代码语言:javascript复制devtool:"cheap-module-source-map"
生产模式
- source-map
优点:包含行列映射 缺点:打包编译速度慢
在生产模式下配置
代码语言:javascript复制devtool:"source-map"
提升打包构建速度
Hot Module Replacement 热模块替换
为什么
我们在修改代码的时候,只修改了一个模块,webpack会默认把所有模块重新打包一遍。但是我们只想把修改的模块重新打包,提升速度。
是什么
Hot Module Replacement 热模块替换
怎么用
通过在devServer设置hot:true
代码语言:javascript复制 devServer:{
host:"localhost", //启动服务器的域名
port:"3000", //启动服务器端口号
open:true, //是否自动打开浏览器
hot:true, //打开hmr
},
js使用hml,在main.js中设置
代码语言:javascript复制if(module.hot){
//判断是否支持热模块功能
module.hot.accept("./js/count")
module.hot.accept("./js/sum")
}
oneOf
每个文件只能被一个loader处理
代码语言:javascript复制 rules: [
{
oneOf: [ //每个文件只能被其中一个loader处理
{ test: /.css$/, 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", "less-loader"] },
{
test: /.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
generator: {
//输出文件名称,10代表hash值只取前10位
filename: "static/images/[hash:10][ext][query]",
},
},
{
test: /.(ttf|woff?2|)$/,
type: "asset/resource",
generator: {
//输出名称,10代表hash值只取前10位
filename: "static/media/[hash:10][ext][query]",
},
},
{
test: /.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
],
},
],
Include和Exclude
为什么
开发时我们需要使用第三方库和插件,所有文件都下载到node_modules中了,而这些文件是不需要编译直接使用的。所以我们在对js文件进行处理时,要排除node_modules中的文件。
是什么
include:包含,只处理xxx文件 exclude:排除,排除xxx文件以外的文件都处理
怎么用
exclude和include只使用一个
代码语言:javascript复制{
test: /.js$/,
exclude: /node_modules/, //排除node_modules,其他都处理
// include:path.resolve(__dirname,"./src"), //只处理src下的文件,其他不处理
loader: "babel-loader",
},
Cache
为什么
每次打包都需要经过eslint检查和babel编译,速度比较慢 我们可以缓存之前的eslint检查和babel编译结果,这样二次打包的速度就更快了
是什么
对eslint检查和babel编译进行缓存
怎么做
代码语言:javascript复制{
test: /.js$/,
exclude: /node_modules/, //排除node_modules,其他都处理
// include:path.resolve(__dirname,"./src"), //只处理src下的文件,其他不处理
loader: "babel-loader",
options:{
cacheDirectory:true, //开启babel缓存
cacheCompression:false,//关闭缓存文件压缩
}
},
测试:打包完成后在node_modules中增加了cache的文件
Thead多进程
为什么
当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。 我们想要继续提升打包速度,其实就是要提升 js 的打包速度,因为其他文件都比较少。 我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了。
是什么
多进程打包:开启电脑的多个进程同时干一件事,速度更快。
需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销。
怎么用
下载包
代码语言:javascript复制npm i thread-loader -D
在webpack.prod.js获取cpu核数
代码语言:javascript复制// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
//TerserPlugin webpack自带压缩js
const TerserPlugin = require("terser-webpack-plugin");
配置生产环境
代码语言:javascript复制use: [
{
loader:"thread-loader", //开启多进程
options: {
workers: threads, //开启个进程数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, //开启babel缓存
cacheCompression: false, //关闭缓存文件压缩
},
},
],
代码语言:javascript复制plugins: [
// 压缩js 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads // 开启多进程
})
],
optimization
对打包结果进行优化,放置压缩操作
代码语言:javascript复制 const TerserWebpackPlugin = require("terser-webpack-plugin");
optimization: {
minimizer: [
new TerserPlugin({
parallel: threads, // 开启多进程
}),
//压缩css
new CssMinimizerPlugin(),
],
},
开发环境配置同上
减少代码体积
tree-shaking
为什么
开发时我们引用一些工具库或第三方组件库,如果没有特殊处理,我们打包时会引入整个库,体积太大。
是什么
tree-shaking用于描述移除js中的没有用到的代码。 注意:依赖es module
怎么用
webpack生产环境默认开启,无需配置
babel
为什么
babel为编译的每个文件都插入了辅助代码,使体积过大。所以需要将重复的辅助代码作为一个独立的模块,避免重复使用。
是什么
@babel/plugin-transform-runtime 禁用babel自动对每个文件的runtime注入,而是引入。并且使所有代码从这里引入。
怎么用
安装包
代码语言:javascript复制npm i @babel/plugin-transform-runtime -D
配置(测试环境和生产环境都要配置)
代码语言:javascript复制{
loader: "babel-loader",
options: {
cacheDirectory: true, //开启babel缓存
cacheCompression: false, //关闭缓存文件压缩
plugins:["@babel/plugin-transform-runtime"]
},
},
Image Minimizer
为什么
如果开发中引入了较多图片,那么图片体积会比较大,将来请求速度比较慢。我们可以对图片进行压缩,减少体积
注意:如果图片是在线链接则不需要,本地图片则需要打包
是什么
image-minimizer-webpack-plugin用来压缩图片的插件
怎么用
代码语言:javascript复制下载 npm i image-minimizer-webpack-plugin imagemin -D
无损压缩
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
有损压缩
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant,
imagemin-svgo -D
配置(生产模式)
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[ "svgo", { plugins: [ "preset-default", "prefixIds", { name: "sortAttrs", params: { xmlnsOrder: "alphabetical", }, }, ],
},
],
],
},
},
}),
打包时会报错,安装两个文件(jpegtran.exe,optipng.exe官网下载)到 node_modules 中才能解决。 需要复制到 node_modulesjpegtran-binvendor
下面
优化代码运行性能
code split
为什么
打包代码的时候会把所有js文件打包到一个文件下。体积太大,如果只想渲染首页,只需要加载首页的js。其他的js文件不加载。 所以我们需要将打包的代码进行分割,生成多个js文件,按需加载。
是什么
1.分割文件。将打包的文件进行分割,生成多个js文件。 2.按需加载。需要哪个文件加载哪个文件
怎么做
参考链接blog.csdn.net/goudexingwu…
实际开发时多为单页面应用,在生产环境的optimization中配置
代码语言:javascript复制//代码分割操作
splitChunks:{
chunks:"all",
//其他使用默认值
}
测试
将main.js中引入的文件注释,在点击按钮时才加载此文件。在html文件中写点击按钮 main.js按需引入测试如下
document.getElementById("btn").onclick = function () {
import("./js/count").then(({ count }) => {
console.log(count(2, 9));
});
};
count文件在一进入页面时不加载,只有点击按钮时才加载。
给模块命名
// webpack特殊的命名方式/*webpackChunkName: "count"*/
document.getElementById("btn").onclick = function () {
import(/*webpackChunkName: "count"*/ "./js/count").then(({ count }) => {
console.log(count(2, 9));
});
};
生产环境在output中配置
代码语言:javascript复制 //给打包输出的其他文件命名
chunkFilename:"static/js/[name].js",
统一命名配置
//入口文件打包输出的文件名
filename: "static/js/[name].js",
chunkFilename:"static/js/[name].chunk.js",
//对其他文件命名资源处理
assetModuleFilename: 'static/media/[hash:10][ext][query]',
对css统一命名做处理
new MiniCssExtractPlugin({ filename: "static/css/[name].css",
chunkFilename:"static/css/[name].chulk.css" }),
preload/prefetch(兼容性不太好)
为什么
虽然我们前面已经做了代码分割,按需加载,但是有些资源需要我们点击或者触发时才加载,如果文件体积过大,加载慢,用户体验极其不好。我们需要在浏览器的空闲时间加载后续的资源,需要用到preload和prefetch。
是什么
preload:告诉浏览器立即加载的资源
prefetch:告诉浏览器在空闲时间才可以加载资源
共同点:
只加载不执行,有缓存
区别
preload加载优先级高,只可以加载当前页面的资源
prefetch既可以加载当前页面要使用的资源,也可以加载下一个页面要使用的资源。
怎么用
下载包
代码语言:javascript复制npm i --save-dev @vue/preload-webpack-plugin
本来使用的是 preload-webpack-plugin,但其与webpack5不兼容所以采用其替代品
配置
代码语言:javascript复制const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
new PreloadWebpackPlugin({
rel:"preload",
as:"script",
// rel:"prefetch",
})
代码语言:javascript复制//有一个文件发生变化,只当前文件的缓存变化,其他文件的换成不受影响
runtimeChunk:{
name:(entrypoint) => `runtime-${entrypoint.name}.js`,
}
core-js
为什么
babel对js的处理无法处理async函数,promise对象等,存在一定的兼容性问题。
是什么
专门做es6及以上api的polyfill(补丁)
怎么用
修改main.js
代码语言:javascript复制安装包
npm i core-js
完整引入
在main.js中引入:import "core-js"
按需加载
import "core-js/es/promise"
按需自动引入
修改babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", //按需加载自动引入
corejs: 3,
},
],
], //预设,babel插件。扩展babel功能,编译es6语法
};
PWA
为什么
用户可以离线访问
是什么
渐进式网络应用程序,在离线时应用程序能够正常运行。内部通过service workers实现。
怎么用
安装包npm i workbox-webpack-plugin -D 在生产环境配置
代码语言:javascript复制const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,//这些选项帮助快速启用
skipWaiting: true//不允许遗留任何“旧的”
})
在main.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('sw注册成功了 ', registration);
}).catch(registrationError => {
console.log('SW注册失败 ', registrationError);
});
});
}
此时sw注册失败,需要npm i serve -g后serve dist访问,即可在无网络时访问页面。