vite性能优化提升开发体验之hmr和预编译

一、vite中的预编译

1. 预编译概念介绍

Vite,一个由Vue.js开发者尤雨溪开发的新型前端构建工具,主要利用了现代浏览器支持的ESM(ES模块)来进行快速开发。Vite在法语中意为“快”,其中最大的亮点就是其开发服务器启动的速度,能够在几乎看不到的时间内完成启动,这主要得益于两大关键性的技术:模块热更新HMR)和预编译Pre-Bundling)。

预编译,也就是预构建(Pre-Bundling)。在传统的打包过程中(比如使用Webpack),所有的模块都会被构建到一个文件中去,这个过程就是所谓的“打包Bundling)”。在Vite中,引入了“预编译”的这么一个概念,Vite会在服务器启动时对所有的依赖进行一次性的编译,并将其缓存起来。在后续的模块导入的时候,就不需要再对这些模块进行编译,提高了加载效率。

node_modules/.vite中的文件就是vite预编译文件
在这里插入图片描述

Vite的预编译主要针对那些大型的、复杂的第三方库,对把它们转换成可以直接在浏览器运行的ES模块。这样做主要有以下优化效果:

  1. 加快了开发过程中的加载速度。因为在开发模式下,运行Vite的应用,会请求大量的小模块,但是对于一些大型的库(比如Vue、React等),如果按照模块化的方式加载明显不合理,会造成请求过多。通过预编译,Vite将这些库提前编译到一个文件里,从而减少请求的开销。
  2. 加快了构建速度。因为预编译阶段已经预先处理了依赖的模块,所以在最终打包构建的时候,只需要处理自身的源代码逻辑,无需再额外处理依赖模块,以此提高构建速度。
  3. 改善了兼容性问题。由于很多第三方模块可能包含一些现在浏览器所不支持的代码,比如JSX,通过预编译,Vite将这些代码转换成浏览器可以直接运行的ES模块,解决了兼容性问题。
  4. 更好地实现了按需加载和代码拆分。预编译将大库拆分成多个小模块,可以按需加载,无需加载整个库,从而优化了性能。

举例来说,假设一个前端项目用到了vue、vant、axios等多个库,在没有使用预编译的情况下,每次启动项目时都需要去加载和解析这些库,耗时较长。而使用了Vite的预编译功能后,这些库可以在项目启动前就已经编译完成,后续只需要引用即可,大大提高了前端项目的启动速度和运行效率。

2. 配置预编译选项

在 Vite 项目中,我们在 vite.config.js 文件中配置 optimizeDeps 选项来实现对第三方库预编译的控制。optimizeDeps 选项允许手动设置需要预构建的依赖。exclude 属性用于排除某些不需要预编译的依赖,include 属性用于添加需要预编译的依赖。

以下是一个基本的配置示例:

// vite.config.js
module.exports = {optimizeDeps: {include: ['lodash'],   // 将 lodash 加入预编译exclude: ['moment']   // 将 moment 移除预编译}
}

在上面的示例中,lodash 将会被预编译,而 moment 将不会被预编译。

注意:开发依赖和已知不需要编译的依赖会自动被 Vite 排除掉。如果遇到有问题的依赖预编译,可以使用 exclude 来手动排除。而对于 Vite 默认没有预编译,但你需要其预编译的依赖,可以使用 include 来手动添加。

3. vite和webpack目前在预编译阶段的对比

功能/框架ViteWebpack
预编译Vite 使用 esbuild 进行预编译,因为 esbuild 是用 Go 语言写的,所以预编译的速度比 webpack 快很多。但是 esbuild 的兼容性和插件系统不如 webpack 完善Webpack 使用 babel 作为默认的预处理工具,与 esbuild 相比较,速度慢很多。但是 webpack 的社区更加活跃,有很多插件可以使用,并且兼容性更好。
Tree SharkingVite使用ES模块导入进行tree shaking,可以直接消除无用代码,效率更高。更好的支持动态导入(import())和CSS导入。Webpack的tree shaking需要在生产模式下才能执行,而且不支持动态导入和CSS导入的tree shaking,可能会保留无用代码。
缓存机制Vite在开发模式下没有使用缓存,但在生产模式下使用Rollup打包时,会进行缓存以优化构建速度。Vite的缓存机制更侧重于模块的热更新,并且,支持服务器端的模块缓存。Webpack使用硬盘缓存,初次构建慢,但是再次构建会从缓存中加载模块,从而提高构建速度。但在大型项目中,如果不合理配置,缓存可能会导致内存飙升。
优点构建速度快,开发体验好,方便快捷。支持Vue 3.0、Hot Module Replacement(HMR)等新特性。提供了丰富的配置和插件系统,适合大型项目。
劣势对于大型项目,可能会出现一些隐藏的问题和兼容性问题。配置复杂,学习曲线陡峭。初次构建速度慢。

二、热模块替换hmr

1. 什么是hmr

热模块替换Hot Module Replacement,HMR)是一种机制,它使得应用在运行时能够更新各种模块,而无需进行完全刷新。例如,某些库可以针对这个API进行优化,以达到接近无刷新更改的效果。这项技术主要针对单页面应用(SPA)。

举例说明,如果我们在编写一个网页应用,并且同时运行着一个开发服务器,那么当我们修改了代码并保存后,整个页面会自动刷新以显示出新的结果。而如果使用了HMR,就无需刷新整个页面,我们改动的部分(模块)会被自动替换掉并立即显示出新的效果

应用HMR之后的好处有:

  1. 保持应用状态:传统的整页刷新会导致当前应用的状态被丢失,而HMR能够在无需刷新整个页面的情况下替换、添加或删除模块,从而能够保持应用的状态。
  2. 只更新更改的部分:当修改一个或多个代码模块,整个应用不需要全部更新,只更新被改动的模块。
  3. 开发速度:由于只替换更改的内容,所以测试新的变更变得更快。
  4. 样式调整快:如果应用的修改仅仅是 CSS/SCSS 样式,那么 HMR 就会变得非常有用。这是因为,当你调整样式的时候,无需刷新页面,调整立马生效,这对于样式调整而言是非常有利的。

注意,HMR 主要在开发环境,生产环境通常不需要开启。

2. vite中hmr的相关配置

Vite构建的项目中,默认情况下是启用了热模块替换(HMR)的。如果你需要修改HMR相关的配置,你可以在Vite的配置文件(vite.config.js)中,对server.hmr进行设置。

例如,如果你需要禁用HMR,可以在vite.config.js中这样配置:

export default {server: {hmr: false}
}

如果需要设置连接超时或者跳过检查脏模块,可以如下配置:

export default {server: {hmr: {timeout: 30000,overlay: false}}
}

ViteHMR能力非常强大,它不仅可以处理JavaScript模块的热替换,还能处理CSS、HTML等其他类型的模块。只要你的代码里含有HMR相关的接口,Vite就能自动完成热替换。

在大部分情况下,你并不需要手动设置HMR,Vite默认的设置已经可以满足绝大多数应用场景。如果你需要设置HMR,通常是遇到了一些特殊的情况,比如需要修改连接超时时间、需要禁用HMR等。

3. vite中hmr的执行过程

热模块替换(Hot Module Replacement,HMR)是Vite(以及其他现代前端构建工具,如Webpack)的一个重要特性,但Vite的实现方式相对更优。

在对JavaScript、Vue、React等进行HMR时,Vite会有些不同的处理方式,总的来说,有以下几个步骤:

  1. 文件改变后,Vite的开发服务器首先会通知在客户端运行的更新代码,文件已经被更新。

  2. 在客户端,Vite有一个运行时处理器,它会找到这个文件对应的模块。

  3. 查看这个模块的其他依赖或者倚赖(即这个模块被哪些模块引用),建立依赖关系图。

  4. 如果这个模块可以被更新(即符合HMR规则)则直接更新,如果不能则会通知引用它的父模块更新。

  5. 这个过程是递归的,直至找到可以进行HMR的模块,或者已经到达了应用的顶级模块,此时则会进行全量刷新。

相比WebpackVite不需要额外的代码进行热更新,因为Vite是基于ES6模块的,可以依靠浏览器原生的import语法去请求和缓存模块,使得HMR更加高效。而Webpack是基于CommonJS的,需要通过上下文去理解模块的引用关系,实现热更新则需要额外的编译输出和运行时支持。

此外,Vite对于CSS的处理也具有优势,当CSS文件更新时,Vite直接通过inject的方式在客户端更新样式,而不会影响正在运行的JavaScript代码。

4. vite和webpack中的hmr对比

项目Vite 中的 HMRWebpack 中的 HMR
定义Vite 中,HMR 是通过 ESM 在浏览器中的原生支持,无需进行额外的浏览器以下代码处理,并且具有极快的速度。Webpack 中,HMR 是一种模块热替换的功能,可以在应用程序运行过程中替换、添加、删除模块,无需进行整个页面的刷新。
速度速度比较快,因为它只需要更新修改过的部分,而不是整个应用。相对较慢,因为当文件修改时,Webpack 会重新构建并刷新整个页面。
热更新范围由于 Vite 利用原生 ESM 进行模块热更新,所以其影响范围较小,只对被修改的模块进行更新。若一个模块的值发生了改变,改变会冒泡,使得依赖这个模块的所有模块全部更新,更新范围相当大。
原理利用了 ES6 module 的系统,当文件改变时,直接只请求改变的文件并重新执行。默认会给每个模块添加热更新代码,当文件发生变化后,通过打包工具发出的文件更改信号,触发更新函数,让客户端重新加载文件。
配置复杂度Vite 的配置相对较简单,只需要简单的几步就能启用 HMR。Webpack 的配置要复杂一些,除了需要添加 HMR 插件,还需要对其进行详细的配置。
兼容性Vite 要求 Node.js 版本 12.0.0 以上,并且只支持现代浏览器,不支持 IE。Webpack 对于旧版本的浏览器兼容性更好。

三、总结

对于hmr,在Vite中,当改动一个文件时,Vite会立即使用WebSocket向浏览器推送更新,然后浏览器通过重新获取被改动的模块,替换原有的代码,从而实现了部分更新,而不必要进行页面的整体刷新。这大大提高了开发时的用户体验。

Vite中的预编译: 在传统的 SPA 打包器中,无论 JavaScript 文件的大小,文件需要被完全解析并转换为浏览器可运行的代码,这个过程可能会比较耗时。而Vite则采取了另一个策略,即预编译。
Vite 开发服务器在启动时,会预编译所有被 import 的依赖。预编译将ES6+ 语法或 TypeScript 编译为可以在浏览器中运行的 ESnext 语法,并尽可能的粗略编译,只做最小化处理(实际上只做语法编译和依赖导入的重写),所以在具有缓存的情况下,预编译是非常快的。
在第一次页面加载时,仅需要加载和解析实际需要的代码。之后的页面导航都会只加载需要的代码,并且因为服务器在内存中保留有编译代码,所以这个过程是非常快的。

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

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

相关文章

使用qemu创建ubuntu-base文件系统,并安装PM相关内核模块

目录 一、配置镜像二、使用qemu模拟nvdimm(安装PM相关内核模块)运行记录 遇到的一些问题1、ext4文件系统损坏问题:系统启动时,遇到ext4的报错信息解决办法:2、内核模块未成功加载3、qemu报错4、主机终端无法正常打开 流…

flask实现get和post请求

1、实现get请求 在项目根目录创建app.py 代码如下: from flask import Flask,render_template,requestapp Flask(__name__)app.route("/regist/user/", methods[GET]) def regist():return render_template("regist.html") #默认去templat…

【基本绘图注释函数】——MatLab画图

目录索引 title:ylable:legend: title: 在绘图中添加标签。此类函数的输入是一个字符串。MATLAB 中的字符串是用双引号 (") 引起来的。 上面一部分画图代码这里省略 title("Sample Mass")ylable: 为y轴…

03插值与拟合

9.已知飞机下轮廓线上数据如下,分别用分段线性插值和三次样条插值求x每改变0.1时的y值。 x035791112131415y01.21.72.02.12.01.81.21.01.6 %9.已知飞机下轮廓线上数据如下,分别用分段线性插值和三次样条插值求每改变0.1时的y值。x [0 3 5 7 9 11 12 1…

Dreamweaver批量替换所有超链接替换成#

需求:想要将页面所有链接地址替换为#。 方法一 CTRLF打开“查找和替换”,勾选“使用正则表达式” 查找 href"([\s\S]*?)" 替换为 href"#" 副作用:样式表链接地址也会被替换为#,需提前备份。 方法二 也可以查…

【Hello mysql】 mysql的索引

Mysql专栏:Mysql 本篇博客简介:介绍mysql的索引 mysql索引 索引索引是什么索引的分类索引作用查看 磁盘mysql的工作过程认识磁盘定位扇区磁盘随机访问(Random Access)与连续访问(Sequential Access)mysql和磁盘交互的基本单位 索引的理解建立测试表为何I…

dede tag不以关键词作为url以数字作为url方法修改

dede tag不以关键词作为url以数字作为url方法修改 打开/include/taglib/tag.lib.php 查找以下代码: $row[link] $cfg_cmsurl."/tags.php?/".urlencode($row[keyword])."/"; 替换为: $row[link] $cfg_cmsurl."/tags.php?/&q…

考核:QTableWidget开发[折叠/展开单元格QTableWidgetItem]

目录 效果要求一、功能概述二、功能三、关系FATable 表NTable 表CTable 表 实现infos.hmain.cppcomplextablewidget.hcomplextablewidget.cppschemedialog.hschemedialog.cpp 源码模糊知识点 效果 要求 一、功能概述 二、功能 三、关系 FATable 表 CREATE TABLE fatable (idF…

插入排序和希尔排序:用C语言打造高效的排序算法

插入排序 插入排序的思路就像是你在整理一堆扑克牌。你先拿起第一张牌,然后拿起第二张牌,把它插入到合适的位置,使得你手上的两张牌是有序的。接着,你再拿起第三张牌,也把它插入到合适的位置,使得你手上的…

error: ‘CV_LOAD_IMAGE_UNCHANGED’ was not declared in this scope

1-错误 2-错误原因 opencv4.x以上,有些宏,API名字改了,需要改为新的 3-解决方案 CV_LOAD_IMAGE_UNCHANGED 改为 cv::IMREAD_UNCHANGEDCV_LOAD_IMAGE_GRAYSCALE 改为 cv::IMREAD_GRAYSCALECV_LOAD_IMAGE_COLOR 改为 cv::IMREAD_COLORCV_LO…

Java反射机制概述

Java反射的概述 Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 加载完类之后,在堆内存的方法区中就产生了一…

含多类型充电桩的电动汽车充电站优化配置方法(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

rapid_latex_ocr: 更快更好用的公式图像转latex工具

Rapid Latex OCR rapid_latex_ocr是一个将公式图像转为latex格式的工具。仓库中的推理代码来自修改自LaTeX-OCR,模型已经全部转为ONNX格式,并对推理代码做了精简,推理速度更快,更容易部署。仓库只有基于ONNXRuntime或者OpenVINO推…

阿里瓴羊One推出背后,零售企业迎数字化新解

配图来自Canva可画 近年来随着数字经济的高速发展,各式各样的SaaS应用服务更是层出不穷,但本质上SaaS大多局限于单一业务流层面,对用户核心关切的增长问题等则没有提供更好的解法。在SaaS赛道日渐拥挤、企业增长焦虑愈演愈烈之下&#xff0c…

前端uni-app自定义精美全端复制文本插件,支持全端文本复制插件 可设置复制按钮颜色

随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。 通过组件化开发,可以有效实现…

调频连续波(FMCW)波形设计、真实道路场景仿真及汽车自适应巡航控制信号处理(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 💥1 概述 以下是关于调频连续波(FMCW)波形设计、真实道路场景仿真以及汽车自适应巡航控制信号处理的概述&#x…

mycat设置sql隔离级别的问题

问题 General log中出现大量SQL “SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ”。 该语句会引起两个问题, 1: "REPEATABLE READ"不是我们预期的事物隔离级别。 2: 大量无效的SQL影响性能。 注: MySql的可重复读会带来怎样…

第三方api对接怎么做?淘宝1688api接口怎么对接?

在今天的互联网上,第三方API对接是必不可少的。这种技术将不同的应用程序/服务连接在一起,创造了无限的可能性。 第三方api对接怎么做? 1、与支付公司签约 首先,通过正规的渠道,如支付公司官网或正规服务商&#xf…

归并排序—C语言实现

前言 🥰在学数据结构的第一节课就知道了数据结构课程是要管理并且学会操作数据,当然操作数据首先想到的就是数据的排序,排过顺序的数据的使用价值才够大。前面我们学习了顺序表也学习了链表等等,这些就是储存数据的方法&#xff0…

Pytorch基本使用—参数初始化

深度学习模型参数初始化是指在训练深度神经网络时,对网络的权重和偏置进行初始化的过程。合适的参数初始化可以加速模型的收敛,并提高模型的性能。 ✨ 1 基本介绍 在深度学习中,常用的参数初始化方法有以下几种: 零初始化&#…