1.基础概念
entry:入口
output:输出
loader:模块转换器,将模块的原内容按照需求转换成新内容
plugin:扩展插件,在webpack构建过程的特定时机注入扩展逻辑,用来改变或优化构建结果
mode:控制打包环境,通过选择development,production或none中的一个,设置mode参数,可以启用webpack内置在相应环境的优化。默认值为production环境
devserver:小型的node.js expr服务器,使用webpack-dev-middleware中间件来通过webpack打包生成的资源文件提供web服务\
2.构建性能构建效率
2.1分析工具
2.1.1 内置工具profile选项:profile:true
执行 "build:report": "webpack --config ./webpack.config.js --json=stats.json"可生成json格式文件
官方可视化工具:webpack.github.io/analyse,加载生成文件,可看到性能
2.1.2 SpeedMeasurePlugin(每个Plugin,Loader耗时)
新建speedMeasure.js文件,执行 "build:speed": "webpack --config ./speedMeasure.js“
或者建立base.js,build.js,speedMeasure.js,修改执行命令为:"build": "webpack --config ./service/build.js"
\
2.2持久化缓存
在开发过程中,如果轻微的修改就需要运行全部的打包过程是一种巨大的浪费。使用缓存技术,存储中间产物就成了最有效的优化手段。
cache将首次构建持久化到文件系统中,在下次执行是跳过解析、链接、编译过程
2.3并行处理
HappyPack:多进程运行loader(停止维护)
Thread-loader:多进程运行资源加载(官方驱动)
Paraller-webpack:多进程运行多个webpack构建示例(多入口场景)
TerserWebpackPlugin:支持多进程方式执行压缩丑化
以Thread-loader举例:创建与销毁进程可能会带来反向优化,很多loader有不兼容的情况
\
2.4减少编译范围
2.4.1 LazyCompilation
异步引用模块的按需编译,require(‘./xxx’)或import(‘./xxx‘)不会立即编译
2.4.2 约束loader执行范围-exclude
处理node_modules中的js文件时直接跳过这个rule项,不执行文件的loader逻辑
2.4.3 对于已经打包集成的代码,无需再次编译
noParse跳过文件编译,其中提前打包的无需编译:前提条件是不包含import内容,无法TreeShaking,必须保证程序无语法错误
2.5 简化构建步骤
2.5.1开发模式禁用优化
Minimize压缩、Splitchunks分包、ConcatenateModules模块连接、UsedExports tree-shaking功能
\
2.5.2 关闭sourcemap
2.6 使用高效编译器(Esbuild、swc)
代码压缩优化
3.页面性能
3.1性能指标
web.dev/metrics,以用户为中心的性能指标是了解和改善网站体验的重要工具。TTFB(第一字节时间)、FCP(首次内容绘制)、LCP(最大内容绘制)、TTI(可交互时间)..
3.2性能指标工具
Chrome性能分析工具、Lightouse性能分析工具、Webpack-bundle-analyze
3.3模拟线上Webserver
运行"dev:server": "node ./service/index.js"
3.4分包策略与chunk
解决的问题:页面初始代码包过大,影响首屏渲染,无法有效应用缓存
3.4.1什么是chunk
此Webpack术语在内部用于管理捆绑过程。Bundle(输出束)由chunk组成,其中有几种类型(entry和child)。通常,chunk直接和bundle对应,但是有些配置不会产生一对一的关系
3.4.2分包策略
Initial chunk:entry模块及相应子模块打包成initial chunk
Async chunk:通过import(‘./xx‘)等语句导入的异步模块及相应子模块组成的async chunk
Runtime chunk:运行代码抽离成runtime chunk,可通过entry.runtime配置项实现(异步加载)
3.5代码压缩
减少体积,减少传输时间
Js:TerserWebpackPlugin
Css:cssminimizerwebpackplugin
Html:htmlMinifierTerser
Js压缩:terser是一个js的parse (解释)、mangler(绞肉机、丑化)、compressor(压缩机)移除不使用的代码,压缩多行代码为一行的工具集
3.6动态加载
模块懒加载,解决首屏性能
3.6.1实现原理
()=>import()函数、路由的支持、Webpack对import()函数的分包
3.7Treeshaking
别名叫树摇,最早是由Rollup实现,是一种采用删除不需要的额外代码的方式优化代码体积的技术。
3.7.1原理
Tree Shaking在去除代码冗余的过程中,程序会从入口文件出发,扫描所有的模块依赖,以及模块的子依赖,然后将它们链接起来形成一个“抽象语法树”(AST。随后,运行所有代码,查看哪些代码是用到过的,做好标记。最后,再将“抽象语法树”中没有用到的代码“摇落”。经历这样一个过程后,就去除了没有用到的代码。
3.7.2为什么CommonJS无法Treeshaking
CommonJS与ES6 Module模块的依赖的区别在于,CommonJS是动态的,ES6 Module是静态的。CommonJS导入时,require的路径参数是支持表达式的,路径在代码执行时是可以动态改变的,所以如果在代码编译阶段就建立各个模块的依赖关系,那么一定是不准确的,只有在代码运行了以后,才可以真正确认模块的依赖关系,因此说CommonJS是动态的。
3.7.3webpack精准使用TreeShaking的条件
(1)使用ES6 Module语法(即import和export)。 (2)确保没有@babel/preset-env等工具将ES6 Module语法转换为CommonJS模块。module:false (3)使用支持Tree Shaking的第三方库。
3.7.4开启Treeshaking
3.8作用域提升ScopeHoisting
好处:代码体积变小,声明代码被省略、代码运行时作用域更少,内存开销变小
3.9HTTP缓存机制优化
强缓存:也称为本地缓存,不向服务器发送请求,直接使用客户端本地缓存数据
强缓存失效的方法:文件名加版本号:index.js?version=1index.css?version=1、文件名哈希值~文件指纹
协商缓存:也称304缓存,向服务器发送请求,由服务器判断请求文件是否发生改变。如果未发生改变,则返回304状态码,通知客户端直接使用本地缓存;如果发生改变,则直接返回请求文件。
3.9.1缓存策略
(1)访问入口永远不缓存
(2)资源文件
设置强缓存并设置超长过期时间Cache-Control:max-age=31536000
资源文件更新时使用新的文件指纹
3.9.2哈希值与文件指纹
摘要与哈希算法:摘要算法又称哈希算法、散列算法。摘要也称哈希值,表示输入任意长度的数据,都会输出固定长度的数据。通过摘要算法(比如MD5和SHA-1)就可以得到该哈希值。
不定长输入转定长、摘要满足雪崩效应(剧烈变化)、单项不可逆
3.9.3Webpack与文件指纹
版本管理:
(1)在发布版本时,通过文件指纹来区分修改的文件和未修改的文件
(2)使用缓存:未修改的文件,文件指纹保持不变,浏览器继续使用缓存访问。
文件指纹设置:
我们在配置文件中,通过占位符设置文件指纹。
3.9.4利用express实现缓存
const http=require('http')
const express=require("express")
const ecstatic=require("ecstatic")
const history=require("connect-history-api-fallback")
const path=require("path")
const app=express()
app.use(history())
app.use(function(req,res,next){
console.log('url:',req.url)
if(req.url==='/index.html'){
res.set({
'Cache-control':'public,max-age=0',
'Expires':new Date(Date.now()+0).toUTCString()
})
}else{
res.set({
'Cache-control':'public,max-age=31536000',
'Expires':new Date(Date.now()+31536000).toUTCString()
})
}
next()
})
app.use(ecstatic({root:path.resolve(__dirname,'../dist')}))
http.createServer(app).listen(8889,()=>{
console.log('服务启动')
})
3.10静态资源内联与压缩
3.10.1静态资源内联:图片、CSS、html
Webpack的内联功能允许您将静态资源(如图像,字体或CSS)内联到您的代码中,而无需将它们单独打包。这样做的好处是可以减少网络请求,提高应用程序的性能。减少网络请求次数;有利于缓存;防止资源加载失败。
3.10.2图片压缩
let loader=base.module.rules.find(
v=>v.test.toString()==="/\.(png|jpe?g|gif|webp)(\?.*)?$/"
)
Object.assign(loader,{
parser:{
dataUrlCondition:{
maxSize:20*1024
}
},
use:[
{
loader:'image-webpack-loader',
options:{
mozjpeg:{
progressive:true
},
optipng:{
enabled:false
},
pngquant:{
quanlity:[0.65,0.90],
speed:4
},
gifsicle:{
interlaced:false
},
webp:{
quanlity:75
}
}
}
]
})
}
3.11骨架屏
在页面数据加载完成前,先给用户展示出页面的大致结构(灰色占位图)使界面加载过程变得更加流畅;不会造成长时间白屏或者闪烁。
简单来说,骨架屏就是在页面内容未加载完成的时候,先使用一些图形进行占位,待内容加载完成之后再把它替换掉
3.11.1生成骨架屏方案
(1)手工编辑骨架屏
(2)利用puppeteer或者Chrome插件生成
(3)利用SSR服务器端渲染技术生成
(4)组件级骨架屏技术