调优成绩
优化前 | 优化后 | 优化比例 | |
---|---|---|---|
打包体积 | 32.01 MB | 16.56 MB | 48.27% |
Gzip 体积 | 3.37 MB | 1.82 MB | 45.99% |
文件数量 | 82 | 19 | 76.83% |
资源压缩 | 服务器 br 压缩 | 客户端 br 压缩 | 1 |
压缩级别 | 6 | 11(最高) | 1 |
构建速度 | 60s + | 41.1s + | 31.67% |
播放页 FP 耗时 | 显著感知 | 无感知 | 1 |
(以上数据起源为本地测试,仅供参考)
优化指标
- 升高播放页 FP 耗时
- 缩小动态资源申请数量
- 晋升开发体验
-
晋升构建产物品质
(文章基于 webpack@4.46.0)问题剖析
先看我的项目以后的打包剖析后果
以上是用 vue-cli 生成的构建统计报告,它会帮忙剖析包中蕴含的模块们的大小,简略列一下报告信息如下:
- 整体打包体积 32.01 MB
- ts.worker.js 是 monaco 编辑器的语言反对文件,次要提供 typescript 语法反对,体积 10.92 MB
- my-details.js 是播放页文件,网站外围资源文件,体积 6.81 MB
- chunk-vendors.js 第三方模块捆绑包,体积 4.14 MB
- html.workar.js 是 monaco 编辑器的 html 语法反对文件
- css.workar.js 是 monaco 编辑器的 css 语法反对文件
- json.worker.js 是 monaco 编辑器的 json 语法反对文件
- app.js 我的项目入口文件, 体积 1.02 MB
- 小文件文件数量太多,加起来靠近百个, 导致 http 申请过多
通过剖析总结,定位问题如下:
- monaco-editor 是最大的问题,体积占据半壁江山,重大影响加载速度,须要优化
- chunk-vendors.js 作为公共模块,形成我的项目必不可少的一些根底类库,降级频率都不高,但每个页面都须要它们,当初它体积过大,应该在正当范畴内拆分成更小一些的 js,以利用浏览器的并发申请,优化首页加载体验。其中蕴含了三个大家伙:elementUI、moment 和 lodash,更是须要独自做优化
- my-details.js 和 app.js 作为我的项目次要的资源文件,体积过大,须要优化
- 小文件数量太多,须要合并
解决思路
查看下有没有哪些产出是不必要的,在无限的工夫空间和算力下,去除低效的反复(提出公共大模块),进行正当的冗余(小文件容许反复),达到工夫和空间综合考量上的最优。
上面分步骤实现每一个优化项。
monaco-editor 优化
放大体积
咱们业务层面,只须要用到展现性能,其语言编辑性能齐全用不到,因而能够把语言包全副过滤掉,这里须要用到 monaco-editor-webpack-plugin 插件,配置增加插件选项 languages 为反对的语言数组(具体语言查看官网)默认是反对所有语言的,配置此项应该只是去除一些语言的高级个性反对。
new MonacoWebpackPlugin({languages: [],
}),
再次打包后,体积放大至 9.26 MB。
独自打包
monaco-editor 作为一个重量级组件,会扩散很多小文件到各个中央,从而减少文件数量和体积,进而造成流量损失,通过 webpack 的 splitChunks 性能拆分 monaco-editor 为独自独立文件,充分利用浏览器缓存,缩小屡次援用时的耗费。
splitChunks: {
chunks: 'all',
minSize: 20000,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
maxSize: 0,
cacheGroups: {
monacoEditor: {
chunks: 'async',
name: 'chunk-monaco-editor',
priority: 22,
test: /[\/]node_modules[\/]monaco-editor[\/]/,
enforce: true,
reuseExistingChunk: true,
},
}
按需加载
通过按需加载,缩小核心内容渲染前的阻塞,转到须要的时候加载。
const monaco = await import('monaco-editor');
开启 prefetch
按需加载后,因为 monaco-editor 自身体量很大,因而在加载编辑器时会呈现长时间无响应景象,采纳 prefetch 预加载计划,在浏览器闲暇时事后下载资源,到用的时候间接取,无效防止无响应状况。
const monaco = await import(/* webpackPrefetch: true;"*/'monaco-editor');
moment.js 优化
尝试删除 moment.js 语言包后体积仍然很大,最初采纳和 moment.js api 齐全兼容的 dayjs 替换,gzip 压缩后仅仅 2kb
(因替换工作为全局,可能会呈现和 moment.js 相干性能的 bug)
element-ui 优化
独自打包
实践上 UI 组件库也能够放入 chunk-vendors.js 中,但它切实是过大,可能比 libs 里所有的包加起来还要大不少,而且 UI 组件库的更新频率也绝对比 chunk-vendors.js 要更高一点。Element-UI 组件库作为 UI 组件,应从 chunk-vendors.js 中分离出来,独自打包为 chunk-elementUI.js,如图所示打包后体积为 1.67 MB
按需引入
依照官网按需引入形式,只引入应用的组件,缩小体积。
lodash.js 优化
按需引入
应用 webpack 插件 lodash-webpack-plugin 和 babel 插件实现按需打包 lodash
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
config.plugin('loadshReplace').use(new LodashModuleReplacementPlugin());
module.exports = {presets: ['@vue/cli-plugin-babel/preset'],
plugins: ['lodash',],
};
优化后,lodash 基本上做到无感知存在
svgIcon 优化
独自打包
svgIcon 组件库作为高频更新且援用超多的库,应独自分出为 chunk-svgIcon.js,如图所示打包后体积为 561 kb
删除 use-zh.svg
通过代码审查发现体积最大的 use-zh.svg 在我的项目中当初并未应用,所以删除
雪碧图
将所有 svg 合成雪碧图,缩小申请次数,应用 svg-sprite-loader 实现
const svgRule = config.module.rule('svg');
// 革除已有的所有 loader, 如果你不这样做,接下来的 loader 会附加在该规定现有的 loader 之后。svgRule.uses.clear();
// 增加要替换的 loader
svgRule
.test(/.svg$/)
.include.add(path.resolve(__dirname, 'src/components/svgIcon/svg'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({symbolId: 'icon-[name]',
})
.end();
压缩 svg(未执行)
因为压缩过后的 svg 图会存在去掉 fill 的状况,因而这一步骤并未执行
代码压缩
采纳 terser 插件(webpack4 官网举荐)进行 js 和 css 代码压缩,同时去掉生产环境的正文和 console 信息
config.optimization.minimizer('terser').tap(options => {
const compress = {
warnings: false,
drop_console: true,
drop_debugger: true,
pure_funcs: ['console.log'],
};
const initCompress = options[0].terserOptions.compress;
options[0].terserOptions.compress = {...initCompress, ...compress};
return options;
});
图片压缩(未执行)
应用 webpack 插件 image-webpack-loader 对所有图片进行压缩,然而该插件依赖于零碎环境,在不同环境下可能呈现装置失败,编译失败等状况,咱们我的项目目前图片资源较少,所以临时不必。
开启 br 压缩
以后 br 压缩是在 nginx 服务器进行且并未缓存资源,因而每次申请都须要对资源进行压缩之后收回,思考服务器性能,压缩级别设置为 6。
当初改为客户端压缩,服务器在接管申请时间接把压缩文件收回,缩小服务器压力。同时客户端压缩能够把压缩级别调整至最高的 11,整体资源大小会再次降落,应用 compression-webpack-plugin 实现。
const CompressionWebpackPlugin = require('compression-webpack-plugin');
if (!isDev) {
plugins.push(
new CompressionWebpackPlugin({filename: '[path].br[query]',
algorithm: 'brotliCompress',
test: /.(js|css|json|txt|html|ico|svg)(?.*)?$/i,
compressionOptions: {
params: {[zlib.constants.BROTLI_PARAM_QUALITY]: 11,
},
},
threshold: 1024,
minRatio: 0.99,
// 删除原始文件只保留压缩后的文件
deleteOriginalAssets: false,
}),
);
}
多线程执行 loader
开启 parallel 为 Babel 或 TypeScript 应用 thread-loader
parallel: require('os').cpus().length > 1
打包缓存
采纳 HardSourceWebpackPlugin 插件为模块提供两头缓存,缓存默认的寄存门路是: node_modules/.cache/hard-source。配置 hard-source-webpack-plugin,首次构建工夫没有太大变动,然而第二次开始,构建工夫大概能够节约 80%。
可能带来的问题,修复方法在这 hard-source-webpack-plugin
上面链接用于解决 hash 失落问题
https://github.com/mzgoddard/…
其余批改项
- 提取环境变量
const
` isDev = process.env.NODE_ENV === ‘development’; ` - 减少打包速度检测插件 SpeedMeasurePlugin
最终报告
报告图: