介绍
参考尚硅谷课程: www.bilibili.com/video/BV14T…
所谓高级配置其实就是进行Webpack优化,让我们的代码在编译/运行时性能更好~ 一般会从以下角度进行优化:
- 提升开发体验
- 提升打包构建速度
- 减少代码体积
- 优化代码运行性能
1.提升开发体验
SourceMap
为什么
开发时我们经过Weboack编译后的代码,css和js合并成了一个文件,多了很多其他代码。此时如果代码运行出现错误,提示代码错误位置我们是看不懂的。一旦开发代码文件很多的情况下,很难去发现错误出现在哪里
是什么
SourceMap是用来生成源代码与侯建后代码一一映射的文件的方案 它会生成一个xxx.map文件,里面包含源代码和构建后代码每一行,每一列的映射关系。当构建后代码出错了,会通过xxx.map文件,从构建后代码出错位置找到映射后源代码出错位置,从而让浏览器提示源代码文件出错位置,帮助我们更快找到错误根源
怎么用
通过查看Webpack DevTool文档可知,SourceMap值有很多种情况 但实际开发时我们只需要关注两种情况即可:
- 开发模式:
cheap-module-source-map
优点:打包编译速度快,只包含行映射
缺点:没有列映射
module.exports={
mode:'development',
devtool:'cheap-module-source-map'
}
- 生产模式:
source-map
优点:包含行/列映射
缺点:打包编译速度更慢
module.exports={
mode:'development',
devtool:'source-map'
}
2.提升打包构建速度
HotModuleReplacement
为什么
开发时我们修改了其中一个模块代码,Webpakc默认会将所有模块全部重新打包编译,速度很慢 所以我们需要做到修改某个模块代码,就只有这个模块代码进行重新打包编译,其他模块不变,这样打包速度就能变快
是什么
HotModuleReplacement(HMR/热模块替换):在程序运行中,替换,添加或删除模块,而无需重新加载整个页面
怎么用
1.基本配置
module.exports={
devServer: {
host: 'localhost',
port: '3000',
open: true,//是否自动打开浏览器,
hot:true, //开启HMR功能,(只能用于开发环境,生产环境不需要)
},
}
Include/Exclude
为什么
开发时我们需要使用第三方库或插件,所有文件都下载到了node_modules中了,而这些文件是不需要编译可以直接使用的。 所以我们在对js文件处理时,要排除node_modules里面的文件
是什么
- Include 包含,只处理xxx文件
- Exclude 排除,除了xxx文件以外都处理
怎么用
同时只能使用一种
{
test: /\.js$/,
exclude: /node_modules/,//排除node_modules中的js文件(这些文件不处理)
//include: path.resolve(__dirname, '../src'),//只处理src下的文件,其他的不处理
loader: 'babel-loader',
//可以单独写babel.config.js去配置
options: {
presets: [
"@babel/preset-env"
]
}
}
new ESLintPlugin({
//检测哪些文件
context: path.resolve(__dirname, '../src'),
exclude: 'node_modules' //默认值
}),
Cache
为什么
每次打包时js都要经过Eslint检查和Babel编译,速度比较慢 我们可以缓存之前的Eslint和Babel编译结果,这样第二次打包时速度就会更快了
是什么
对Eslint检查和Babel编译结果进行缓存
怎么用
Eslint:
{
test: /\.js$/,
exclude: /node_modules/,//排除node_modules中的js文件(这些文件不处理)
include: path.resolve(__dirname, '../src'),//只处理src下的文件,其他的不处理
loader: 'babel-loader',
// 可以单独写babel.config.js去配置
options: {
presets: [
"@babel/preset-env"
],
cacheDirectory: true,//开启babel缓存
cacheCompression: false,//关闭缓存文件压缩
}
}
Babel:
new ESLintPlugin({
//检测哪些文件
context: path.resolve(__dirname, '../src'),
exclude: 'node_modules',//默认值
cache: true,
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache')
}),
注意:此时打包的时候,会报一个关于oneof的错误,不清楚是哪里冲突了,于是先把oneof注释了,回头再解决
Thead
为什么
当项目越来越庞大时,打包速度越来越慢,甚至需要一个下午才能打包出来代码。这个速度是比较慢的 我们想要继续提升打包速度,其实就是要提升js的打包速度,因为其他文件都比较少 而对js文件处理主要就是eslint、babel、Terser三个工具,所以我们要提升它们的运行速度 我们可以开启多进程同时处理js文件,这样速度就比之前的单进程打包更快了
是什么
多进程打包:开启电脑的多个进程同时干一件事,速度更快
怎么用
我们启动继承的数量就是我们CPU的核数 1.如何获取CPU核数,因为每个电脑都不一样
//nodejs核心模块,直接使用
const os =require('os')
//cpu核数
const threads=os.cpus().length
2.下载包:npm i thread-loader -D
3.使用
{
test: /\.js$/,
exclude: /node_modules/,//排除node_modules中的js文件(这些文件不处理)
use: [
{
loader: 'thread-loader',//开启多进程
options: {
works: threads
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true,//开启babel缓存
cacheCompression: false,//关闭缓存文件压缩
}
}
]
}
Eslint开启多进程
new ESLintPlugin({
//检测哪些文件
context: path.resolve(__dirname, '../src'),
exclude: 'node_modules',//默认值
cache: true,
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslintcache'),
threads,//开启多进程
}),
3.减少代码体积
Tree Shaking
为什么
开发时我们定义了一些工具函数库,或者引用第三方工具函数库或组件库 如果没有特殊处理的话,我们打包时会引入整个库,但实际上我们可能只用上极小部分功能 这样整个库都打包进来的话,体积太大
是什么
Tree Shaking是一个术语,同程用于描述JavaScript中没有使用上的代码
注意:它依赖ES Moudle
怎么用
Webpack已经默认开启了这个功能,无需其他配置
Babel
为什么
Babel 为编译的每个文件都插入了辅助代码,使代码体积过大! Babel 对一些公共方法使用了非常小的辅助代码,比如_extend。默认情况下会被添加到每一个需要它的文件中 你可以将这些辅助代码作为一个独立模块,来避免重复引入
是什么
@babel/plugin-transform-runtime:禁用了Babel自动对每个文件的runtime注入,而是引入@babel/plugin-transform-runtime 并且使所有辅助代码从这里引用
怎么用
下载包:npm i @babel/plugin-transform-runtime -D
{
test: /\.js$/,
exclude: /node_modules/,//排除node_modules中的js文件(这些文件不处理)
use: [
{
loader: 'thread-loader',//开启多进程
options: {
works: threads
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true,//开启babel缓存
cacheCompression: false,//关闭缓存文件压缩
plugins: ['babel/plugin-transform-runtime'],//减少代码体积
}
}
]
}
Imgae Minimizer
为什么
开发中如果项目中引用了较多图片,那么图片体积会比较大,将来请求速度比较慢 我们可以对图片进行压缩,减少图片体积 注意:如果项目中图片都是在线链接,那就不需要了。本地项目静态图片才需要进行压缩
是什么
imgae-minimizer-webpack-plugin:用来压缩图片的插件
怎么用
1.下载包
npm i imgae-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无损/有损的区别
4.优化代码运行性能
Code Split
为什么
打包代码时会将所有js文件打包到一个文件中,体积太大了。如果我们只要渲染首页,就应该只加载首页的js文件,其他我呢间不应该加载 所以我们需要将打包生成的文件进行代码分割,生成多个js文件,渲染哪个页面就只加载某个js文件,这样加载的资源就少,速度就更快
是什么
代码分割(Code Split)主要做了两件事: 1.分割文件:将打包生成的文件进行分割,生成了多个js文件 2.按需加载:需要哪个文件就加载哪个文件
怎么用
代码分割实现方式有不同的方式,为了更加体现它们之间的差异,我们会分别创建新的文件来演示
第一种多入口打包
entry: {
//有多个入口文件,多入口
app: './src/app.js',
main:'./src/main.js'
},
output: {
//文件输出的路径
//__dirname nodejs的变量,代表当前文件的文件夹目录
path: path.resolve(__dirname, '../dist'),
//入口文件打包的输出文件名
filename: '[name].js',//webpack命名方式。[name]以文件名命名
//打包前,自动清理上次打包的文件夹,并再次打包
clean: true
},
第二种方式optimization splitChunks 使用demo1的目录结构创建demo2,简单配置下webpack
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build'),
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true,
},
}),
],
optimization: {
splitChunks: {
chunks: 'all',
},
},
mode: 'production',
};
optimization splitChunks的作用就是:
可以将mode_modules中代码单独打包到一个chunk最终输出 自动分析多入口chunk中有没有公共的文件,有的话就会将公共文件单独打包一个chunk(单入口情况下)
第三种方式使用js方法 在以下代码中加入imort()方法
function sum(...arg) {
return arg.reduce((p, c) => p + c, 0);
}
import(/* webpackChunkName: 'test' */'./test').then(({ mul, count }) => {
// 文件加载成功
// eslint-disable-next-line
console.log(mul(2, 5));
})
.catch(() => {
// eslint-disable-next-line
console.log('文件加载失败');
})
// eslint-disable-next-line no-console
console.log(sum(2, 3));