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 语法,并尽可能的粗略编译,只做最小化处理(实际上只做语法编译和依赖导入的重写),所以在具有缓存的情况下,预编译是非常快的。
在第一次页面加载时,仅需要加载和解析实际需要的代码。之后的页面导航都会只加载需要的代码,并且因为服务器在内存中保留有编译代码,所以这个过程是非常快的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jieyucx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值