【webpack4】第五部分 webpack优化配置
文章目录
5. webpack优化配置
5.1 HMR
-
HMR:hot module replacement 热模块替换
-
作用:当一个模块发生变化的时候,只会重新打包这个模块(而不是重新打包所有的模块),极大提高了构建速度
-
开启热模块替换只需要在
devServer下设置hot:true
需要注意:– 样式文件:可以使用
HMR功能,因为style-loader内部已经实现了– html文件:默认是不使用HMR功能,但是开启
HMR功能会导致html文件不能热更新(热更新:本地写的代码没有重新编译重新更新)(html本身只有一个所以其实不需要HMR处理) -
解决的办法:修改entry,
entry:['./src/index.js','./src/index.html'] -
js文件:默认也是不使用
HMR功能,需要使用HMR配置如下:
index.js
if(module.hot)
{
//如果module.hot为真就表示已经开启了HMR
// 下面代码表示监视某个模块,一旦模块被修改就执行回调函数
module.hot.accept('./test.js',function(){
//重新再次调用函数
test()
})
}
webpack.config.js
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
/*
开启热模块替换只需要在devServer下设置hot:true
需要注意:
- 样式文件:可以使用HMR功能,因为style-loader内部已经实现了
- js文件:默认是不使用HMR功能
- html文件:默认是不使用HMR功能,但是开启HMR功能会导致html文件不能(不需要HMR处理)
热更新(本地写的代码没有重新编译重新更新)
解决的办法:修改entry, entry:['./src/index.js','./src/index.html']
*/
module.exports = {
entry:['./src/index.js','./src/index.html'],
output:{
filename:'js/built.js',
path:resolve(__dirname,"build")
},
module:{
rules:[
//打包css资源
{
test:/\.css$/,
use:['style-loader','css-loader']
},
//打包less资源
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader']
},
//打包图片资源(css/less)
{
test:/\.(jpg|png|webp|gif)$/,
loader:'url-loader',
options:{
limit: 9*1024,
name:'[hash:10].[ext]',
esModule:false,
// 将打包好的图片资源放在imgs文件加下
outputPath:'imgs'
}
},
//打包html中的图片
{
test:/\.html$/,
loader:'html-loader',
options:{
esModule:false
}
},
//打包其他资源
{
exclude:/\.(html|css|less|js|jpg|png|webp|gif)$/,
loader:'file-loader',
options:{
// 将打包好的图片资源放在media文件加下
outputPath:'media'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
open:true,
port:8001,
//开启热模块模式
hot:true
},
mode:'development'
}
5.2 source-map
5.2.1 什么是source-map?
一种提供源代码到构建后代码映射的技术,说人话就是:如果我们构建后的代码出错了,可以通过映射找到源代码错误的地方。
5.2.2 种类
- source-map
- 外部,能够报出错误代码的准确信息和源代码的错误位置
- inline-source-map
- 内联,只生成一个内联source-map,能够报出错误代码的准确信息和源代码的错误位置
- hidden-source-map
- 外部,能够报出错误代码的原因,但是没有错误位置的信息,不能够追踪源代码的错误位置,只能提示到构建后代码的错误位置
- eval-source-map
- 内联,每一个文件都生成对应的source-map,都在eval。能够报出错误代码的准确信息和源代码的错误位置
- nosource-source-map
- 外部,能够报出错误代码的准确信息,但是没有任何源代码的信息 (彻底隐藏)
- cheap-source-map
- 外部,能够报出错误代码的准确信息和源代码的错误位置,但是只能位置只能准确到行
- cheap-module-source-map
- 外部,能够报出错误代码的准确信息和源代码的错误位置
5.2.3 开放环境和调试环境的需求
开发环境:速度快,调试好。推荐:eval-source-map
生成环境:源代码隐藏(根据需求),调试好。推荐:source-map
如果需要隐藏:nosources-source-map | hidden-source-map
module.exports = {
....
....
....
....
devtool:'eval-source-map', //配置
mode:'development'
}
5.3 oneOf
oneOf作用:提高loader处理的性能,避免重新一遍一遍执行loader影响性能
注意点:不能有两个配置同时处理同一个类型的文件(例如:处理js的时候)那么我们就将其中一个提取出oneof外面
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:['./src/index.js','./src/index.html'],
output:{
filename:'js/built.js',
path:resolve(__dirname,"build")
},
module:{
rules:[
{
/*
oneof作用:提高loader处理的性能,避免重新一遍一遍执行loader影响性能
注意点:不能有两个配置同时处理同一个类型的文件(例如:处理js的时候)
那么我们就将其中一个提取出oneof外面
*/
oneOf:[
//打包css资源
{
test:/\.css$/,
use:['style-loader','css-loader']
},
//打包less资源
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader']
},
//打包图片资源(css/less)
{
test:/\.(jpg|png|webp|gif)$/,
loader:'url-loader',
options:{
limit: 9*1024,
name:'[hash:10].[ext]',
esModule:false,
// 将打包好的图片资源放在imgs文件加下
outputPath:'imgs'
}
},
//打包html中的图片
{
test:/\.html$/,
loader:'html-loader',
options:{
esModule:false
}
},
//打包其他资源
{
exclude:/\.(html|css|less|js|jpg|png|webp|gif)$/,
loader:'file-loader',
options:{
// 将打包好的图片资源放在media文件加下
outputPath:'media'
}
}
]
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
open:true,
port:8001,
//开启热模块模式
hot:true
},
devtool:'eval-source-map',
mode:'production'
}
5.4 缓存
5.4.1 babel缓存:cacheDiretory:true
{
test:/\.js$/,
exclude:/node_module/,
loader:'babel-loader',
cacheDirectory:true
}
5.4.2 文件资源缓存:(利用维护hash值的变化)
-
hash:每次webpack构建时会生成一个唯一的hash值– 问题:因为js和css同时使用hash值(每次都会生成唯一的值,不管文件是否发生修改)就会导致如果重新打包,会导致所有的缓存都失效
-
chunkhash:根据chunk生成的hash值,如果打包的来源来自同一个chunk,那么hash值一样– 问题:js和css的
hash值还是一样,因为css是在js中被引入的所以同属一个chunk,所有由入口文件引入的文件最终都会形成一个chunk -
contenthash:根据文件的内容生成hash值,不同文件的hash值不一样,如果文件没有修改hash值是不会变的,如果文件修改hash值也会变化
具体代码
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry:"./src/js/index.js",
output:{
filename:"js/built.[contenthash:10].js",
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader'],
},
{
test:/\.less$/,
use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
new MiniCssExtractPlugin({
filename:'css/built.[contenthash:10].css'
})
],
mode:'development'
}
5.5 tree shaking
作用:去除无用的代码,减少代码的体积
使用的前提条件:
- 使用ES6模块化
- 开启生产模式
- 满足上述2个条件就会开启
tree shaking
在package.josn中配置"sideEffects":false,表示所有的代码都没有副作用(都可以进行tree shaking),这样写可能会把css、 @babel/ployfill直接干掉,因为我们只是引入并没有使用,有可能会被当做无用代码被干掉。
解决办法:"sideEffects":["*.css","*.less"] ,这样就可以保留css
const {resolve} = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:"./src/js/index.js",
output:{
filename:"js/built.js",
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
removeComments:true,
collapseWhitespace:true
}
})
],
devServer:{
contentBase:resolve(__dirname,'build'),
compress:true,
port:8081,
open:true
},
mode:'production'
}
5.6 code split
5.6.1 demo1
多入口和单入口的不同写法
下图为多入口打包后的结果:

const {resolve} = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 单入口
// 单页面对应单入口
// entry:"./src/js/index.js"
//多入口 特点:有多少个入口最终就输出多少个bundle
//多页面对应多入口
entry:{
index:"./src/js/index.js",
test:"./src/js/test.js"
},
output:{
// [name]:表示取文件名
filename:"js/[name].[contenthash:10].js",
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
removeComments:true,
collapseWhitespace:true
}
})
],
mode:'production'
}
5.6.2 demo2
配置optimization,对于多入口文件来说可以自动分析多入口chunk中,是否有公共的依赖,有的话会单独打包一份,对于单文件来说享受不到这个功能,demo3会讲,怎么解决。
作用:
1. 可以将node_module中的代码单独打包一个chunk输出,以便于后续再次进行优化(单入口和多入口都可以用)
2. 自动分析多入口chunk中,是否有公共的依赖,如果有会单独打包一份(多入口)
optimization:{
splitChunks:{
chunks:'all'
}
}

具体代码
const {resolve} = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:{
index:'./src/js/index.js',
test:'./src/js/test.js'
},
output:{
filename:"js/[name].[contenthash:10].js",
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
removeComments:true,
collapseWhitespace:true
}
})
],
/*
1. 可以将node_module中的代码单独打包一个chunk输出,以便于后续再次进行优化
2. 自动分析多入口chunk中,是否有公共的依赖,如果有会单独打包一份
*/
optimization:{
splitChunks:{
chunks:'all'
}
},
mode:'production'
}
5.6.3 demo3
在入口文件中配置
将文件单独打包出来(通过js代码)
import 动态导入语法:可以将某个文件单独打包出来
/* webpackChunkName: 'test' */ :表示修改文件名

src/js/index.js
import "../css/test.css"
import(/*webpackChunkName: 'test' */'./test')
.then(({add})=>{
//文件加载成功
console.log(add(5,5));
}).catch(()=>{
//文件加载失败
console.log('文件加载失败!!');
})
webpack.config.js
const {resolve} = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:"./src/js/index.js",
output:{
filename:"js/[name].js",
path:resolve(__dirname,'build')
},
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:'css/built.css'
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
minify:{
removeComments:true,
collapseWhitespace:true
}
})
],
optimization:{
splitChunks:{
chunks:'all'
}
},
mode:'production'
}
5.7 懒加载和预加载
5.7.1 懒加载

懒加载也是依靠import动态导入实现的,也就意味着要先进行代码分隔才可以进行懒加载
懒加载:当文件需要的时候在进行加载
console.log('index文件被加载了!!');
document.getElementById('btn').onclick =function(){
//懒加载
import(/*webpackChunkName:'test'*/ './test.js')
.then(({mul})=>{
console.log(mul(5,6));
})
}
5.7.2 预加载

预加载:等到其他资源加载完后,浏览器空闲下进行加载,会在使用之前提前加载js文件
console.log('index文件被加载了!!');
document.getElementById('btn').onclick =function(){
// webpackPrefetch:true
import(/*webpackChunkName:'test' ,webpackPrefetch:true */ './test.js')
.then(({mul})=>{
console.log(mul(5,6));
})
}
5.8 多进程打包
npm install --save-dev thread-loader 需要下载的包
....
....
....
{
test: /\.js$/,
exclude: /node_modules/,
use: [
/*
开启多进程打包。
进程启动大概为 600ms,进程通信也有开销。
只有工作消耗时间比较长的包(例如:babel),才需要多进程打包
*/
{
loader: 'thread-loader', options: {
workers: 2 // 进程 2 个
}
},
{
loader: 'babel-loader', options: {
presets: [[
'@babel/preset-env',
{
useBuiltIns: 'usage', corejs: { version: 3 }, targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 开启 babel 缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
}
....
5.9 externals
作用:指示某些库不被打包
const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'production',
externals:{
// 拒绝jQuery被打包,所以需要在html中去导入jQuery
jquery:'jQuery'
}
}
5.10 dll
dll作用:会将第三方库单独进行打包
5.10.1 使用dll
-
新建一个新的文件
webpack.dll.js -
需要注意我们在运行
webpack时,默认是查找webpack.config.js配置文件,所以我们需要修改指令,来运行webpack.dll.js。指令:webpack --config webpack.dll.js -
webpack.dll.js
const {resolve} = require('path')
const webpack = require('webpack')
module.exports = {
entry:{
/*
最终打包生成的[name] --> jquery
['jQuery'] --> 要打包的库
*/
jquery:['jQuery']
},
output:{
filename:'[name].js',
path:resolve(__dirname,'dll'),
library:'[name]_hash' //表示要打包库向外暴露内容的名字
},
plugins:[
// 该插件打包一个manifest.json用来提供和jQuery之间的映射关系
new webpack.DllPlugin({
name:'[name]_hash', //映射库向外暴露内容的名字
path:resolve(__dirname,'dll/manifest.json') //输出文件的路径
})
],
mode :'production'
}
- webpack.config.js
const {resolve} = require('path')
const webpack = require('webpack')
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:'./src/js/index.js',
output:{
filename:'js/built.js',
path:resolve(__dirname,'build')
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
}),
// 用来告诉webpack哪些库不参与打包,并且告诉webpack使用时名称也得改
new webpack.DllReferencePlugin({
manifest:resolve(__dirname,'dll/manifest.json')
}),
//将某个文件打包输出并且在html中自动添加该资源
new AddAssetHtmlWebpackPlugin({
filepath:resolve(__dirname,'dll/jquery.js')
})
],
mode:'production'
}
5.11 性能优化总结
开发环境性能优化
- 优化打包构建速度
- HMR
- 优化代码调试
- source-map
生产环境性能优化
- 优化打包构建速度
- oneOf
- babel缓存
- 多进程打包
- externals
- dll
- 优化代码运行的性能
- 缓存(hash-chunkhash-contenthash)
- tree shaking
- code split
- 懒加载/预加载
总结
以上就是今天要讲的内容,希望对大家有所帮助!!!
本文详细介绍Webpack的各种优化配置方法,包括热模块替换(HMR)、source-map的使用、缓存策略、Tree-shaking、代码分割(code splitting)等,帮助开发者提升项目构建效率。
392

被折叠的 条评论
为什么被折叠?



