webpack实际实践优化项目

news2024/11/27 11:35:04

参考:
如何通过性能优化,将包的体积压缩了62.7%
雅虎35条
20210526-webpack深入学习,搭建和优化react项目

本文只专注于性能优化的这个部分。

总体来说分为两个方面:第一是开发环境中主要优化打包速度,第二是线上环境中主要优化分包大小。

打包阶段

使用speed-measure-webpack-plugin插件,显示打包过程中的每个步骤耗时大小。然后根据耗费的时长去优化。
比如下图:

安装cache-loader打包缓存
  {
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    use: [
      cacheLoader,
      {
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      }
    ]
  }
happypack .在打包的时候开启多线程打包
UglifyJsPlugin开启多线程优化时间,有两个方式,可以都试一下看看哪个效果好一点。
  1. 开启多线程
  // 在minimizer属性内添加
  // 自定义js优化配置,将会覆盖默认配置
  new UglifyJsPlugin({
      parallel: true,  //使用多进程并行运行来提高构建速度
      sourceMap: false,
      uglifyOptions: {
          warnings: false,
          compress: {
              unused: true,
              drop_debugger: true,
              drop_console: true, 
          },
          output: {
              comments: false // 去掉注释
          }
      }
  })
  1. 使用:webpack-parallel-uglify-plugin
    上图可以看出UglifyJsPlugin这个包花费时间太长,可以使用相同效果的另一个包,开启多核同步压缩增加压缩的效率。
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
new ParallelUglifyPlugin({
    uglifyJS: {
      output: {
        beautify: false, // 是否保留空格和制表符,设置为不保留
        comments: false, // 是否保留代码中的注释,设置为不保留
      },
      compress: {
        drop_console: true, // 是否删除代码中的console语句,设置为删除
        collapse_vars: false, // 是否内嵌虽然已经定义了,但是只用到一次的变量,设置为不使用
        reduce_vars: false, // 是否提取出现了多次但是没有定义成变量去引用的静态值,设置为不转换
      },
      warnings: false // 是否在删除没有用到的代码时输出警告信息,设置为不警告
    },
  }),
线上优化阶段

这一部分主要在于分离包(组件懒加载、路径懒加载、按需引入)、合并包(optimization.splitChunks)、压缩包(NGINX: gzip)
具体可以看以前的文章20210526-webpack深入学习,搭建和优化react项目

使用webpack-bundle-analyzer插件,显示打包后的包大小、包组成,然后针对去处理。
将大包拆小:

异步引入,路由懒加载 分包 import('@/components/Index')
按需引入组件,看看是不是直接把一个依赖都引入进来了,比如lodash需要引入babel-plugin-lodash等。

优化代码和合并相同的包

看看analyzer显示的第三方包有没有重复引入、打包到不同包的情况,这样的话就比较浪费空间,最好将第三方包合并一下,这里就使用到 optimization.splitChunks

压缩代码、去除无用代码

引入Uglifyjs进行代码压缩(第一步时间优化已经做了) Uglifyjs还会进行Tree-shaking剔除无用代码。比如引入了第三方包却没有用上的情况也会删除。

在服务器上的优化
  1. 图片和其他文件进行无损压缩,并上传到cdn上。
    推荐网站:https://tinyjpg.com

  2. nginx配置开通gzip ,从线上拉取的代码能压缩2/3
    巨强。

Next项目的实际实践

一年半年前进行过一次next项目的webpack优化,那时候的优化方向主要是splitChunks分包的数据。
半年前的参考文章可看博客列表:结合Next项目实际认识webpack.splitChunks

Next版本:12.3.4(因为使用next-plugin-antd-less 只能支持到next12。。)
Node版本:16.20.2

推荐阅读:v12.3.X的Next文档

经过半年多的持续优化,在webpack这方面又有了新的优化目标:

  1. 发现treeShaking没有生效,引入但是没有使用的资源仍然打包进去了。
  2. console.log正式环境禁用。
  3. 同一个组件在不同的包里被反复打包,导致一个页面上被多次下载。
  4. 部署构建太慢,想要加快速度。

Treeshaking

结论:next使用terser-plugin做的压缩和摇树,本地构建不会开,但是在构建环境会使用,因此确实会把没有引用的组件shake出去,不会影响使用。

调研过程:

  1. 一开始从本地上看以为失效了,查看了很多terser有关的问题,列在如下:
    • https://github.com/vercel/next.js/issues/20804
    • https://github.com/vercel/next.js/issues/49742
  2. 推荐使用next13+可以解决这个问题,于是重新实验,但是本地情况下仍然没有shake出去。
  3. nvm安装(next13+必须要node18以上)教程:
    • https://blog.csdn.net/Cavin80/article/details/132831839
    • https://juejin.cn/post/7083026831263137800
  4. 按照方案二,增加terser的参数passes:2可以解决,但是next并没有开放terserOptions给我们,因此只能另辟蹊径,找了半天源码,找到了一个v12版本可行的options插入方法。注意这个为后续的drop_console方案提供了思路。(不过事实证明passes也没什么变化)
  // next v12版本的实验特性,用于配置swc压缩属性
  experimental: { swcMinifyDebugOptions: { compress: { passes: 2 } } },
  1. modularizeImports。经过不懈寻找,找到了这么一个属性,可以用于内部组件的按需引入。

    官方推荐按需引入来达到treeShaking效果:https://github.com/vercel/next.js/issues/45687

    https://vercel.com/blog/how-we-optimized-package-imports-in-next-js

  2. 最后发现:原来是没有部署到线上,正式构建环境是可以treeshaking成功的。


drop console

线上环境我们并不想显示意外的console,因此删除console也是一个需求。

next提供的没有起作用。

  compiler: {
    removeConsole: {
      exclude: ['error'],
    },
  },

根据上面对源码的研究,找到了插入terserOptions的方式,增加了如下代码,push到构建环境后就能正常生效了。

  experimental: {
    swcMinifyDebugOptions: { compress: { passes: 2, drop_console: true } },
  },

PS.中间有一段自行重新引入了terser-webpack-plugin没有成功。

        config.optimization.minimizer = [
          new TerserPlugin({
            parallel: true,
            sourceMap: true,
            terserOptions: {
              compress: { drop_console: isProduction },
            },
          }),
        ];

部署构建太慢,想要加快速度。

  1. 引入速度衡量依赖speed-measure-webpack-plugin

    使用参考:https://github.com/vercel/next.js/discussions/33678

    config.plugins.push(smp);
    
  2. 分析:注意vscode setting原本默认的展示日志行数太少,可以通过 “terminal.integrated.scrollback”:1000000配置。

经过测试速度插件,可以看出耗时较久的是next\ no-loaders\ less-loader,前两个应该是next内部自行实现的(很无奈),那我们只能从less-loader下手了。

接下来是省流版:本项目使用next-plugin-antd-less已经不再维护,并且不支持多线程处理,因此费劲了九牛二虎之力仍然没有效果。作为一次探究过程放在下面。

打印出next的loader配置,经过对next-plugin-antd-less源码的研究,实际上对于css的处理next都是放在oneOf中的,我们要处理也要优先处理oneOf中的loader。

我考虑的方案是:

  1. 采用thread-loader添加多线程处理。
  2. 或者采用happyPack添加多线程处理。

const withConsole = (config) => {
  // console.log('----resolveLoader----\n',config.resolveLoader)
  // console.log('----rules----\n',config.module.rules)
  // console.log('---oneOf----\n',console.log(config.module.rules.map((rule) => Array.isArray(rule.oneOf) && rule)))

  return {
    ...config,
    webpack(webpackConfig, nextConfig) {

      // const _oneOf = [];
      // webpackConfig.module.rules.forEach((rule) => {
      //   if (Array.isArray(rule)) {
      //     rule.forEach((loader) => {
      //       Array.isArray(loader.oneOf) && _oneOf.push(loader);
      //     });
      //   } else {
      //     Array.isArray(rule.oneOf) && _oneOf.push(rule);
      //   }
      // });
      // // console.log('---oneOf----\n');
      
      // _oneOf.forEach(rule=>{
      //   rule.oneOf.forEach(_d=>{

      //     if(_d.test?.toString() === /\.module\.(scss|sass)$/.toString()){
      //       console.log(
      //         '---sass----\n',
      //         '🌈',
      //         _d
      //       )
      //     }

      //     console.log(_d)
      //   })

      // })

      const config = nextConfig;
      console.log('---config----\n', config);
      return webpackConfig;
    },
  };
};
{
    test: /(antd\/.*?\/style|@ant-design).*(?<![.]js)$/,
    use: 'null-loader'
  },
  { issuerLayer: 'edge-asset', type: 'asset/source' },
  {
    dependency: 'url',
    loader: 'next-middleware-asset-loader',
    type: 'javascript/auto',
    layer: 'edge-asset'
  },
  {
    test: /\.wasm$/,
    loader: 'next-middleware-wasm-loader',
    type: 'javascript/auto',
    resourceQuery: /module/i
  },
  { test: /\.m?js/, resolve: { fullySpecified: false } },
  {
    test: /\.(js|cjs|mjs)$/,
    issuerLayer: 'api',
    parser: { url: true }
  },
  {
    oneOf: [
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object], [Object]
    ]
  },
  {
    test: /\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i,
    loader: 'next-image-loader',
    issuer: { not: /\.(css|scss|sass)$/ },
    dependency: { not: [Array] },
    options: { isServer: true, isDev: false, basePath: '', assetPrefix: '' }
  },
  { oneOf: [ [Object], [Object] ] },
  {
    test: /\.+(js|jsx|mjs|ts|tsx)$/,
    use: [ 'thread-loader', [Object] ],
    include: [Function (anonymous)],
    type: 'javascript/auto'
  },
  {
    test: /\.(jpg|jpeg|png|svg|gif|ico|webp|jp2|avif)$/,
    issuer: /\.\w+(?<!(s?c|sa)ss)$/i,
    exclude: undefined,
    use: [ [Object] ]
  }
]
但是问题点在于,我打印出了所有的loader配置以后发现 找不到less-loader。。

然后我没有办法,把next-plugin-antd-less源码的插件引入了项目测试一下效果,在手动引入的代码文件中增加了thread-loader.

报错:UnhandledPromiseRejectionWarning: TypeError: loaderContext.getLogger is not a function
查找了一下这个问题是因为less-loader的版本问题导致的,降低了一下less-loader的版本。。。
https://github.com/webpack-contrib/thread-loader/issues/135

最后效果看起来确实少了5-6秒,但是不太值得。最终放弃了这个方案,以及happyPack也是同样的原因,做不到再把plugin引进源码文件再处理一次。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1450866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VScode+PlatformIO 物联网Iot开发平台环境搭建

1.vscode &#xff08;1&#xff09;安装platformIO插件 &#xff08;2&#xff09;新建项目或导入已有的arduino项目 Name&#xff1a;需要填写你项目的名称&#xff1b; Board&#xff1a;点开是一个下拉框&#xff0c;但是可以输入你想要的开发板&#xff0c;这里选择&quo…

Spring Task定时任务

目录 1、介绍 2、cron表达式 2.1、在线生成器 2.2、通配符 3、代码示例 3.1、使用步骤 3.2、 代码开发 3.3、测试 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发…

【前端高频面试题--Vue组件通信篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;前端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac;前端高频面试题--Vue组件通信篇 往期精彩内容Vue与VueComponent的关系props / $emit父子组件传值父…

备战蓝桥杯---图论之最短路Bellman-Ford算法及优化

目录 上次我们讲到复杂度为&#xff08;nm)logm(m为边&#xff0c;n为点&#xff09;的迪杰斯特拉算法&#xff0c;其中有一个明显的不足就是它无法解决包含负权边的图。 于是我们引进Bellman-Ford算法。 核心&#xff1a;枚举所有的点&#xff0c;能松弛就松弛&#xff0c;直…

《剑指offer》

本专题是分享剑指offer的一些题目&#xff0c;开始刷题计划。 二维数组的中的查找【https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId13&tqId11154&ru/exam/oj】 描述 在一个二维数组array中&#xff08;每个一维数组的长度相同&#xff0…

[计算机提升] 备份系统:设置还原点

6.7 备份系统&#xff1a;设置还原点 在Windows系统中&#xff0c;系统还原点是指系统在特定时间存储的重要系统文件的备份。通过创建系统还原点&#xff0c;可以轻松地将系统恢复到之前创建还原点的状态。这有助于解决系统文件损坏或Windows操作系统出现问题的情况。 1、右键…

推荐在线图像处理程序源码

对于喜爱图像编辑的朋友们来说&#xff0c;Photoshop无疑是处理照片的利器。然而&#xff0c;传统的Photoshop软件不仅需要下载安装&#xff0c;还对电脑配置有一定的要求&#xff0c;这无疑增加了使用的门槛。 现在&#xff0c;我们为您带来一款革命性的在线PS修图工具——基…

Redis篇----第一篇

系列文章目录 文章目录 系列文章目录前言一、什么是 Redis?二、Redis 与其他 key-value 存储有什么不同?三、Redis 的数据类型?四、使用 Redis 有哪些好处?五、Redis 相比 Memcached 有哪些优势?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住…

GAN生成对抗性网络

一、GAN原理 出发点&#xff1a;机器学习中生成模型的问题 无监督学习是机器学习和未来人工智能的突破点&#xff0c;生成模型是无监督学习的关键部分 特点&#xff1a; 不需要MCMC或者变分贝叶斯等复杂的手段&#xff0c;只需要在G和D中对应的多层感知机中运行反向传播或者…

(2024,DiS,扩散,状态空间主干,Mamba)具有状态空间主干的可扩展扩散模型

Scalable Diffusion Models with State Space Backbone 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 方法 2.1 基础 2.2 模型结构设计 3. 实验 0. 摘要 这篇论文提出…

挑战杯 python区块链实现 - proof of work工作量证明共识算法

文章目录 0 前言1 区块链基础1.1 比特币内部结构1.2 实现的区块链数据结构1.3 注意点1.4 区块链的核心-工作量证明算法1.4.1 拜占庭将军问题1.4.2 解决办法1.4.3 代码实现 2 快速实现一个区块链2.1 什么是区块链2.2 一个完整的快包含什么2.3 什么是挖矿2.4 工作量证明算法&…

MySQL容器的数据挂载

挂载本地目录或文件 可以发现&#xff0c;数据卷的目录结构较深&#xff0c;如果我们去操作数据卷目录会不太方便。在很多情况下&#xff0c;我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似&#xff1a; # 挂载本地目录 -v 本地目录:容器内目录 # 挂载本地…

社区商铺开什么店最好?从商业计划书到实际运营

在社区商铺开店&#xff0c;选择适合的业态是成功的关键。作为一名开店 5 年的资深创业者&#xff0c;我想分享一些关于社区店的干货和见解。 这篇文章&#xff0c;我用我的项目给大家举例子&#xff01; 鲜奶吧作为一种新兴的业态&#xff0c;以提供新鲜、健康的乳制品为主&…

抽象的问题1

vue3&#xff0c;在使用v-mode绑定属性时&#xff0c;发生了奇怪的问题&#xff0c;渲染失败了 代码如下 <template><div><form><div>账号<input v-model"form_user_Data.username" type"text"></div><div>密…

百模大战怎么样了?

百度入场最早&#xff0c;paddlegan/paddlepaddle多年前就布局了中小模型&#xff0c;ERNIE1.0 大模型早在2019年就发布了&#xff0c;只不过效果差&#xff0c;成本高没弄起来。 后来借着chatgpt的东风&#xff0c;百度几乎国内第一时间发布了国产大模型文心一言&#xff0c;文…

寒假学习记录17:包管理器(包管理工具)

概念 包&#xff08;package&#xff09; 包含元数据的库&#xff0c;这些元数据包括&#xff1a;名称&#xff0c;描述&#xff0c;git主页&#xff0c;许可证协议&#xff0c;作者&#xff0c;依赖..... 库&#xff08;library&#xff0c;简称lib&#xff09; 以一个或多个模…

从数字孪生到智慧城市:科技引领下的城市未来展望

一、引言 随着科技的飞速发展&#xff0c;数字孪生和智慧城市已成为当今世界城市发展的重要趋势。数字孪生通过建立物理世界的数字模型&#xff0c;为城市管理和规划提供了前所未有的可能性&#xff1b;而智慧城市则借助先进的信息通信技术&#xff0c;使城市运行更加高效、便…

springboot194基于springboot的医药管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的医药管理系统 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考。 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **…

软件实例分享,药店进销存软件医药系统进销存教程

软件实例分享&#xff0c;药店进销存软件医药系统进销存教程 一、前言 以下软件程序教程以 佳易王药店进销存管理系统V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件可以对药品的有效期进行管理&#xff0c;可以查询还有多少天到期的…