首屏性能优化
如何定位到首屏性能问题?有哪些量化指标?
如何定位:
webpack-bundle-analyzer插件:生成可视化依赖图谱,用来分析依赖关系和包大小;- Performance面板:Chrome调试工具,分析性能必备,需要掌握性能录制和分析“火焰图”;
- Network面板:Chrome调试工具,用来查看和调试网络请求;
- 埋点监控工具:一般是借助Sentry或者第三方监控工具,可以采集数据和监控线上问题。
量化指标:
- FCP,首次内容绘制时间,之用户首次“看到东西”的时间,一般要求小于1.8s;
- LCP,最大内容绘制时间,如主图、主标题、用户感知主体页面已加载,一般要求2.5s;
- TTI,页面首次可交互的时间(按钮、输入等响应),一般要求小于5s;
有哪些首屏优化手段?以及优化效果如何?
- JS分包:包括路由懒加载和组件按需加载,只需在路由配置时,改为动态import,以及将组件库改为按需加载;
- 静态资源走CDN:购买CDN服务,将静态资源托管到CDN,加快访问速度;
- 提取通用库:配置
externals,将项目中体积较大的三方库改用CDN引入,减少打包体积; - 开启Gzip:在Nginx服务器上开启Gzip压缩,降低网络传输体积;
- 体验优化:比如骨架屏和Loading,可以降低用户等待焦虑;
- 图片加载优化:图片懒加载、预加载,图片压缩以及使用现代格式的图片;
- SSR服务端渲染:服务端渲染在一定程度上也能加快首屏访问速度,但是需要考虑开发和运维成本,一般只有在SEO要求比较高的场景才考虑使用。
效果:
- 分包能直接减轻首屏资源压力,能减少大约80%包体积;
- 图片优化和体验优化能直接提升用户交互体验,感知最明显;
- Gzip/CDN解决了传输慢、资源加载慢的问题,效果也比较显著;
一般这3点组合起来,能让首屏打开速度提升2-5倍。
Gzip和CDN一般是服务器上配置,为什么前端来做?
Gzip和CDN虽然在服务器配置,但前端也需要做一些配合~
Gzip
- 原理:将HTML、JS、CSS等文本资源在服务端压缩后传输,降低首屏资源体积,减少网络传输耗时,加快首屏渲染;
- 后端工作:修改Nginx配置(gzip_static设置为on)。建议前端学一下Nginx的常用配置:CORS跨域、代理跨域、HTTPS、缓存等;
- 前端配合:使用
compression-webpack-plugin在构建时预生成.gz压缩文件,减少服务器实时压缩的开销; - 进阶场景:对于需要极致优化的场景,可以选择Brotli来替代Gzip,Brotli可以压缩的更小,但是浏览器兼容性稍差。
开发环境优化思路有哪些,怎么定位到构建过程中耗时的任务?
升级到webpack5或者迁移到vite,但是需要考虑到升级难度和时间成本;
配置webpack缓存:缓存不变的文件,提高二次构建速度。
启用 Webpack 持久化缓存(内置支持)
从 Webpack 5 开始,推荐使用内置的文件缓存(
cache: 'filesystem')。jsx// webpack.config.js module.exports = { // ... cache: { type: 'filesystem', // 启用文件缓存 buildDependencies: { config: [__filename], // 如果配置文件变了,重新缓存 }, }, };Webpack 会在
node_modules/.cache/webpack/中自动生成缓存内容。启用 loader 缓存(如 babel-loader)
jsx{ test: /\.js$/, use: { loader: 'babel-loader', options: { cacheDirectory: true, // 启用 babel 缓存 }, }, }这会把缓存存在
node_modules/.cache/babel-loader/目录下,加速二次构建。使用
cache-loader(Webpack 4 时代用法,Webpack 5 不再推荐)bashnpm install cache-loader --save-devjsx{ test: /\.js$/, use: [ 'cache-loader', 'babel-loader', ], include: path.resolve('src'), }Webpack 5 已不推荐使用
cache-loader,建议直接使用cache: { type: 'filesystem' }。使用
hard-source-webpack-plugin(已废弃)
多线程并行打包:使用
thread-loaderbashnpm install --save-dev thread-loaderjsx// webpack.config.js module.exports = { module: { rules: [ { test: /\.js$/, include: path.resolve('src'), use: [ { loader: 'thread-loader', options: { workers: 2, // 启动两个 worker(默认是 CPU 核数 - 1) }, }, { loader: 'babel-loader', options: { cacheDirectory: true, }, }, ], }, ], }, };thread-loader要放在 耗时 loader 的前面,比如babel-loader、ts-loader、vue-loader。不要给style-loader、css-loader等轻量 loader 加线程,反而变慢。预编译第三方库:对于稳定第三方库进行预编译,减少每次构建的处理时间,可以使用DllPlugin或者vue-cli项目配置transpileDependencies。
怎么定位问题?
- 使用
speed-measure-webpack-plugin插件来分析loader/plugin花费的时间; - 控制变量:隔离特定功能模块,观察构建速度变化;
- 打包时使
--profile —-json生成status.json分析文件,包含详细的构建性能分析数据。