Web 前端性能优化之五:构建优化

4、构建优化

资源的合并与压缩所涉及的优化点包括两方面:一方面是减少HTTP的请求数量,另一方面是减少HTTP请求资源的大小。

1、HTML 压缩
1、什么是 HTML 压缩

在这里插入图片描述

百度首页部分 HTML 源代码

在这里插入图片描述

谷歌首页部分 HTML 源代码

虽然这些格式化的字符能带来很好的代码可读性,但对浏览器解析过程来说其实并不需要,反而还增加了资源的开销。

HTML压缩就是要删除在文本文件中有意义的,但在HTML中并不参与解析的字符。这些字符包括空格、制表符、换行符及一些其他意义的字符,如HTML注释等。

如果单纯只看一个文件的压缩,可能效果并不明显,比如就以前面百度首页为例,原始字符长度为158519,经过压缩之后的长度为157334,长度减少了约0.75%。

难道这就能说明HTML压缩的效果不明显吗?其实我们不能这么考虑,对大型的互联网公司来说,每一个请求的减少都是一个非常大的优化。以谷歌为例,它的网络流量占到了全网流量的40%左右,假如网络流量能达到5ZB(1ZB=109TB),以谷歌的流量占比,它当年的实际网络流量就是5ZB×40%=2ZB,那么当谷歌经过优化让每1MB的请求减少一个字节,则整年便可节省2000TB的流量。如果以每GB流量一毛钱计算,那么一年省下来的开支也不是个小数目,这就是要进行HTML压缩的原因。

2、如何压缩
1、使用 html-minifier

使用nodejs所提供的html-minifier工具进行压缩,它涉及很多参数的配置,包括是否去掉注释removeComments,是否去掉空格collapseWhitespace,是否压缩HTML中的JavaScript的minifyJS及是否压缩HTML中的CSS的minifyCSS,具体方式如下:

在这里插入图片描述

2、CSS 压缩

CSS代码也能进行压缩,而且很有必要去压缩,如下是谷歌首页经过压缩的部分CSS源代码:

在这里插入图片描述

谷歌首页部分 CSS 源代码

从中非常直观的感受是它去掉了回车和换行,此外这里的CSS压缩还做了两件事:首先是无效代码的删除,因为对有些CSS来说,无效的代码可能是注释和无效字符,需要将这些无效的代码删除,这一步很重要;其次是CSS语义合并,通常我们写的CSS可能由于文件层级的嵌套,很难避免一定的语义重复,所以就需要进行语义合并。

可以使用html-minifier针对HTML中的CSS进行压缩。除此之外,还可以使用clean-css进行CSS的压缩,其基本使用方法如下:

在这里插入图片描述

clean-css也有许多配置项,比如是否基于语义进行合并的merging,是否优化颜色取值的colors,以及诸多对不同类型浏览器兼容性的规则导出。

3、JavaScript 压缩与混淆

JavaScript部分的处理主要包括三个方面:无效字符和注释的删除、代码语义缩减和优化及代码混淆保护。无效字符和注释的删除原理与HTML和CSS的压缩类似。

1、代码语义缩减和优化

通过对JavaScript的压缩可以将一些变量的长度进行缩短,比如说原本一个很长的变量名经过压缩后,可以用很短的像a、b来代替,这样能进一步有效地缩减JavaScript的代码量。同样还可以针对一些重复代码进行优化,比如去除重复的变量赋值,将一些无效的代码进行缩减与合并的优化。

在这里插入图片描述

2、代码混淆保护

由于任何能够访问到网站页面的用户,都可以通过浏览器的开发者工具查看到前端的JavaScript代码,如果前端代码的语义非常明显,没进行压缩也没进行混淆,其格式还完整保留,那么理论上任何访问网站的人都可以轻易地窥探到我们代码中的逻辑,从而去做一些威胁系统安全的事情。所以进行JavaScript代码压缩和混淆的处理,也是对我们前端代码的一种保护。

如何来防止别有用心之人窥探到我们业务的核心代码呢?实际上就是进行JavaScript压缩,将前端源代码的可读性变得尽可能低,混淆变量与方法的命名。

对大部分公司来说,HTML压缩可有可无,但是CSS与JavaScript压缩却是必须要进行的。

JavaScript压缩处理也有类似的第三方库可供使用:uglifyJS2。可以通过npm引入uglify-js库来使用,也可以结合构建工具一起使用,其单独使用时的方法如下:

在这里插入图片描述

其中压缩混淆的配置对象结构如下:

在这里插入图片描述

4、webpack 构建与优化
1、尽量与时俱进:尽可能使用最新稳定版本的webpack、nodejs、npm或yarn能有效地提升打包构建的效率。
2、较少 Loader 的执行

根据具体情况使用include或exclude,在尽可能少的模块上执行Loader。webpack的配置文件如下:

在这里插入图片描述

这里关注module字段中对JavaScript文件的处理规则,如果不加exclude字段,则webpack会对该配置文件所在路径下的所有JavaScript文件使用babel-loader,虽然babel-loader的功能强大,但它执行起来很慢。

这样所处理的JavaScript不仅会包含我们的项目源代码,还会涉及node_modules路径下项目引用的所有第三方文件。由于第三方库的文件在发布前本身已经执行过一次babel-loader,没必要再重复执行一次,增加不必要的打包构建耗时,所以exclude字段不可省略。

同时与之对应的还有一个include字段,其使用含义与exclude相反,即仅对其指定范围内的JavaScript文件进行处理,以降低loader被执行的频率。

对于图片文件则没有必要通过include或exclude来降低loader的执行频率,因为无论哪里引入的图片,最后打包都需要通过url-loader对其进行处理,所以include或exclude的语法并不适用于所有loader类型,要根据具体的情况而定。

使用exclude或include可以帮助我们规避对庞大的第三方库文件的处理,但仅通过限定文件处理范围所带来的性能提升其实是有限的,除此之外,如果开启缓存将构建结果缓存到文件系统中,则可让babel-loader的工作效率得到成倍增加,处理方式也很简单,只需为loader增加相应的参数即可:

在这里插入图片描述

3、确保插件的精简和可靠

建议使用webpack官方网站上推荐的插件

4、合理配置 resolve 参数

配置resolve参数可以为我们在编写代码引入模块时提供不少便利,比如使用extensions省略引入JavaScript文件的后缀,使用alias减少书写所引入模块的多目录层级,使用mainFiles声明目录下的默认使用文件等,但当我们使用这些参数带来便利的同时,如果滥加使用也会降低打包速度。

1、可对 js、ts 省略路径,但不要对 css、图片等设置

在这里插入图片描述

可以使用resolve中的extensions属性来申明这些后缀,让项目在构建打包时,由webpack帮我们查找并补全文件后缀。同时对组件路径的引用也可通过resolve的alias配置来进行简化,配置如下:

在这里插入图片描述

如此配置的含义是,当所引入的模块默认了文件后缀时,webpack会在其指定路径下依次查找是否有.js、.jsx、.ts这三种后缀的文件,如果有便使用,并且在模块引入的同时用cpn代替src/component。当有了上述配置后,之前提到的Hello模块的引入便可写成如下形式:

在这里插入图片描述

2、不建议使用 mainFiles 属性

另外,resolve还有一个mainFiles属性,通过对它的配置可以指定让webpack查找引入模块路径下的默认文件名,虽然它能在很大程度上简化模块引用的编码量,但付出的代价是增加了打包构建过程中对目标文件的查找时间,所以不建议使用

5、使用 DllPlugin

前端项目中经常会用到庞大的第三方库,来协助我们完成特定功能的开发,而每当发生修改需要重新进行打包时,webpack会默认去分析所有引用的第三方组件库,最后将其打包进我们的项目代码中。在通常情况下,第三方组件包的代码是稳定的,不更换所引用的版本其代码是不会发生修改的,所以这就给出了一条优化的思路:我们仅需要在第一次打包时去分析这些第三方库,而在之后的打包过程中只需使用之前的结果即可。

这便会用到DllPlugin,它是基于Windows动态链接库(DLL)的思想创建出来的,该插件会把第三方库单独打包到一个文件中,作为一个单纯的依赖库,它不会和我们的项目代码一起参与重新打包,只有当依赖自身发生版本变化时才会重新进行打包。

使用DllPlugin处理文件的过程可分为两步:首先基于动态链接库专属的配置文件打包dll库文件,然后再基于webpack的构建文件打包项目代码。下面以一个简单的React组件为例:

在这里插入图片描述

这里引入了三个在React项目中经常会遇到的第三方包react、react-dom和lodash,如果我们不进行任何处理,每当修改该文件后进行重新打包,则都会引起webpack去分析它们,若打包次数频繁,显然会浪费许多时间。

接下来我们进行优化,具体分为两步,首先将所依赖的第三方库打包成dll文件,然后检查第三方库的版本是否在其后的迭代中发生了变化,若无变化就都使用之前的打包结果。这里可以为第三方库创建单独的配置文件,内容如下:

在这里插入图片描述

该配置文件中将react、react-dom和lodash三个包的包名存储在数组中,并赋值给vendors,其含义是经过打包后,这三个包归于一个名为vendors的包。output中声明了该包的文件名及输出路径,library字段表示该第三方包对外暴露的引用名,即在其他地方可以使用该字段值引用包中的内容。最后使用webpack中的DllPlugin插件对该包中的映射关系进行分析,并将结果输出到指定路径下的json文件。

然后我们需要在webpack主配置文件中,声明对上述打包好的第三方包的使用规则:

在这里插入图片描述

这样配置的意思是首先引入第三方包的打包结果路径,其次引入第三方包的映射关系,当发生重新打包构建时,webpack会首先查看引用的第三方包是否包含在已建立的映射关系文件vendor.manifest.json中,若存在便通过所声明的全局变量vendors去使用,若不存在便去node_modules中获取所需的模块,动态地进行打包操作。

上述方式虽然能够降低重复打包构建的时间,但将项目中所有第三方包都打包进一个文件,势必会使其体积过大从而导致请求过慢,所以在实际项目中,我们也应根据各个第三方包的大小进行拆分,就上述代码而言,可将react和react-dom从vendors中组成为一个新包,代码如下:

在这里插入图片描述

如此在执行webpack构建后会生成四个文件,分别是:vendors包的代码文件vendors.dll.js和其映射关系文件vendors.manifest.json,react包的代码文件react.dll.js和其映射关系文件react.manifest.json,同时对应的主配置文件也需要进行相应的修改,以引入打包的代码文件和映射关系文件。

在这里插入图片描述

这样处理后,既降低了重复构建时的打包时间,又规避了打包成单一文件时,可能由于代码文件体积过大而存在加载过慢的风险。

6、将单进程转化为多进程

webpack是单进程的,就算有多个任务同时存在,它们也只能一个一个排队依次执行,这是nodejs的限制。

但好在大多数CPU已经都是多核的了,我们可以使用happypack充分释放CPU在多核并发方面的优势,帮助我们把打包构建任务分解成多个子任务去并发执行,这将大大提高打包的效率。其使用方法也很简单,就是将原有的loader配置转移到happypack中去处理:

在这里插入图片描述

7、压缩打包结果的体积
1、删除冗余代码

webpack从2.0版本开始,便基于ES6推出了Tree-shaking,它能根据import、export的模块导入导出语法,在构建编译过程中分析每个模块是否被真实使用,对于没用到的代码,会在最后的打包结果中删除。

容易看出Tree-shaking对处理模块级的代码冗余比较擅长,但对更细粒度的代码冗余,比如console语句、注释等,可能就需要在CSS和JavaScript压缩过程中进行处理了,常用的方式是通过uglifyjs-webpack-plugin来实现的,具体配置方式如下:

在这里插入图片描述

2、代码拆分按需加载

项目源代码也需要拆分,可以根据路由来划分打包文件,当访问到不同路由时再触发相应回调请求打包文件,对于webpack的打包输出的配置如下:

在这里插入图片描述

以React项目为例,在配置路由时还需添加如下内容:

在这里插入图片描述

此处的关键方法就是require.ensure这个异步方法,webpack会将我们这里定义的组件单独打包成一个文件,仅当路由跳转到mine时,才会触发回调去获取MyComponent组件的内容。

3、可视化分析

分析打包结果的可视化工具:webpack-bundle-analyzer。它的分析结果会生成一个文件大小图:

该插件的工作原理也比较简单,就是分析在compiler.plugin(‘done’,function(stats));时传入的参数stats,它是webpack的一个统计类Stats的实例,然后通过对实例调用toJson()方法转成json文件,再从中提取出chunks各个包的大小信息,最后在Canvas中进行画图。通过该图能让开发者快速意识到哪些模块异常的大,然后找出过大的原因去优化它。

在这里插入图片描述

webpack-bundle-analyzer分析结果

该工具使用起来也很方便,就如使用普通插件一样:

在这里插入图片描述

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

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

相关文章

SpringBoot及其特性

0.前言 Spring 框架提供了很多现成的功能。那么什么是 Spring Boot?使用 Spring 框架,我们可以避免编写基础框架并快速开发应用程序。为了让 Spring 框架提供基础框架,我们需要向 Spring 框架描述有关我们的应用程序及其组件的信息。 不只是…

OpenAI Sora:浅析文生视频模型Sora以及技术原理简介

一、Sora是什么? Sora官方链接:https://openai.com/sora 视频模型领头羊Runway Gen 2、Pika等AI视频工具,都还在突破几秒内的连贯性,而OpenAI,已经达到了史诗级的纪录。 OpenAI,永远快别人一步&#xff0…

C语言面试题之判定字符是否唯一

判定字符是否唯一 实例要求 实现一个算法,确定一个字符串 s 的所有字符是否全都不同 实例分析 1、使用一个大小为 256 的bool数组 charSet 来记录字符是否出现过;2、遍历字符串时,如果字符已经在数组中标记过,则返回 false&a…

Golang 开发实战day08 - Multiple Return values

Golang 教程08 - Multiple Return values 1. Multiple return values 1.1 如何理解多个返回值? Go语言中的多返回值,就像你听了一首歌曲yellow,可以从歌曲里反馈出忧郁和害羞!Goland的多个返回值就类似于如此,设定一…

LangChain - OpenGPTs

文章目录 MessageGraph 消息图认知架构AssistantsRAGChatBot 持久化配置新模型新工具astream_events总结 关键链接: OpenGPT GitHub 存储库YouTube 上的 OpenGPT 演练LangGraph:Python、JS 两个多月前,在 OpenAI 开发日之后,我们…

检定重型铸铁平台的方法——北重厂家

检定重型铸铁平台的方法一般包括以下几个方面: 1.外观检查:检查平台表面是否平整和光滑,是否有明显的裂纹、磨损或损坏等情况。 2.尺寸检测:使用专用的测量工具,如千分尺、测微计等,测量平台的尺寸&#x…

Day107:代码审计-PHP模型开发篇MVC层RCE执行文件对比法1day分析0day验证

目录 MVC 架构 CNVD-代码执行1day-lmxcms1.40版本 CNVD-命令执行1day-baijiacms4.1.4版本 知识点: 1、PHP审计-MVC开发-RCE&代码执行 2、PHP审计-MVC开发-RCE&命令执行 3、PHP审计-MVC开发-RCE&文件对比 MVC 架构 MVC流程: Controller截…

支持向量机(SVM)白话之个人理解(学习记录)

本文仅有文字理解部分,没有相应的数学公式推导过程,便于新手理解。 一、什么是支持向量机 首先我们看下面这张图,在图中圆形和三角形分别代表不同的数据类型,如何画出一条直线使两者能够显著地区分开来呢? 答案可以多…

成都污水处理设备厂家怎么选?

在选择成都的污水处理设备厂家时,可以从以下几个方面来进行评估和选择: 1. **公司资质**:首先需要确认厂家是否拥有合法的营业执照、环保设备生产许可证及相关的环保工程资质。 2. **技术实力**:了解厂家是否具备雄厚的技术研发实…

通过自动化部署消除人为操作:不断提高提交部署比率

三十年后,我仍然热爱成为一名软件工程师。事实上,我最近读了威尔拉森(Will Larson)的《员工工程师:超越管理轨道的领导力》,这进一步点燃了我以编程方式解决复杂问题的热情。知道雇主继续照顾员工、原则和杰…

Goingpub国自然基金-免费查询

可进行年份、学部、项目类别等检索,支持生成主题词汇总分析报告。 最最最关键,免费,只需要你注册登录一下,防止被爬虫侵扰。 界面简单,实用,支持模糊搜索,包含最新2023年数据,共56…

Python异常值分析

异常值分析是检验数据是否有录入错误以及含有不合常理的数据。忽视异常值的存在是十分危险的,不加剔除地把异常值包括进数据的计算分析过程中,对结果会产生不良影响;重视异常值的出现,分析其产生的原因,常常成为发现问…

从0开始学人工智能测试节选:Spark -- 结构化数据领域中测试人员的万金油技术(一)

回顾一下模型的生命周期 需要注意的是,在这个流程中,测试至少要参与的以下的活动: 离线的模型测试线上线下一致性测试数据质量测试模型的线上质量监控建模过程的功能/性能等测试 可以看出来测试人员需要做的事情其实不少,整个建模…

Python景区票务人脸识别系统(V2.0),附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

uniapp使用npm命令引入font-awesome图标库最新版本并解决APP和小程序不显示图标的问题

uniapp使用npm命令引入font-awesome图标库最新版本 图标库网址:https://fontawesome.com/search?qtools&or 命令行: 引入 npm i fortawesome/fontawesome-free 查看版本 npm list fortawesome在main.js文件中: import fortawesome/fo…

阿里云服务器可以干嘛?阿里云服务器八大用途介绍

阿里云服务器可以干嘛?能干啥你还不知道么!简单来讲可用来搭建网站、个人博客、企业官网、论坛、电子商务、AI、LLM大语言模型、测试环境等,阿里云百科aliyunbaike.com整理阿里云服务器的用途: 阿里云服务器活动 aliyunbaike.com…

SQL Server语法基础:入门到精通

博客前言 在数据库管理的世界中,SQL Server无疑是一个重要的角色。无论是初学者还是经验丰富的数据库管理员,都需要对SQL Server的查询语法有深入的理解。本文将带领大家深入解析SQL Server的查询语法,并分享一些实用的技巧,帮助…

Redis 之集群模式

一 集群原理 集群,即Redis Cluster,是Redis 3.0开始引入的分布式存储方案。 集群由多个节点(Node)组成,Redis的数据分布在这些节点中。 集群中的节点分为主节点和从节点:只有主节点负责读写请求和集群信息的维护;从…

突破编程_前端_SVG(概述)

1 什么是 SVG SVG,全称可缩放矢量图形(Scalable Vector Graphics),是一种基于 XML(可扩展标记语言)的矢量图像格式。这种图像格式的主要特点是它描述的是矢量图形,而不是基于像素的位图图像。因…

基于 Vue3 + Webpack5 + Element Plus Table 二次构建表格组件

基于 Vue3 Webpack5 Element Plus Table 二次构建表格组件 文章目录 基于 Vue3 Webpack5 Element Plus Table 二次构建表格组件一、组件特点二、安装三、快速启动四、单元格渲染配置说明五、源码下载地址 基于 Vue3 Webpack5 Element Plus Table 二次构建表格组件&#x…