webpack之常见性能优化_webpack性能优化-程序员宅基地

技术标签: webpack  前端  


关于webpack常见的性能优化,可从以下三方面做处理。

  1. 构建性能,当构建性能越高,开发效率越高。
  2. 传输性能,在这方面重点考虑网络中总的传输量,以及文件数量等。
  3. 运行性能,主要是指js在客户端的运行效率。

构建性能

减少模块解析

如果某个模块不做解析,该模块经过loader处理后的代码就是最终代码。

对于单独的模块不需要解析(不进行AST、不记录依赖、不进行依赖替换等操作,直接生成最终代码),可以做一下处理:

module.exports = {
    
	mode:'development',
	mdule:{
    
		noParse:/ElementUI/,
	}
}

对于存在依赖的模块,如果使用了noParse,存在的依赖并不会被记录和替换。

优化loader性能

限制loader的应用

针对某些第三方库,不必要使用某些loader处理。例如babel-loader,处理一些已经打包好的第三方库,反而增加了项目构建时间。

module.exports = {
    
	mode:'development',
	mdule:{
    
		rules:[
			{
    
				test:/\.js$/,
				include:/\.\src/,//应用于src目录下
				exclude:/node_modules/, //排除某些文件或目录
				use:["xx-loader"]
			}
		],
	}
}

缓存loader的结果

当文件内容不变时,经过相同的loader解析后,解析结果并没有改变,所以这个时候将loader的解析结果保存下来,让后续的解析直接使用保存的结果,具体如下:

module.exports = {
    
	module:{
    
		rules:[
			{
    
				test:/\.js$/,
				use:[{
    
					loader:'cache-loader'.
					cacheDirectory:'./cache'
				},...loaders]
			}
		]
	}
}

cache-loader的原理是,在执行loader之前,如果发现已缓存文件,直接在loader.pitch函数里return源代码。

多线程打包

通过thread-loader开启一个线程池,后续会把loader放进线程池的线程中运行以提高运行效率。

module.exports = {
    
	module:{
    
		rules:[
			{
    
				test:/\.js$/,
				use:[{
    
					loader:'cache-loader'.
					cacheDirectory:'./cache'
				},
				'thread-loader']
			}
		]
	}
}

thread-loader可以通过测试决定放置的位置。

开启热替换

热替换(Hot Module Replacement)可以降低代码改动到效果呈现的时间,最新webpack默认开启热替换。

module.exports = {
    
	mode:'development',
	devServer:{
    
		open:true,
		hot:true
	},
	plugins:[
		new HtmlWebpackPlugin({
    
			template:'./public/index.html'
		})
	]
}

默认情况下,webpack-dev-server不管是否开启热更新,当重新打包后,都会调用location.reload刷新页面,但如果运行module.hot.accept(),将改变这一行为。module.hot.accept的作用就是让webpack-dev-server通过socket管道,把服务器更新的内容发送到浏览器。

对于样式的热替换,可以添加style-loader

module.exports = {
    
	mode:'development',
	devServer:{
    
		open:true,
		hot:true
	},
	module:{
    
		rules:[{
    
			test:/\.css$/,
			use:['style-loader','css-loader']
		}]
	},
	plugins:[
		new HtmlWebpackPlugin({
    
			template:'./public/index.html'
		})
	]
}

常见loader和plugin

loader名称 loader描述
babel-loader 转换ES6+新特性语法
style-loader 将css文件引用并插到html
css-loader 支持.css文件的加载和解析
less-loader 支持less文件转换
sass-loader 支持sass文件转换
ts-loader 将ts转换成js
file-loader 进行图片、字体等文件的打包
raw-loader 将文件以字符串形式导入
thread-loader 多进程打包
plugin名称 plugin描述
CommonsChunkPlugin 将chunks相同的模块代码提取成公共js
CleanWebpackPlugin 清理构建目录
ExtractTextWebpackPlugin 从捆绑包或捆绑包中提取文本到单独的文件中
CopyWebpackPlugin 将文件或者文件夹拷贝到构建的输出目录
HtmlWebpackPlugin 创建html文件去承载输出的bundle
UglifyjsWebpackPlugin 压缩代码
TerserPlugin 压缩代码
ZipWebpackPlugin 将打包的资源生产zip包
OptimizeCSSAssetsPlugin css压缩插件
WebpackBundleAnalyzer 模块依赖的可视化

传输性能

分包

webpack默认不进行分包,会把所有依赖添加到同一个bundle,特别是在多页面打包的情况下,会存在多个chunk引入公共模块导致冗余代码的情况,占用打包体积。

分包的目的是在不影响源代码的情况下降低代码体积,并非所有的情况都适合分包,需要视具体情况而定。

手动分包

思路:

  1. 打包公共模块。例如常见第三方库。
  2. 手动引入公共js

注意事项:

  1. 不要对小型库进行单独打包。
  2. 不要对依赖多的库进行单独打包

公共模块打包过程如下:

//webpack.dll.config.js
const webpack = require('webpack')
module.exports = {
    
	mode:"production",
	entry:{
    
		element:['element'],
		jquery:['jquert']
	},
	output:{
    
		filename:'dll/[name].js',
		library:'[name]'//暴露全局变量名
	},
	plugin:[
		new webpack.DllPlugin({
    
			path:path.resolve(__dirname,'dll','[name].manifest.json'),//资源清单保存位置
			name:'[name]'//资源清单中保存的变量名
		}),
		
	]
}

//webpack.config.js
const webpack = require('webpack')
module.exports = {
    
	plugin:[
		new webpack.DllReferencePlugin({
    
			manifest:require('./dll/element.manifest.json')
		}) //指定资源清单,在打包时对照资源清单,当发现该模块是资源清单里的资源时不进行打包处理。
	]
}

引用: https://webpack.docschina.org/plugins/dll-plugin#dllplugin

自动分包

webpack提供了optimization配置项,其中splitChunks是分包策略的配置,通过splitChunksPlugin配置分包策略进行分包,分包时,webpack开启了一个新的chunk,对分离的模块进行打包。

一般开发阶段没必要分包,因为有热替换,并且开发一般是在本机,大文件对开发阶段影响不大。

分包的基础单位是模块。所以在设置minSize时有时会出现打包的文件超过该值。

全局策略:

module.exports = {
    
	entry:{
    },
	output:{
    },
	optimization:{
    
		splitChunks:{
    
			chunks:'all', //默认为async,可选all或者initial
			maxSize:30 *1024,//控制包的最大字节数
			automaticNameDelimiter:'.',//新chunk名称的分隔符,默认为~
			minChunks:1,//一个模块被多少个chunk使用时才会进行分包,默认为1
			minSize:30 * 1024,//单位为字节,当分包达到多少字节后才允许被真正地拆包,默认为30000
		},
	},
	plugin:[
	]
}

缓存组策略:
当不配置cacheGroups时,内部会存在vendors和default默认配置,我们也可以通过手动更改默认值。

module.exports = {
    
	entry:{
    },
	output:{
    },
	optimization:{
    
		splitChunks:{
    
			cacheGroups:{
    
				//默认存在以下配置,可继承全局配置
				vendors:{
    
					test:/[\\/]node_modules[\\/]/,//当匹配到相应模块时,将这些模块进行单独打包
					priority:-10//缓存组优先级,优先级越高,该策略越先进行处理,默认值为0
				},
				default:{
    
					minChunks:2,//最小chunk引用数为2
					priority:-20,//优先级
					reuseExistingChunk:true,//重用已经分离的chunk
				},
				elementUI:{
    
					minSize:0,
					test: /[\\/]node_modules[\\/]_?element-ui(.*)/,
					minChunks:2
					}
			}
		},
	}
}

模块体积优化

代码压缩

webpack内置terser,terser是一个代码压缩工具,压缩代码除了压缩代码体积,还可以提升破解成本。

Terser官网:https://terser.org/

默认情况下webpack的production模式是开启代码压缩,当我们要更改压缩配置时,可做以下处理:

module.exports = {
    
	optimization:{
    
		minimize:true, //是否启动压缩,默认是只在生产环境自动开启。
		minimizer:[
			//压缩时使用的插件,当你自动改压缩配置时必须配置相关压缩插件
			new TerserPlugin(),//js压缩插件
			new OptimizeCSSAssetsPlugin()//css压缩插件
		]
	}
}

terser、webpack、rollup.js都能够识别/*#__PURE__/注释标记,/*#__PURE__/的作用就是告诉打包工具该函数的调用不会产生副作用。

tree shaking

tree shaking,树摇,可以理解为摇动一棵树,即将腐烂的果实也随之摇动而掉落。

能够tree shaking的代码需要满足一定的代码规范,例如以下情况:

//有利于tree shaking
export xxx 导出,
import {
    xxx} from 'xxx'导入

//不利于tree shaking
export default {
    xxx}导出,
import xxx from ‘xxx'导入

上面的情况当webpack依赖分析完毕后,webpack会根据每个模块每个导出是否被使用,标记其为dead code,然后交给代码压缩工具处理。

commonjs很难做到tree shaking,所以主流的库为了做tree shaking,都会发布其es6版本。

以vue为例,vue的代码中大量使用/*#__PURE__*/注释,通常产生副作用的代码都是模块内函数的顶级调用。该注释可以作用于任何语句上,让打包工具识别。

tree shaking对于无法识别副作用的函数会认为是副作用函数,不会产生副作用的代码标记/*#__PURE__*/注释。

相比于js,css并无法做到tree shaking,不过可以通过正则匹配页面样式有没有引用进行移除样式代码。

可以通过purgecss-webpack-plugin进行处理,css module无法处理。

https://www.npmjs.com/package/purgecss-webpack-plugin

懒加载

通过动态导入模块,例如在判断里使用导入语句。
导入语句不能使用commonjs,虽然require支持动态导入,但是它在打包环节也会进入依赖分析。
动态加载可以使用import(),import作为es6的草案,webpack打包发现使用import()的调用,会对其单独打包,打包结果该代码时,浏览器会使用jsonp远程请求该模块,import()返回的是一个promise。

async function run(){
    
	if(判断条件){
    
		const {
     chunk } = await import(/* webpackChunkName:'自定义chunkName' */'xxx.js')
	}
}
run()

请求的异步的模块会加入webpackJsonp数组里。

值得注意的是,这样的异步导入是不可以做到tree shaking的,不过可以使用取巧的方法,通过一个媒介引入,打包分析过程既能tree shaking又能异步加载。

//媒介文件
export {
     xxx } from '目标文件'

//主文件
async function run(){
    
	if(判断条件){
    
		const {
     chunk } = await import(	'媒介文件')
	}
}
run()

gzip

http传输中,开启gzip需要进行如下配置:

  1. request header:Accept-Encoding:gzip,deflate,br
  2. response header:Content-Encoding:gzip

对哪些文件压缩,采用哪种压缩算法,这个需要测试权衡,毕竟压缩文件和解压文件都是需要时间的,对于相对大点的文件一般会有收益。

webpack压缩参与的步骤在于将文件预压缩,当请求到来时直接响应已经压缩的文件,而不需要先压缩再响应。

gzip预压缩可以通过compression-webpack-plugin插件进行。

const CompressionWebpackPlugin = require('compression-webpack-plugin')

module.export = {
    
	plugin:[
		new CompressionWebpackPlugin({
    
			test:/\.js$/ //针对需要预压缩的文件
			minRatio:0.5 //压缩比率
		})
	]
}

以gzip为例,打包之后的文件包含了.js和.js.gz文件

辅助工具

  1. ESLint:通过ESLint规范代码。
  2. webpack-bundle-analyzer:通过该插件可以生成可视化打包结果的页面,有助于我们分析模块依赖。

运行性能

运行性能这方面,主要指js在浏览器端运行速度,取决于我们如何书写高性能的代码。

关于高性能的代码,可以参考常见的设计模式、代码规范、最佳实践等。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Mr_RedStar/article/details/123462435

智能推荐

c语言开发无人机自动驾驶仪,无人机自动驾驶仪.pdf-程序员宅基地

文章浏览阅读780次。无人机自动驾驶仪.pdf先进的多功能无人机自动驾驶仪 先进的多功能无人机自动驾驶仪 某 型 先 进 的 多 功 能 图 形 化 组 态 编 程 无 人 机 飞 行 控 制 系 统 ,非 常 适 合 用 户 根 据 个 性 化 需 求 进 行 二 次 开 发 和 功 能 扩 展 。它 集 飞 行 控 制 、数 据 采 集 、控 制 律 设 计 和 半 物 理 仿 真 四 大 功 能 于 一 体 ,适...

Java项目:校园人力人事资源管理系统(java+Springboot+ssm+mysql+jsp+maven)_学校人事管理系统设计代码-程序员宅基地

文章浏览阅读5k次,点赞18次,收藏71次。源码获取:博客首页 "资源" 里下载!校园人力资源管理系统:学校部门管理,教室管理,学历信息管理,职务,教师职称,奖励,学历,社会关系,工作经历,培训管理,公告等信息功能等等。部门控制层:@RequestMapping("/Department")@RestControllerpublic class DepartmentController { @Autowired IDepartmentService departmentServi..._学校人事管理系统设计代码

UWA报告使用小技巧,你get了吗?(第五弹)_uwa 使用-程序员宅基地

文章浏览阅读191次。动动手指,get新技能!_uwa 使用

机器学习学习笔记.day13_由第i个高斯混合成分生成且类别为j的概率-程序员宅基地

文章浏览阅读682次。周志华《机器学习》 学习笔记最近开始学习机器学习,参考书籍西瓜书,做点笔记。第十三章 半监督学习13.1 未标记样本让学习器不依赖外界交互、自动的利用未标记样本来提升学习性能,就是半监督学习;聚类假设:假设数据存在簇结构,同一个簇的样本属于同一个类别;流形假设:假设数据分布在一个流行结构上,邻近的样本拥有相似的输出值;半监督学习可进一步分为纯半监督学习和_由第i个高斯混合成分生成且类别为j的概率

fork创建进程过程(底层实现) 和 写实拷贝_fork系统调用创建新进程的过程和原理,写时拷贝-程序员宅基地

文章浏览阅读835次。linux系统中提供了三个系统调用可以创建新进程:clone()、fork()、vfork()。实际上,不管是我们比较熟悉的fork()还是剩下的两个在linux中都是通过clone()实现的。clone()是在c语言库中定义的一个封装函数,它负责建立进程堆栈并且调用对程序员隐藏的clone()系统调用。 进一步观察发现,linux内核中又是用do_fork()来处理这三个系统_fork系统调用创建新进程的过程和原理,写时拷贝

关于解决vivado error:add_1 must be in range [-1,DEPTH-1] 问题_vcs仿真时error:add_1 must be in range [-1,depth-1]-程序员宅基地

文章浏览阅读2.1k次。在仿真vivado fft ip 核时出现关于解决vivado error:add_1 must be in range [-1,DEPTH-1] 问题经查找资料与亲自实践得出如下结论1.拉高m_ tready,貌似不拉高也没有问题2.上电复位要给s_axis_config_tvalid和s_axis_config_tdata初始化,并配置一下..._vcs仿真时error:add_1 must be in range [-1,depth-1]

随便推点

Win7如何共享有线网络实现手机上网_win7怎么共享网络手机-程序员宅基地

文章浏览阅读4.1k次。使用win7自带的创建临时网络,是计算机到计算机的,所以不支持手机连接所以需要两个命令来实现netsh wlan set hostednetwork mode=allow ssid=你想建立的网络名字(英文格式) key=你想设置的密码(至少8位)回车再输入netsh wlan start hostednetwork按回车,激活这个无线网络。(这两条命令有先后顺序)_win7怎么共享网络手机

网络里面计算机这么解除权限,电脑上软件的权限怎么关闭-程序员宅基地

文章浏览阅读4.6k次。电脑上软件的权限怎么关闭今天给大家介绍一下电脑上软件的权限怎么关闭的具体操作步骤。1. 首先我们需要下载安装一个电脑管家的软件,请大家自行下载安装。2. 安装之后,打开电脑管家软件,进入主页面后,点击左侧的工具箱选项。3. 在打开的右侧页面,点击上方的搜索框,输入权限雷达下载,进行搜索4. 在结果中,打开权限雷达选项,在打开的窗口中,点击页面中的立即扫描选项5. 扫描之后,如图,我们就可以看到电脑..._电脑下载权限怎么解除?

matlab读取struct数据结构,matlab基本数据结构struct-程序员宅基地

文章浏览阅读7.2k次。一起来学演化计算-matlab基本数据结构struct觉得有用的话,欢迎一起讨论相互学习~Follow Me结构数组structMATLAB提供了两种定义结构的方式:直接应用和使用struct函数使用直接引用方式定义结构与建立数值型数组一样,建立新struct对象不需要事先申明,可以直接引用,而且可以动态扩充。比如建立一个复数变量xx.real = 0; % 创建字段名为real,并为该字段赋值为..._matlab struct 读取

北航课程中心不能登录解决办法(Error 500: No message found under code 'screen.welcome.digit.tip' for locale 'en_US')_welcome登录入口500-程序员宅基地

文章浏览阅读6.5k次。1.原因分析在登录北航课程中心的时候经常会出现这种错误:Error 500: No message found under code 'screen.welcome.digit.tip' for locale 'en_US'.根据错误提示,打开开发者工具(键盘 F12 键),在 Network 面板中发现发送的数据的头部信息(header) 中的 Accept-Langua_welcome登录入口500

摘录的一些Bjarne Stroustrup关于C++的谈话内容_bjrane stroustrup的书-程序员宅基地

文章浏览阅读5.8k次。1 专访 Bjarne Stroustrup2 C++ 热点问题一席谈3 C++0x 热点问题访谈4 C++0x 概览 专访 Bjarne Stroustrup 来源:荣耀 马皓明 译 作者:Bjarne Stroustrup 等级:一般 发布于2005-10-22 22:54 被读1091次 【字体:大 中 小】 _bjrane stroustrup的书

C#:图片的 粒子化 破碎效果_c# 粒子-程序员宅基地

文章浏览阅读1.5k次。0.之前是做java语言安卓开发,看到了图片的粒子化破碎效果,一直没时间好好研究。这次在c#语言中做窗体应用开发,终于研究出这个效果了。文章是借鉴Android的,不过原理都差不多。学习网址如下:https://www.jianshu.com/p/12184d8616461. 先看看图片的像素级操作的代码,很简单//初识//创建一个2X2的图片,每个像素占24位..._c# 粒子