关于vue.js:webpack-性能调优报告

48次阅读

共计 4429 个字符,预计需要花费 12 分钟才能阅读完成。

调优成绩

优化前 优化后 优化比例
打包体积 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 生成的构建统计报告,它会帮忙剖析包中蕴含的模块们的大小,简略列一下报告信息如下:

  1. 整体打包体积 32.01 MB
  2. ts.worker.js 是 monaco 编辑器的语言反对文件,次要提供 typescript 语法反对,体积 10.92 MB
  3. my-details.js 是播放页文件,网站外围资源文件,体积 6.81 MB
  4. chunk-vendors.js 第三方模块捆绑包,体积 4.14 MB
  5. html.workar.js 是 monaco 编辑器的 html 语法反对文件
  6. css.workar.js 是 monaco 编辑器的 css 语法反对文件
  7. json.worker.js 是 monaco 编辑器的 json 语法反对文件
  8. app.js 我的项目入口文件, 体积 1.02 MB
  9. 小文件文件数量太多,加起来靠近百个, 导致 http 申请过多

通过剖析总结,定位问题如下:

  1. monaco-editor 是最大的问题,体积占据半壁江山,重大影响加载速度,须要优化
  2. chunk-vendors.js 作为公共模块,形成我的项目必不可少的一些根底类库,降级频率都不高,但每个页面都须要它们,当初它体积过大,应该在正当范畴内拆分成更小一些的 js,以利用浏览器的并发申请,优化首页加载体验。其中蕴含了三个大家伙:elementUI、moment 和 lodash,更是须要独自做优化
  3. my-details.js 和 app.js 作为我的项目次要的资源文件,体积过大,须要优化
  4. 小文件数量太多,须要合并

解决思路

查看下有没有哪些产出是不必要的,在无限的工夫空间和算力下,去除低效的反复(提出公共大模块),进行正当的冗余(小文件容许反复),达到工夫和空间综合考量上的最优。
上面分步骤实现每一个优化项。

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

最终报告

报告图:

正文完
 0