【webpack4系列】webpack构建速度和体积优化策略(五)

news2024/9/22 5:28:11

文章目录

    • 速度分析:使用 speed-measure-webpack-plugin
    • 体积分析:使用webpack-bundle-analyzer
    • 使用高版本的 webpack 和 Node.js
    • 多进程/多实例构建
      • 资源并行解析可选方案
      • 使用 HappyPack 解析资源
      • 使用 thread-loader 解析资源
    • 多进程并行压缩代码
      • 方法一:使用 parallel-uglify-plugin 插件
      • 方法二:uglifyjs-webpack-plugin 开启 parallel 参数
      • 方法三:terser-webpack-plugin 开启 parallel 参数
    • 进一步分包:预编译资源模块
      • 分包:设置 Externals
      • 进一步分包:预编译资源模块
    • 充分利用缓存提升二次构建速度
    • 缩小构建目标与减少文件搜索范围
      • 缩小构建目标
      • 减少文件搜索范围
    • 使用Tree Shaking擦除无用的JavaScript和CSS
    • 使用webpack进行图片压缩(压缩有问题)
    • 构建体积优化:动态 Polyfill

速度分析:使用 speed-measure-webpack-plugin

使用speed-measure-webpack-plugin插件。

官网地址:https://github.com/stephencookdev/speed-measure-webpack-plugin#readme

示例效果:
在这里插入图片描述

安装:

npm i speed-measure-webpack-plugin -D

使用:

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();

module.exports = smp.wrap({
  // 其他省略
  plugins: [
    new MyPlugin(), new MyOtherPlugin()
  ]
});

速度分析插件作用:

  • 分析整个打包总耗时
  • 每个插件和loader的耗时情况

体积分析:使用webpack-bundle-analyzer

示例代码:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

安装:

npm i webpack-bundle-analyzer -D

可以分析哪些问题?

  • 依赖的第三方模块文件大小
  • 业务里面的组件代码大小

使用高版本的 webpack 和 Node.js

高版本的webpack和node.js降低了构建时间。

使用webpack4的优化原因:

  • V8 带来的优化(for of 替代 forEach、Map 和 Set 替代 Object、includes 替代 indexOf)
  • 默认使用更快的 md4 hash 算法
  • webpacks AST 可以直接从 loader 传递给 AST,减少解析时间
  • 使用字符串方法替代正则表达式

多进程/多实例构建

资源并行解析可选方案

  • parallel-webpack
  • HappyPack
  • thread-loader

使用 HappyPack 解析资源

原理:每次 webapck 解析一个模块,HappyPack 会将它及它的依赖分配给 worker 线程中。

安装:

npm i happypack -D

使用示例:

const HappyPack = require('happypack');
 
exports.module = {
  rules: [
    {
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: 'happypack/loader',
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    }
  ]
};
 
exports.plugins = [
  // 2) create the plugin:
  new HappyPack({
    // 3) re-add the loaders you replaced above in #1:
    loaders: [ 'babel-loader?presets[]=es2015' ]
  })
];

使用 thread-loader 解析资源

由于webpack4.x目前只能安装thread-loader@3.0.0版本,3.0.0以后的版本需要webpack5.x。

原理:每次 webpack 解析一个模块,thread-loader 会将它及它的依赖分配给 worker 线程中

npm i thread-loader@3.0.0 -D

配置:

module: {
    rules: [
      {
        test: /.js$/,
        use: [
          {
            loader: "thread-loader",
            options: {
              workers: 3
            }
          },
          "babel-loader"
        ]
      }
    ]
  }

多进程并行压缩代码

方法一:使用 parallel-uglify-plugin 插件

const ParalleUglifyPlugin = require("webpack-parallel-uglify-plugin");
module.exports = {
  plugins: [
    new ParalleluglifyPlugin({
      uglifyjs: {
        output: {
          beautify: false,
          comments: false
        },
        compress: {
          warnings: false,
          drop_console: true,
          collapse_vars: true,
          reduce_vars: true
        }
      }
    })
  ]
};

方法二:uglifyjs-webpack-plugin 开启 parallel 参数

建议webpack3.x使用该插件。

const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
module.exports = {
  plugins: [
    new UglifyJsPlugin({
      uglifyoptions: {
        warnings: false,
        parse: {},
        compress: {},
        mangle: true,
        output: null,
        toplevel: false,
        nameCache: null,
        ie8: false,
        keep_fnames: false
      },
      parallel: true
    })
  ]
};

方法三:terser-webpack-plugin 开启 parallel 参数

webpack4.x及以上建议使用terser-webpack-plugin插件

注:Using Webpack v4, you have to install terser-webpack-plugin v4.

安装:

npm i terser-webpack-plugin@4 -D

配置:

const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true
      })
    ]
  }
};

进一步分包:预编译资源模块

分包:设置 Externals

思路:将 vue、react、react-dom 等基础包通过cdn 引入,不打入 bundle 中。

方法:使用html-webpack-externals-plugin

安装:

npm i html-webpack-externals-plugin -D

配置:

const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackExternalsPlugin({
      externals: [
        {
          module: "react",
          entry: "https://unpkg.com/react@18.2.0/umd/react.production.min.js",
          global: "React"
        },
        {
          module: "react-dom",
          entry: "https://unpkg.com/react-dom@18/umd/react-dom.production.min.js",
          global: "ReactDOM"
        }
      ]
    })
  ]
};

进一步分包:预编译资源模块

思路:将react、react-dom基础包和业务基础包打包成一个文件

方法:使用DLLPlugin进行分包,DllReferencePluginmanifest.json 引用

  • DllPlugin:负责抽离第三方库,形成第三方动态库dll。
  • DllReferencePlugin:负责引用第三方库。

使用 DLLPlugin 进行分包

新建一个webpack.dll.js:

const path = require("path");
const webpack = require("webpack");

module.exports = {
  entry: {
    library: ["react", "react-dom"]
  },
  output: {
    filename: "[name].dll.js",
    path: path.join(__dirname, "build/library"),
    library: "[name]_[hash:8]" // 保持与webpack.DllPlugin中name一致
  },
  plugins: [
    new webpack.DllPlugin({
      name: "[name]_[hash:8]", // 保持与output.library中名称一致
      path: path.join(__dirname, "build/library/[name].json")
    })
  ]
};

在package.json中添加命令:

"scripts": {
    "dll": "webpack --config webpack.dll.js"
}

最后执行npm run dll,结果在工程根目录下有如下文件:

  • build
    • library.dll.js
    • library.json

使用 DllReferencePlugin 引用 manifest.json

在webpack.prod.js中插件中配置如下:

plugins: [
    new webpack.DllReferencePlugin({
      manifest: require("./build/library/library.json")
    })
]

当执行npm run build 后其实index.html页面中没有引入library.dll.js文件,我们可以通过安装add-asset-html-webpack-plugin插件,webpack4.x版本使用add-asset-html-webpack-plugin@3

npm i add-asset-html-webpack-plugin@3 -D

在webpack.prod.js中插件中配置如下:

plugins: [
    new webpack.DllReferencePlugin({
      manifest: require("./build/library/library.json")
    }),
    new AddAssetHtmlPlugin({
      filepath: path.resolve("./build/library", "library.dll.js")
    })
]

起作用 就是把build/library/library.dll.js拷贝到编译后的dist文件夹下,并且通过script标签引入到index.html中。

最终页面生成的效果:

<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<head>
  <title>Document</title>
  <link href="search_42937580.css" rel="stylesheet">
</head>
<body>
  <div id="root"></div>
  <script src="library.dll.js"></script>
  <script src="search_c1f12d25.js"></script>
</body>
</html>

add-asset-html-webpack-plugin参考地址:https://www.npmjs.com/package/add-asset-html-webpack-plugin/v/3.2.2?activeTab=versions

充分利用缓存提升二次构建速度

目的:提升二次构建速度。

缓存思路:

  • babel-loader 开启缓存
  • terser-webpack-plugin 开启缓存
  • 使用 cache-loader 或者 hard-source-webpack-plugin

开启了对应方式的缓存,会在node_modules目录下的cache文件夹看到缓存的内容,如下结构:

  • node_modules
    • .cache
      • babel-loader
      • hard-source
      • terser-webpack-plugin

1、babel-loader 开启缓存

rules: [
  {
    test: /.js$/,
    use: ["babel-loader?cacheDirectory=true"
    ]
  }
]

如果是使用的HappyPack,配置如下:

new HappyPack({
    loaders: ["babel-loader?cacheDirectory=true"]
})

2、terser-webpack-plugin 开启缓存

optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
        cache: true
      })
    ]
  }

3、hard-source-webpack-plugin开启缓存
安装:

npm i hard-source-webpack-plugin -D

配置:

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

module.exports = {
    plugins: [
         new HardSourceWebpackPlugin()
    ]
}

在webpack4.x中会报错。

缩小构建目标与减少文件搜索范围

缩小构建目标

目的:尽可能的少构建模块

比如 babel-loader 不解析 node_modules

 rules: [
  {
    test: /.js$/,
    include: [path.resolve(__dirname, "src")],
    use: [
        "babel-loader"
    ]
  }

当然也可以使用exclude,来缩小构建范围。

减少文件搜索范围

  • 优化 resolve.modules 配置(减少模块搜索层级)
  • 优化 resolve.mainFields 配置
  • 优化 resolve.extensions 配置
  • 合理使用 alias

示例代码:

resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
      react: path.resolve(__dirname, "./node_modules/react/umd/react.production.min.js"),
      "react-dom": path.resolve(__dirname, "./node_modules/react-dom/umd/react-dom.production.min.js")
      extensions: [".js"],
      mainFields: ["main"]
  },

使用Tree Shaking擦除无用的JavaScript和CSS

概念:1 个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到
bundle 里面去,tree shaking 就是只把用到的方法打入 bundle ,没用到的方法会在
uglify 阶段被擦除掉。

使用:webpack 默认支持,在 .babelrc 里设置 modules: false 即可

  • production mode的情况下默认开启

要求:必须是 ES6 的语法,CJS 的方式不支持

无用的 CSS 如何删除掉?

  • PurifyCSS: 遍历代码,识别已经用到的 CSS class
  • uncss: HTML 需要通过 jsdom加载,所有的样式通过PostCSS解析,通过document.querySelector 来识别在 html 文件里面不存在的选择器

在 webpack 中如何使用 PurifyCSS?
PurifyCSS官网已经不再维护了,使用 purgecss-webpack-plugin这个插件和 mini-css-extract-plugin 配合使用。

安装purgecss-webpack-plugin插件:

npm i purgecss-webpack-plugin@4 -D

配置:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const PurgeCSSPlugin = require('purgecss-webpack-plugin')

const PATHS = {
  src: path.join(__dirname, 'src')
}

module.exports = {
 // 其他省略
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader"
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
    }),
    new PurgeCSSPlugin({
      paths: glob.sync(`${PATHS.src}/**/*`,  { nodir: true }),
    }),
  ]
}

使用webpack进行图片压缩(压缩有问题)

基于 Node 库的 imagemin 或者 tinypng API

使用:配置 image-webpack-loader

安装image-webpack-loader:

npm i image-webpack-loader@6 -D

其中imagemin-mozjpeg对node版本有要求:

 "engines": {
    "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
  }

配置:

{
test: /.(png|jpe?g|gif)$/,
    use: [
      {
        loader: "file-loader",
        options: { name: "[name]_[hash:8].[ext]" }
      },
      {
        loader: "image-webpack-loader",
        options: {
          mozjpeg: {
            progressive: true,
            quality: 65
          },
          // optipng.enabled: false will disable optipng
          optipng: {
            enabled: false
          },
          pngquant: {
            quality: [0.65, 0.9],
            speed: 4
          },
          gifsicle: {
            interlaced: false
          },
          // the webp option will enable WEBP
          webp: {
            quality: 75
          }
        }
      }
    ]
}

Imagemin的优点分析:

  • 有很多定制选项
  • 可以引入更多第三方优化插件,例如pngquant
  • 可以处理多种图片格式

Imagemin的压缩原理:

  • pngquant: 是一款PNG压缩器,通过将图像转换为具有alpha通道(通常比24/32位PNG
  • 文件小60-80%)的更高效的8位PNG格式,可显著减小文件大小。
  • pngcrush:其主要目的是通过尝试不同的压缩级别和PNG过滤方法来降低PNG IDAT数据
  • 流的大小。
  • optipng:其设计灵感来自于pngcrush。optipng可将图像文件重新压缩为更小尺寸,而不
  • 会丢失任何信息。
  • tinypng:也是将24位png文件转化为更小有索引的8位图片,同时所有非必要的metadata
  • 也会被剥离掉

构建体积优化:动态 Polyfill

直接把babel-polyfill打包到工程,一般会很大。

Polyfill Service原理:识别 User Agent,下发不同的 Polyfill

如何使用动态 Polyfill service?

polyfill.io 官方提供的服务

<script src="https://cdn.polyfill.io/v3/polyfill.js"></script>

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

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

相关文章

掌握远程管理的艺术:揭秘Python的pywinrm库

文章目录 &#x1f525; 掌握远程管理的艺术&#xff1a;揭秘Python的pywinrm库 &#x1f525;背景&#xff1a;为何选择pywinrm&#xff1f;pywinrm库简介安装pywinrm库简单库函数使用方法场景应用常见问题与解决方案总结 &#x1f525; 掌握远程管理的艺术&#xff1a;揭秘Py…

gingivitis

gingivitis 牙龈炎 1&#xff09;这个是啥不知道 2&#xff09;七叶莲片 3&#xff09;甲硝唑芬布芬胶囊 4&#xff09;盐酸左氧氟沙星胶囊 5&#xff09;纳珍 开始学习记录医生开的药。日常备药记录一下。【不要乱吃药哈】

C++ | Leetcode C++题解之第409题最长回文串

题目&#xff1a; 题解&#xff1a; class Solution { public:int longestPalindrome(string s) {unordered_map<char, int> count;int ans 0;for (char c : s)count[c];for (auto p : count) {int v p.second;ans v / 2 * 2;if (v % 2 1 and ans % 2 0)ans;}retur…

C语言进阶版第10课—qsort函数排序

文章目录 1. 回调函数2. qsort排序函数&#xff08;定义&#xff09;3. bubble冒泡函数4. qsort函数对整型数组排序5. qsort函数对字符指针数组排序6. qsort函数对结构体数组排序7. 模拟实现qsort排序函数7.1 模拟实现排序整型数组7.2 模拟实现排序结构体数组 8. 结构体访问 1.…

数据库事务中的四大问题:脏读、脏写、不可重复读与幻读详解

数据库事务中的四大问题&#xff1a;脏读、脏写、不可重复读与幻读详解 什么是脏读 定义 事务B读取数据时&#xff0c;读取到的是事务A更新之后&#xff0c;但还未提交的数据。 事务A修改了一条数据&#xff0c;但是还没有提交时&#xff0c;事务B查询到了这条未提交的数据…

火语言RPA流程组件介绍--下拉框选择

&#x1f6a9;【组件功能】&#xff1a;勾选下拉框选项 配置预览 配置说明 丨目标元素 支持T或# 默认FLOW输入项 通过自动捕获工具捕获(选择元素工具使用方法)或手动填写网页元素的css,xpath&#xff0c;指定对应网页元素作为操作目标 丨值 支持T或# 选中目标的值&#xf…

Leetcode 第 413 场周赛题解

Leetcode 第 413 场周赛题解 Leetcode 第 413 场周赛题解题目1&#xff1a;3274. 检查棋盘方格颜色是否相同思路代码复杂度分析 题目2&#xff1a;3275. 第 K 近障碍物查询思路代码复杂度分析 题目3&#xff1a;3276. 选择矩阵中单元格的最大得分思路代码复杂度分析 题目4&…

【SpringCloud】Spring Cloud 开发环境搭建与基础工程构建

目录 环境和工程搭建开发环境安装JDKJDK版本介绍JDK17安装WindowsLinux - UbuntuLinux - CentOs MySQL安装UbuntuCentOS 案例介绍需求服务拆分服务拆分原则服务拆分示例 数据准备工程搭建构建父子工程创建父工程DependencyManagement 和 DependenciesSpring Cloud版本 创建子项…

【生日视频制作】奔驰梅赛德斯大奔提车交车仪式感视频拍照AE模板修改文字软件一键生成器教程特效素材【AE模板】

生日视频制作教程奔驰梅赛德斯大奔提车交车仪式感视频拍照AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 AE模板套用改图文教程↓↓&#xff1a; 怎么如何做的【生日视频制作】奔驰梅赛德斯大奔提车交车仪式感视频拍照AE模板修改文字软件一键生成器教程特效素材【AE模…

下一代 AI 搜索:多智能体 + 系统2,解决 AI 搜索在复杂信息性能下降问题

下一代 AI 搜索&#xff1a;多智能体 系统2&#xff0c;解决 AI 搜索在复杂信息性能下降问题 AI 搜索&#xff1a;从搜索引擎到答案引擎① AI 搜索市场现状&#xff08;可跳过&#xff09;② 巨好用的 AI 工具推荐程序员的垂直搜索引擎 devv.ai ③ 多智能体 系统2&#xff0c…

易扫功能介绍

背景 之前开发扫描工具&#xff0c;在大家使用过程中提出了很多改进建议&#xff0c;其中最多的就是&#xff0c;IP地址变动&#xff0c;导致无法扫描。易扫软件系统解决了这个问题&#xff0c;同时易扫服务端&#xff0c;支持多操作系统平台安装。 系统架构 主要功能介绍 支…

字典+泛型的栈与队列+委托

字典 在System.Collections.Generic下&#xff0c;对应HashTable,添加了泛型的特性&#xff0c;性能更高更安全&#xff0c;在内存中散列排布&#xff0c;存储也是键值对。 Dictionary<键的数据类型&#xff0c;值的数据类型> 字典名new Dictionary<键的数据类型&am…

18063 圈中的游戏

### 思路 1. 创建一个循环链表表示围成一圈的 n 个人。 2. 从第一个人开始报数&#xff0c;每报到 3 的人退出圈子。 3. 重复上述过程&#xff0c;直到只剩下一个人。 4. 输出最后留下的人的编号。 ### 伪代码 1. 创建一个循环链表&#xff0c;节点表示每个人的编号。 2. 初始…

【视觉中国-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

TCP Analysis Flags 之 TCP ZeroWindow

前言 默认情况下&#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态&#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时&#xff0c;会对每个 TCP 数据包进行一次分析&#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…

9. 什么是 Beam Search?深入理解模型生成策略

是不是总感觉很熟悉&#xff1f; 在之前第5&#xff0c;7&#xff0c;8篇文章中&#xff0c;我们都曾经用到过与它相关的参数&#xff0c;而对于早就有着实操经验的同学们&#xff0c;想必见到的更多。这篇文章将从示例到数学原理和代码带你进行理解。 Beam Search 对应的中文翻…

工厂模式(一):简单工厂模式

一、概念 顾名思义&#xff0c;带着工厂&#xff0c;两字肯定就是有标准、快速、统一等等一些工厂独有的特点。 那么什么是简单工厂模式呢&#xff1f; 定义&#xff1a;简单工厂模式是一种创建对象的设计模式&#xff0c;它定义了一个工厂类通过某个静态方法来生成不同类型的…

基于AutoDL部署langchain-chatchat-0.3.1实战

一、租用AutoDL云服务器&#xff0c;配置环境 1.1 配置AutoDL环境 注册好autodl账户之后&#xff0c;开始在上面租服务器&#xff0c;GPU我选择的是RTX4090*2&#xff0c;西北B区&#xff0c;基础镜像选择的是Pytorch-2.3.0-python-3.12&#xff08;ubuntu22.04&#xff09;-…

夸克网盘电脑端和手机端如何查看自己分享的文件

夸克网盘有些地方做的还是有点抽象&#xff0c;好多东西是真的找不到。 找了半天终于找到了自己分享的文件&#xff0c;给大家分享下。 电脑端 点击左侧栏的“快传”&#xff0c;然后点击“我分享的” 手机端 手机端也是类似&#xff0c;点击“快传”后再点击“我分享的”&a…

白月光git

感觉bug好多干脆直接从头到脚梳理 感冒不嘻嘻 近况是&#xff1a; 早起学习 开车去沟里 把蜜蜂拍到狗身上 把车开回来 吃席 安装git和VScode 都是从官网上装的&#xff0c;不说那么多咯&#xff0c;之前说过&#xff1a; 进程间也要唠一唠-CSDN博客https://blog.csdn.net…