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

server/2024/9/24 2:57:47/

文章目录

    • 速度分析:使用 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

webpackplugin_1">速度分析:使用 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的耗时情况

webpackbundleanalyzer_32">体积分析:使用webpack-bundle-analyzer

示例代码:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports = {plugins: [new BundleAnalyzerPlugin()]
}

安装:

npm i webpack-bundle-analyzer -D

可以分析哪些问题?

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

webpack__Nodejs_52">使用高版本的 webpack 和 Node.js

高版本的webpacknode.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}}})]
};

webpackplugin__parallel__156">方法二: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})]
};

webpackplugin__parallel__180">方法三: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_483">使用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.ppmy.cn/server/121129.html

相关文章

伊犁云计算创建ftp

1 yum 安装不再说&#xff0c; 2 有局域网搭建不再说 参考之前的文档 我们直接干ftp 先装ftp 服务 进入 etc/vsftpd/vsftpd.conf 修改如上图 看一下ftp 21 端口是不是在监听 开始测试

操作系统笔记三

进程 把一个静态程序通过OS在内存中让cpu执行起来的动态执行过程叫进程 写代码都是用户态&#xff0c;而进程在执行过程中需要完成特定的功能&#xff0c;这些功能呢只有操作系统能提供&#xff0c;比如说读写文件&#xff0c;读写文件的过程是与硬盘打交道&#xff0c;这个过程…

对FPGA加载过程中不同寄存器初始化方式现象的分析

对FPGA加载过程中不同寄存器初始化方式现象的分析 概述目的术语和缩略语参考资料 相关原理分析MMCM时钟锁定分析声明信号时进行初始化RTL测试代码示波器现象 同步复位/置位初始化RTL测试代码示波器现象 异步复位/置位初始化RTL测试代码示波器现象 不进行任何初始化操作&#xf…

密集行人数据集 CrowdHumanvoc和yolo两种格式,yolo可以直接使用train val test已经划分好有yolov8训练200轮模型

密集行人数据集 CrowdHuman voc和yolo两种格式&#xff0c;yolo可以直接使用 train val test已经划分好 有yolov8训练200轮模型。 CrowdHuman 密集行人检测数据集 数据集描述 CrowdHuman数据集是一个专为密集行人检测设计的数据集&#xff0c;旨在解决行人密集场景下的检测挑…

力扣(leetcode)每日一题 2414 最长的字母序连续子字符串的长度

题干 字母序连续字符串 是由字母表中连续字母组成的字符串。换句话说&#xff0c;字符串 “abcdefghijklmnopqrstuvwxyz” 的任意子字符串都是 字母序连续字符串 。 例如&#xff0c;“abc” 是一个字母序连续字符串&#xff0c;而 “acb” 和 “za” 不是。 给你一个仅由小写…

一行命令,一分钟轻松搞定SSL证书自动续期

httpsok 是一个便捷的 HTTPS 证书自动续签工具&#xff0c;专为 Nginx 服务器设计。已服务众多中小企业&#xff0c;稳定、安全、可靠。现在的网站SSL免费证书有效期只有3个月&#xff0c;所以就会有经常更快SSL证书的需求&#xff0c;如果手上需要更换的SSL证书比较多的情况下…

Spring扩展点系列-MergedBeanDefinitionPostProcessor

文章目录 简介源码分析示例示例一&#xff1a;Spring中Autowire注解的依赖注入 简介 spring容器中Bean的生命周期内所有可扩展的点的调用顺序 扩展接口 实现接口ApplicationContextlnitializer initialize AbstractApplicationContext refreshe BeanDefinitionRegistryPos…

BDE在Win10下的ntwdblib.dll问题

老旧的delphi7运行在WIN10以上&#xff0c;用BDE连接MSSQL2008时&#xff0c;使用默认驱动MSSQL&#xff0c;登录时报错&#xff1a; Vendor initialization failed. Cannot load an IDAPI serverice library File :NTWDBLIB.dll 解决办法&#xff1a; 1、拷贝ntwdblib.dl…