Webpack优化项⽬的⼿段

news2024/10/23 16:03:22
webpack 做性能优化分为两个⽅⾯: 构建时间优化 、 构建体积优化

构建时间优化

缩⼩范围
我们在使⽤ loader 时,可以配置 include exclude 缩⼩ loader 对⽂件的搜索范围,以此来提
⾼构建速率。 像 /node_moudles ⽬录下的体积辣么⼤,⼜是第三⽅包的存储⽬录,直接 exclude 掉可以节 省⼀定的时间的。当然 exclude include 可以⼀起配置,⼤部分情况下都是只需要使⽤ loader 编译 src ⽬录下的代码
module.exports = {
  module: {
    rules: [
      {
        test: /\.(|ts|tsx|js|jsx)$/,// 只解析 src ⽂件夹下的 ts、tsx、js、 jsx ⽂件
        // include 可以是数组,表⽰多个⽂件夹下的模块都要解析
        include: path.resolve(__dirname, '../src'),
        use: ['thread-loader', 'babel-loader'],
        //当然也可以配置 exclude,表⽰ loader 解析时不会编译这部分⽂件
        //同样 exclude 也可以是数组
        exclude: /node_modules/,
      }
    ]
  }
}

export default App;
还需注意⼀个点就是要确保 loader 的 准确性 ,⽐如不要使⽤ less-loader 去解析 css ⽂件
⽂件后缀
resolve.extensions 是我们常⽤的⼀个配置,他可以在导⼊语句没有带⽂件后缀时,可以按照
配置的列表,⾃动补上后缀。我们应该根据我们项⽬中⽂件的实际使⽤情况设置后缀列表,将使⽤频 率⾼的放在前⾯、同时后缀列表也要尽可能的少,减少没有必要的匹配。同时,我们在源码中写导⼊语句的时候,尽量带上后缀,避免查找匹配浪费时间。
module.export = {
  resolve: {// 按照 tsx、ts、jsx、js 的顺序匹配,若没匹配到则报错
    extensions: ['.tsx', '.ts', '.jsx', '.js'],
  }
}
别名
通过配置 resolve.alias 别名的⽅式,减少引⽤⽂件的路径复杂度
module.exports = {
  resolve: {
    alias: {//把 src ⽂件夹别名为 @
        //引⼊ src 下的⽂件就可以 import xxx from
      '@/xxx''@': path.join(__dirname, '../src')
    }
  }
}
// 引⼊ src 下的某个模块时import XXX from '@/xxx/xxx.tsx'
缓存
在优化的⽅案中,缓存也是其中重要的⼀环。在构建过程中,开启缓存提升⼆次打包速度。
在项⽬中,js ⽂件是占⼤头的,当项⽬越来越⼤时,如果每次都需要去编译 JS 代码,那么构建的速度 肯定会很慢的,所以我们可以配置 babel-loader 的缓存配置项 cacheDirectory 来缓存没有
变过的 js 代码
module.exports = {
  module: {
    rules: [
      {
        test: /.jsx ? $ /,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
            },
          }
        ]}
    ]}
}
上⾯的缓存优化只是针对像 babel-loader 这样可以配置缓存的 loader,那没有缓存配置的
loader 该怎么使⽤缓存呢,此时需要 cache-loader
module.exports = {
  module: {
    rules: [
      {
        test: /.jsx ? $ /,
        use: ['cache-loader', "babel-loader"
        ],
      }
    ]
  }
}
编译后同样多⼀个 /node_modules/.cache/cache-loader 缓存⽬录 当然还有⼀种⽅式, webpack5 直接提供了 cache 配置项,开启后即可缓存
module.exports = {
  cache: {
    type: 'filesystem'

  }
}
编译后会多出 /node_modules/.cache/webpack 缓存⽬录
并⾏构建
⾸先,运⾏在 Node ⾥的 webpack 是单线程的,所以⼀次性只能⼲⼀件事,那如果利⽤电脑的多核 优势,也能提⾼构建速度 ? thread-loader 可以开启多进程打包
module.exports = {
  module: {
    rules: [
      {
        test: /.jsx ? $ /,
        use: [// 开启多进程打包。
          {
            loader: 'thread-loader',
            options: {
              workers: 3 // 开启 3个 进程
            }
          },
          {
            loader: 'babel-loader',
          }
        ]
      }
    ]
  }
}
放置在这个 thread-loader 之后的 loader 就会在⼀个单独的 worker 池(worker pool) 中运⾏。每个 worker 都是⼀个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。所以建议仅在耗时的 loader 上使⽤。若项⽬⽂件不算多就不要使⽤,毕竟开启多个线程也会存在性能开销。
定向查找第三⽅模块
resolve.modules 配置⽤于指定 webpack 去哪些⽬录下寻找第三⽅模块。默认值是 ['node_modules'] 。⽽在引⼊模块的时候,会以 node 核⼼模块 -----> node_modules
------> node 全局模块 的顺序查找模块。 我们通过配置 resolve.modules 指定 webpack 搜索第三⽅模块的范围,提⾼构建速率
module.export = {
  resolve: {
    modules: [path.resolve(__dirname, 'node_modules')]
  }
}

构建体积优化

压缩 js
webpack5的话通过 terser-webpack-plugin 来压缩 JS,但在配置了 mode: production时,会默认开启
const TerserPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {// 开启压缩
    minimize: true,// 压缩⼯具
    minimizer: [new TerserPlugin({}),
    ],
  },
}
需要注意⼀个地⽅:⽣产环境会默认配置 terser-webpack-plugin ,所以如果你还有其它压缩插
件使⽤的话需要将 TerserPlugin 显⽰配置或者使⽤ ... ,否则 terser-webpack-plugin 会被覆盖。
const TerserPlugin = require("terser-webpack-plugin");
optimization: {
  minimize: true,
    minimizer: [new TerserPlugin({}), // 显⽰配置// "...", // 或者使⽤展开符,启⽤默
      认插件// 其它压缩插件new CssMinimizerPlugin(),
    ],
},
压缩 css
压缩 css 我们使⽤ css-minimizer-webpack-plugin 同时,应该把 css 提取成单独的⽂件,使⽤ mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$ /,
        use: [// 提取成单独的⽂件
          MiniCssExtractPlugin.loader, "css-loader"
        ],
        exclude: / node_modules /,
      },
    ]
  },
  plugins: [new MiniCssExtractPlugin({// 定义输出⽂件名和⽬录
    filename: "asset/css/main.css",
  })
  ],
  optimization: {
    minimize: true,
    minimizer: [// 压缩 cssnew CssMinimizerPlugin({}),
    ],
  },
}
压缩 html
压缩 html 使⽤的还是 html-webpack-plugin 插件。该插件⽀持配置⼀个 minify 对象,⽤来
配置压缩 html
module.export = {
  plugins: [new HtmlWebpackPlugin({// 动态⽣成 html ⽂件
    template: "./index.html",
    minify: {// 压缩HTML
      removeComments: true, // 移除HTML中的注释
      collapseWhitespace: true, // 删除空⽩符与换⾏符
      minifyCSS: true // 压缩内联css

    },
  })
  ]
}
压缩图⽚
可以通过 image-webpack-loader 来实现
// 导出一个对象,包含一个 module 属性,该属性包含一个 rules 属性,该属性是一个数组,数组中包含一个对象
module.exports = {
  module: {
    rules: [
      {
        // 使用正则表达式匹配文件类型
        test: /\.(png | jpg | gif | jpeg | webp | svg)$/,
        // 使用 file-loader 和 image-webpack-loader 两个加载器
        use: ["file-loader",
          {
            loader: "image-webpack-loader",
            options: {
              // 对 jpeg 文件进行优化
              mozjpeg: {
                progressive: true,
              },
              // 对 png 文件进行优化
              optipng: {
                enabled: false,
              },
              // 对 png 文件进行优化
              pngquant: {
                quality: [0.65, 0.9],
                speed: 4,
              },
              // 对 gif 文件进行优化
              gifsicle: {
                interlaced: false,
              },
            },
          },
        ],
        // 排除 node_modules 目录
        exclude: /node_modules/,  
      },
    ]
  },
}
按需加载
很多时候我们不需要⼀次性加载所有的 JS ⽂件,⽽应该在不同阶段去加载所需要的代码。将路由⻚⾯/触发性功能单独打包为⼀个⽂件,使⽤时才加载,好处是 减轻⾸屏渲染的负担 。因为项 ⽬功能越多其打包体积越⼤,导致⾸屏渲染速度越慢。 实际项⽬中⼤部分是对懒加载路由,⽽懒加载路由可以打包到⼀个 chunk ⾥⾯。⽐如某个列表⻚和编 辑⻚它们之间存在相互跳转,如果对它们拆分成两个 import() js 资源加载模块,在跳转过程中视 图会出现⽩屏切换过程。因为在跳转期间,浏览器会动态创建 script 标签来加载这个 chunk ⽂件,在这期间,⻚⾯是没有任何内容的。所以⼀般会把路由懒加载打包到⼀个 chunk ⾥⾯
const List = lazyComponent('list', () => import(/* webpackChunkName: "list" */
  '@/pages/list'));
const Edit = lazyComponent('edit', () => import(/* webpackChunkName: "list" */
  '@/pages/edit'));
但需要注意⼀点:动态导⼊ import() ⼀个模块,这个模块就不能再出现被其他模块使⽤ 同步
import ⽅式导⼊。⽐如⼀个路由模块在注册 <Route /> 时采⽤动态 import() 导⼊,但在这个模块对外暴露了⼀些 变量⽅法供其他⼦模块使⽤,在这些⼦模块中使⽤了同步 ESModule import ⽅式引⼊,这就造成了动态 import() 的失效。
prload、prefetch
对于某些较⼤的模块,如果点击时再加载,那可能响应的时间反⽽延⻓。我们可以使⽤
prefetch preload 去加载这些模块
prefetch :将来可能需要⼀些模块资源(⼀般是其他⻚⾯的代码),在核⼼代码加载完成之后 带
宽空闲 的时候再去加载需要⽤到的模块代码。 preload :当前核⼼代码加载期间可能需要模块资源(当前⻚⾯需要的但暂时还没使⽤到的),其 是和核⼼代码⽂件⼀起去加载的。只需要通过 魔法注释即可实现,以 prefetch 为例:
  document.getElementById('btn1').onclick = function () {
  import(
     /* webpackChunkName: "btnChunk"/
  * /* webpackPrefetch: true*/
    './module1.js'
 ).then(fn => fn.default());
 
}
这⾏代码表⽰在浏览器空闲时加载 module1.js 模块,并且单独拆⼀个 chunk,叫做 btnChunk 可以看到,在 head ⾥⾯,我们的懒加载模块被直接引⼊了,并且加上了 rel='prefetch' 这样,⻚⾯⾸次加载的时候,浏览器空闲的会后会提前加载 module1.js 。当我们点击按钮的时 候,会直接从缓存中读取该⽂件,因此速度⾮常快。
代码分割
在项⽬中,⼀般是使⽤同⼀套技术栈和公共资源。如果每个⻚⾯的代码中都有这些公开资源,就会导 致资源的浪费。在每⼀个⻚⾯下都会加载重复的公共资源,⼀是会浪费⽤⼾的流量,⼆是不利于项⽬ 的性能,造成⻚⾯加载缓慢,影响⽤⼾体验。 ⼀般是把不变的第三⽅库、⼀些公共模块(⽐如 util.js)这些单独拆成⼀个 chunk,在访问⻚⾯的时候,就可以⼀直使⽤浏览器缓存中的资源webpack ⾥⾯通过 splitChunks 来分割代码
module.exports = { 
  optimization: {
    splitChunks: {
      chunks: 'async', // 值有 all,async 和 initial
      minSize: 20000, // ⽣成 chunk 的最⼩体积(以 bytes 为单位)。
      minRemainingSize: 0,
      minChunks: 1, // 拆分前必须共享模块的最⼩ chunks 数。
      maxAsyncRequests: 30, // 按需加载时的最⼤并⾏请求数。
      maxInitialRequests: 30, // ⼊⼝点的最⼤并⾏请求数。
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/, //第三⽅模块拆出来
          priority: -10,
          reuseExistingChunk: true,
        },
        util.vendors: {
  test: /[\/]utils[\/]/, //公共模块拆出来
    minChunks: 2,
      priority: -20,
        reuseExistingChunk: true,              
                    },  
                  },
  },
},
 }
tree shaking  
tree shaking 在⽣产模式下已经默认开启了
只是需要注意下⾯⼏点:
1. 只对 ESM ⽣效
2. 只能是静态声明和引⽤的 ES6 模块,不能是动态引⼊和声明的。
3. 只能处理模块级别,不能处理函数级别的冗余。
4. 只能处理 JS 相关冗余代码,不能处理 CSS 冗余代码。
⽽可能样式⽂件⾥⾯有些代码我们也没有使⽤,我们可以通过 purgecss-webpack-plugin 插件
来对 css 进⾏ tree shaking
const path = require("path");
const PurgecssPlugin = require("purgecss-webpack-plugin");
const glob = require("glob"); // ⽂件匹配模式
module.exports = {//...
  plugins: [
    ...new PurgeCSSPlugin({
      paths: glob.sync(`${PATH.src}/**/*`, { nodir: true }),
    })
  ],
};
gzip
前端除了在打包的时候将⽆⽤的代码或者 console 、注释剔除之外。我们还可以使⽤ Gzip 对资
源进⾏进⼀步压缩。那么浏览器和服务端是如何通信来⽀持 Gzip 呢?
1. 当⽤⼾访问 web 站点的时候,会在 request header 中设置 accept-encoding:gzip ,表明浏览器是否⽀持 Gzip 。
2. 服务器在收到请求后,判断如果需要返回 Gzip 压缩后的⽂件那么服务器就会先将我们的
JS\CSS 等其他资源⽂件进⾏ Gzip 压缩后再传输到客⼾端,同时将 response headers设置 content-encoding:gzip 。反之,则返回源⽂件。
3. 浏览器在接收到服务器返回的⽂件后,判断服务端返回的内容是否为压缩过的内容,是的话则进⾏解压操作。⼀般情况下我们并不会让服务器实时 Gzip 压缩,⽽是利⽤ webpack 提前将静态资源进⾏ Gzip 压缩,然后将 Gzip 资源放到服务器,当请求需要的时候直接将 Gzip 资源发送给客⼾端。 我们只需要安装 compression-webpack-plugin 并在 plugins 配置就可以了
  const CompressionWebpackPlugin = require("compression-webpack-plugin"); 
// 需要安装
    module.exports = {
      plugins: [new CompressionWebpackPlugin()]
  }
作⽤域提升
Scope Hoisting 可以让 webpack 打包出来的代码⽂件体积更⼩,运⾏更快。在开启 Scope Hoisting 后,构建后的代码会按照引⼊顺序放到⼀个函数作⽤域⾥,通过适当重命名某些变量以防⽌变量名冲突,从⽽减少函数声明和内存花销。需要注意: Scope Hoisting 需要分析模块之间的依赖关系,所以源码必须采⽤ ES6 模块化语法Scope Hoisting 是 webpack 内置功能,只需要在 plugins ⾥⾯使⽤即可,或者直接开启⽣产环境也可以让作⽤域提升⽣效。
module.exports = {
  //⽅式1
  mode: 'production',
  //⽅式2
  plugins: [// 开启 Scope Hoisting 功能new
    webpack.optimize.ModuleConcatenationPlugin()
  ]
}

构建体积优化

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

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

相关文章

【Golang】Gin框架中如何定义路由

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

计算机网络:数据链路层 —— 无线局域网 WLAN

文章目录 局域网无线局域网 WLAN802.11 无线局域网802.11无线局域网的组成WLAN 的组成有固定基础设施的802.11无线局域网漫游服务 无固定基础设施的802.11无线局域网 802.11无线局域网的物理层802.11无线局域网的数据链路层不使用碰撞检测 CD 的原因CSMA/CA 协议CSMA/CA 协议的…

新探索研究生英语读写教程pdf答案(基础级)

《新探索研究生英语读写教程》的设计和编写充分考虑国内研究生人才培养目标和研究生公共英语的教学需求&#xff0c; 教学内容符合研究生认知水平&#xff0c; 学术特征突出&#xff1b;教学设计紧密围绕学术阅读、学术写作和学术研究能力培养&#xff1b;教学资源立体多元&…

阀井燃气监控仪-燃气阀门井数据远程监测设备-旭华智能

在城市的地下&#xff0c;有无数条看不见的生命线——那是为千家万户输送温暖与光明的燃气管线。然而&#xff0c;在这复杂的网络之下&#xff0c;隐藏着不可预知的风险。为了保障每一位市民的安全&#xff0c;我们推出了一款革命性的产品——“智安卫士”可燃气体监测终端。 随…

Python字符串处理深度解析:高级操作技巧、性能优化与实用案例全解

文章目录 前言&#x1f497;一、字符串的定义与特点&#x1f498;1.1 字符串的定义1.1.1 单引号和双引号的字符串定义&#xff1a;1.1.2 三引号定义多行字符串&#xff1a; &#x1f498;1.2 特点&#xff1a;&#x1f498;1.3 字符串是序列小结&#xff1a; &#x1f497;二、…

软件设计模式------抽象工厂模式

抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff0c;又称Kit模式&#xff0c;属于对象创建型模式。 一&#xff1a;先理解两个概念&#xff1a; &#xff08;1&#xff09;产品等级结构&#xff1a; 即产品的继承结构。 通俗来讲&#xff0c;就是不同品…

【计算机网络 - 基础问题】每日 3 题(四十九)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

如何通过智能T0算法增加持仓收益?

第一&#xff1a;什么是智能T0算法&#xff1f;什么是智能T0算法&#xff1f;简单来说&#xff0c;就是基于用户原有的股票持仓&#xff0c;针对同一标的&#xff0c;配合智能T0算法&#xff0c;每天全自动操作&#xff0c;高抛低吸&#xff0c;抓取行情波动价差。操作后每日持…

MySQL的安装(windows,Centos,ubuntu)

目录 在Windows下安装MySQL数据库 在Centos下安装MySQL数据库 在ubuntu下安装MySQL数据库 在Windows下安装MySQL数据库 安装程序的下载地址: https://dev.mysql.com/downloads/ 点击之后就会出现下面的页面 接下来根据安装提示进行操作即可 在Centos下安装MySQL数据库 1.确认…

VMware中Ubuntu安装

VMware官网&#xff1a;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion 先在官网下载VMware&#xff0c;一直根据默认点下一步就好了&#xff0c;记得更改安装地址哦&#xff0c;否则默认下在C盘里。 先下载好Ubuntu映像文件&#xff1a;https://…

No.18 笔记 | XXE(XML 外部实体注入)漏洞原理、分类、利用及防御整理

一、XXE 漏洞概述 &#xff08;一&#xff09;定义 XXE&#xff08;XML 外部实体注入&#xff09;漏洞源于 XML 解析器对外部实体的不当处理&#xff0c;攻击者借此注入恶意 XML 实体&#xff0c;可实现敏感文件读取、远程命令执行和内网渗透等危险操作。 &#xff08;二&am…

[含文档+PPT+源码等]精品基于Nodejs实现的水果批发市场管理系统的设计与实现

基于Node.js实现的水果批发市场管理系统的设计与实现背景&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、行业背景与市场需求 水果批发市场的重要性&#xff1a; 水果批发市场作为农产品流通的重要环节&#xff0c;承载着从生产者到消费者之间的桥梁作用。它的运营效…

传统园区与智慧园区:现代化发展的差异和优势

传统园区和智慧园区代表着城市发展不同阶段的产物&#xff0c;两者在功能、管理、环境等多个方面存在显著差异。通过对传统园区和智慧园区进行对比&#xff0c;可以清晰地看到智慧园区的诸多优势所在。 1. 功能对比&#xff1a; 传统园区通常以简单的生产、办公和商业为主要功…

1.深入理解MySQL索引底层数据结构与算法

文章目录 索引的概念数据结构二叉树红黑树B-B两者的区别 Hash 引擎数据所在位置对应关系MyISAMInnoDB 索引主键聚集索引非聚集索引联合索引 如有写的不对的请指正。 索引的概念 索引是帮助MySQL高效获取数据的排好序的数据结构 数据结构 网址&#xff1a; https://www.cs.us…

Kafka-设计思想-2

一、消息传递语义 现在我们对生产者和消费者的工作方式有了一些了解&#xff0c;让我们讨论一下Kafka在生产者和消费者之间提供的语义保证。 1、最多发送一次&#xff1a;会造成数据丢失 2、至少发送一次&#xff1a;会造成数据重复消费 3、只发送一次&#xff1a;我们想要的效…

MDB收款适配器MDBPOS

LETPOS精简版MDBPOS&#xff08;直接连接MDB协议的刷卡器&#xff0c;按照设定价格收款&#xff0c;输出脉冲&#xff09; 通过串口设定价格&#xff0c;脉冲宽度。 有人刷卡&#xff0c;扣款成功&#xff0c;输出脉冲&#xff0c;使用简单 适合把MDB协议的刷卡器连接到脉冲投…

【算法】归并排序概念及例题运用

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

小程序视频SDK解决方案,提供个性化开发和特效定制设计

美摄科技作为视频处理技术的领航者&#xff0c;深知在这一变革中&#xff0c;每一个细微的创新都能激发无限可能。因此&#xff0c;我们精心打造了一套小程序视频SDK解决方案&#xff0c;旨在满足不同行业、不同规模客户的多元化需求&#xff0c;携手共创视频内容的璀璨未来。 …

这几次比赛题解

因为考虑到再看&#xff0c;所以将所有题目都做成了pdf格式 梦熊十三连测 T1 这道题其实什么也不用想&#xff0c;就按照题目给的意思来打代码就行&#xff0c;这就有40分可以拿。懒人做法 #include<bits/stdc.h> using namespace std; typedef long long ll; ll read…

中航资本:股票显示缺口什么意思啊?股票有缺口一定会补吗?

股票显现缺口什么意思啊&#xff1f; 股票显现缺口是指股票在运行进程中&#xff0c;忽然上涨或许下跌使股价远离上一个交易日收盘价的状况&#xff0c;也便是股票当天的开盘价格和股票前一个交易日的收盘价格违背崎岖很大。在K线图中&#xff0c;缺口表现为股价在持续动摇中有…