一、优化打包构建速度
1.oneOf
使用:在webpack.config.js的module的rules中将一些loader的配置放在oneOf的数组中即可
module: {
rules: [
{//匹配js文件,后面的babel也会匹配js文件,所以将eslint放在外面
test: /\.js$/,
exclude: /node_modules/,//排除node_modules下的文件
loader: 'eslint-loader',
options: {
fix: true//自动修复eslint的错误
}
},
{
oneOf: [
{
test: /\.less$/,
use: [
'style-loader', 'css-loader', 'less-loader'
],
},
{
test: /\.css$/,
use: [
'style-loader', 'css-loader', 'postcss-loader',
],
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',//预设,只是babel做怎么样的兼容性处理
{
useBuiltIns: 'usage',// 按需加载
corejs: {//指定core-js的版本
version: 3
},
targets: {//指定兼容性到浏览器的哪个版本
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
}
}
]
}
]
}, 注意:oneOf中的loader一种文件类型只会匹配一个loader,如果有两个不同的loader配置则后面的loader会失效,需要把其中一个放在oneOf的外面
2.babel缓存
设置babel里loader的配置:cacheDirectory:true
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',//预设,只是babel做怎么样的兼容性处理
{
useBuiltIns: 'usage',// 按需加载
corejs: { version: 3 },//指定core-js的版本
targets: {//指定兼容性到浏览器的哪个版本
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
],
cacheDirectory: true//设置babel缓存,第二次构建时会读取之前的缓存
}
}
3.多进程打包
使用的loader:thread-loader
加上thread-loader,进程启动大概需要600ms,进程通信也需要开销,只有工作消耗时间长,才需要多进程打包,因此一般用于babel中
{
test: /\.js$/,
use: [
{
loader: 'thread-loader',//开启多进程打包,一定要注意顺序,在babel-loader后执行
options: {
workers: 2
}
},
{
loader: 'babel-loader',
options: {
presets: [[
'@babel/preset-env', {
useBuiltIns: 'usage',
corejs: { version: '3' },
targets: {
chrome: '60',
firefox: '60'
}
}
]]
}
}
]
}
4.externals
拒绝一些库参与打包,但在页面使用cdn链接的方式引入(不然没有效果),比如jquery
externals:{
jquery:'jQuery'//拒绝jquery参与打包,从而使构建速度更快
} 5.dll
类似externals指示哪些库是不参与打包的,但是dll会对某些库单独进行打包,将多个库打包为一个chunk
比如将node_modules中的库拆分打包为不同的文件/chunk,更加利于性能优化
(1)新建一个webpack.dll.js文件进行配置(以打包jquery为例)
配置写好后使用webpack --config webpack.dll.js命名生成打包的库以及manifest.json文件到dll目录下
let { resolve } = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
jquery: ['jquery']//最终打包生成的名字为jquery,要打包的库是数组中的
},
output: {
filename: '[name].js',//打包输出的名字取的是entry的key值
path: resolve(__dirname, 'dll'),//打包输出的路径
library: '[name]_[hash]'//打包暴露出去的库的名字
},
plugins: [
new webpack.DefinePlugin({//打包生成一个mainfest.json文件,提供映射关系,告诉webpack下次打包的时候不要再打包其中的内容
name: '[name]_[hash]',//映射库的暴露的内容名称
path: resolve(__dirname, 'dll/manifest.json')//输出文件路径
})
],
mode: 'production',
} (2)在webpack.config.js中引入并配置插件
const AddAssetHtmlWebpackPlugin = require('add-asset-html-Webpack-plugin')
new webpack.DllReferencePlugin({//告诉webpack哪些库不参与打包
manifest:resolve(__dirname,'dll/manifest.json')
})
new AddAssetHtmlWebpackPlugin({//将某个文件打包输出,并在html中自动引入
filepath:resolve(__dirname,'dll/jquery.js')
}) 二、优化代码运行的性能
1.缓存(hash-chunkhash-contenthash)
(1)资源缓存出现的问题:
在缓存有效期间,如果代码有更新,重新打包构建刷新的话,浏览器的页面不会有任何变化
(2)解决方法:对打包文件的名字做一些操作
1)hash
每次webpack打包的时候都会生成一个hash值,取打包生成的hash值拼接在输出文件名后就会更新资源,html就会引入这个新的资源,浏览器就会去服务器重新请求这个新的资源
output: {
filename: 'js/built.[hash:10].js',//打包输出后会输出到js目录下,取hash的前十位
path: resolve(__dirname, 'build')
}, 出现的问题:css和js同时使用一个hash值,如果只改动一个会重新打包,导致所有的缓存失效
2)chunkhash
根据chunk生成hash,如果资源来自于同一个chunk就使用同一个hash
output: {
filename: 'js/built.[chunkhash:10].js',//打包输出后会输出到js目录下,取chunkhash的前十位
path: resolve(__dirname, 'build')
}, 出现的问题:js和css还是属于同一个chunk,因为css是引入到js中的
3)contenthash
根据文件的内容生成hash,不同的文件hash值一定不同
output: {
filename: 'js/built.[contenthash:10].js',//打包输出后会输出到js目录下,取contenthash的前十位
path: resolve(__dirname, 'build')
},
2.tree shaking
(1)作用
去除在程序中没有使用的代码,让代码体积变得更小
(2)前提
必须使用ES6模块化
开启production环境
(3)注意的问题
不同的版本可能会有一些差异,将css文件以及@babel/polyfill当做未使用的代码忽略
测试:在package.json中设置“sideEffects”:false,表示所有代码都可以进行tree shaking,这时候重新打包构建输出的资源就没有css文件了
解决:
"sideEffects":["*.css","*.less"]//指明哪些文件不用tree shaking
3.code split
(1)多入口代码分割
有几个入口,最终输出就有几个bundle
entry: {
index: './src/index.js',
a: './src/js/a.js'
},
output: {
filename: 'js/[name].[contenthash:10].js',//打包输出后会输出到js目录下
path: resolve(__dirname, 'build')
}, 代码结果: (2)optimization
1)作用:
可以将node_modules中的文件单独打包为一个chunk输出
如果是多入口,会自动分析多入口文件,有多个文件中使用同一份公共的资源的话,会将公共的资源打包为单独的chunk
2)使用:
在webpack.confiig,js中配置optimization
optimization: {
splitChunks: {
chunks: 'all'
}
}, (3)通过js代码让某个文件打包为一个单独的chunk
在入口js文件中将某个文件使用import单独打包
import('./js/a.js').then(() => {
console.log('文件加载成功')
}).catch(() => {
console.log('文件加载失败')
}) 单独打包后的文件,默认使用id命名,如果想要对打包后的文件重命名的话,使用注释的方式在文件路径前面加一个webpackChunkName: import(/* webpackChunkName:'test' */'./js/a.js').then(() => {
console.log('文件加载成功')
}).catch(() => {
console.log('文件加载失败')
})
4.懒加载/预加载
正常的加载:并行加载,同一时间加载多个文件,所有的文件会全部先加载完
(1)懒加载:lazy loading
场景:比如在点击按钮的时候才想去加载某个文件
使用:在js文件中使用import(类似code split的第三种方式)
import(/* webpackChunkName:'test' */'./js/a.js').then(() => {
console.log('文件加载成功')
}).catch(() => {
console.log('文件加载失败')
}) (2)预加载:prefetch
在使用之前加载js文件,等其他资源加载完毕,浏览器空闲的时候加载webpackPrefetch的资源
import(/* webpackChunkName:'test',webpackPrefetch:true */'./js/a.js').then(() => {
console.log('文件加载成功')
}).catch(() => {
console.log('文件加载失败')
})
5.PWA
渐进式网络开发应用程序:由service worker+catch完成的,使网页像APP应用程序一样,离线也可以访问,性能会更好
使用的插件:workbox-webpack-plugin
(1)下载和引入插件
npm i workbox-webpack-plugin
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
new WorkboxWebpackPlugin({//最终会生成一个service-worker.js文件
clientsClaim:true,//帮助serviceWorker快速启动
skipWaiting:true//删除旧的serviceWorker
}) (2)注册serviceWorker
一般在入口js文件中注册:
if('serviceWorker' in navigator){
window.addEventListener('load',function(){
navigator.serviceWorker.register('service-worker.js').then(()=>{
console.log('注册成功');
}).catch(()=>{
console.log('注册失败')
})
})
} (3)serviceWorker代码必须运行在服务器上,本地测试可以先安装serve,再通过serve指令启动
npm i serve -g//全局安装serve serve -s build//将build下的资源作为静态资源暴露出去,启动服务器
(4)测试:浏览器设置为下图的offline后,刷新网页,仍然存在刷新前的网页

京公网安备 11010502036488号