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

文章目录

    • 速度分析:使用 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 optipngoptipng: {enabled: false},pngquant: {quality: [0.65, 0.9],speed: 4},gifsicle: {interlaced: false},// the webp option will enable WEBPwebp: {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.rhkb.cn/news/425187.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于C#+Mysql实现(界面)企业的设备管理系统

管理信息系统课程设计说明书 1 引言 企业的设备管理在企业的生产制造和管理过程之中意义比较重大&#xff0c;明确企业的设备的产权和维护成本对于企业的成本控制和财务管理之中起到了重要的作用。随着市场竞争的加剧&#xff0c;现代企业所处的市场环境发生了深刻的变革&…

【Mac】系统环境配置

常用工具 Navicat PJ版本&#xff1a;this Host切换器 SwitchHosts termius 一款好用的Linux服务器连接工具&#xff1a; termius 小飞机 dddd&#xff1a;&#x1fa9c; Git mac安装git有好多种方式&#xff0c;自带的xcode或者通过Homebrew来安装&#xff0c;本文的…

Java——类型转换

一、类型转换 1、介绍 类型转换分为自动类型转换和强制类型转换。 2、自动类型转换 自动类型转换是指在表达式中&#xff0c;当两种不同的数据类型组合在一起时&#xff0c;较小的数据类型会自动转换为较大的数据类型&#xff0c;这个过程是自动的&#xff0c;无需编程者手…

清华大佬自曝:接到了省烟草局的offer,我就拒掉了华为!结果华为立马给我申请了特殊涨薪,总包70w是烟草的2倍,这可如何是好?

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 《Java代码审…

C:字符串函数(续)-学习笔记

穗 一些闲话&#xff1a; 最近玩了这款饿殍-明末千里行&#xff0c;不知大家是否有听过这款游戏&#xff0c;颇有感触&#xff01;&#xff01;&#xff01; 游戏中最让我难以忘怀的便是饿殍穗线的故事&#xff0c;生在如今时代的我之前无法理解杜甫在目睹人间悲剧时的心情&…

【网络原理】❤️Tcp 连接管理机制❤️ “三次握手” “四次挥手”的深度理解, 面试最热门的话题,没有之一, 保姆式教学 !!!

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

华为 HCIP 认证费用和报名资格

在当今竞争激烈的信息技术领域&#xff0c;华为 HCIP认证备受关注。它不仅能提升个人的技术实力与职业竞争力&#xff0c;也为企业选拔优秀人才提供了重要依据。以下将详细介绍华为 HCIP 认证的费用和报名资格。 一、HCIP 认证费用 华为HCIP认证的费用主要由考试费和培训费构成…

电气自动化入门01:电工基础

视频链接&#xff1a;1.1 电工知识&#xff1a;电工基础_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1PJ41117PW?p2&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.电能和电力系统 2.电工常用物理量及其应用 2.1电阻&#xff1a; 2.2电流&#xff1a; 2.3电压&…

【C++】入门基础(下)

Hi&#xff01;很高兴见到你~ 目录 7、引用 7.3 引用的使用&#xff08;实例&#xff09; 7.4 const引用 【第一分点】 【第二分点1】 【第二分点2】 7.5 指针和引用的关系&#xff08;面试点&#xff09; 8、inline 9、nullptr Relaxing Time&#xff01; ———…

系统 IO

"裸奔"层次&#xff1a;不带操作系统的编程 APP(应用程序) -------------------------------- Hardware(硬件) 特点&#xff1a;简单&#xff0c;应用程序直接操作硬件(寄存器) 缺点&#xff1a; 1. 搞应用开发的必须要了解硬件的实现细节&#xff0c;能够看懂原理图…

MyBatis 增删改查【后端 17】

MyBatis 增删改查 引言 MyBatis 是一个优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射&#xff0c;将接口和 Java 的 POJOs (…

yolo训练出现Could not load library libcudnn_cnn_train.so.8问题及解决方法

问题场景&#xff1a; 训练yolov5或者yolov8时候会报错&#xff1a; Could not load library libcudnn_cnn_train.so.8. Error: /usr/local/cuda-12.1/lib64/libcudnn_cnn_train.so.8: uined symbol: _ZN5cudnn3cnn34layerNormFwd_execute_internal_implERKNS_7backend11Vari…

java技术栈介绍

Java技术栈是一个庞大而丰富的生态系统&#xff0c;它包含了从基础语言特性到高级框架、库和工具的整个集合。这个技术栈为开发者提供了构建各种类型应用&#xff08;包括企业级应用、Web应用、移动应用、大数据应用等&#xff09;所需的全部组件。以下是对Java技术栈的一个更详…

zip压缩包的格式不标准导致C++开源unzip.cpp解压失败问题的排查

目录 1、问题描述 2、初步排查 3、查看错误码512对应的含义 4、直接将解压zip包的函数拷贝过来,并将无法解压的zip取来,直接编写测试代码去调试解压过程,最终定位问题 4.1、调试开源unzip.cpp源码的准备工作 4.2、刚解压zip包中最顶层的文件夹就失败了 4.3、是不是zi…

深度学习之微积分预备知识点

极限&#xff08;Limit&#xff09; 定义&#xff1a;表示某一点处函数趋近于某一特定值的过程&#xff0c;一般记为 极限是一种变化状态的描述&#xff0c;核心思想是无限靠近而永远不能到达 公式&#xff1a; 表示 x 趋向 a 时 f(x) 的极限。 知识点口诀解释极限的存在左…

【CSS】 Grid布局:现代网页设计的基石

引言 最近接到一个网页布局比较复杂的页面&#xff0c;看了半天还是决定用grid布局来写&#xff0c;记录一下 布局是构建用户界面的关键部分。CSS Grid布局提供了一种简单而强大的方式来创建复杂的网格布局&#xff0c;它让设计师和开发者能够更直观、更灵活地控制网页的结构。…

MySQL 子查询全解析:执行、性能影响与优化策略

在 MySQL 数据库的操作中&#xff0c;子查询是一个强大而又复杂的工具。今天&#xff0c;我们就来深入探讨 MySQL 如何执行子查询、其性能影响、优化方法以及哪些情况下应避免使用子查询。 一、MySQL 如何执行子查询 非相关子查询 非相关子查询也被称为独立子查询&#xff0c;…

网络安全学习(三)Hydra破解密码

接下来看一下Hydra工具&#xff0c;这是一个暴力破解密码的工具。 使用命令&#xff08;注意区分大小写&#xff09;。 hydra -L user.txt账号字典 -P pass.txt密码字典 IP地址 smb协议名称 hydra -l administrator指定账号 -P pass.txt密码字典 IP地址 smb协议名称 hydra -…

数据结构(Day13)

一、学习内容 内存空间划分 1、一个进程启动后&#xff0c;计算机会给该进程分配4G的虚拟内存 2、其中0G-3G是用户空间【程序员写代码操作部分】【应用层】 3、3G-4G是内核空间【与底层驱动有关】 4、所有进程共享3G-4G的内核空间&#xff0c;每个进程独立拥有0G-3G的用户空间 …

【Go】Go语言介绍与开发环境搭建

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