深入理解Vite核心原理

Vite的底层原理是什么

前置知识

ESM

在了解Vite之前,需要先了解下ESM:

ESM是JavaScript提出的官方标准化模块系统,不同于之前的CJS,AMD,CMD等等,ESM提供了更原生以及更动态的模块加载方案,最重要的就是它是浏览器原生支持的,也就是说我们可以直接在浏览器中去执行import,动态引入我们需要的模块,而不是把所有模块打包在一起。

目前ESM模块化已经支持92%以上的浏览器,而且且作为 ECMA 标准,未来会有更多浏览器支持ECMA规范

深入理解Vite核心原理

当我们在使用模块开发时,其实就是在构建一张模块依赖关系图,当模块加载时,就会从入口文件开始,最终生成完整的模块实例图。

ESM的执行可以分为三个步骤:

  • 构建: 确定从哪里下载该模块文件、下载并将所有的文件解析为模块记录
  • 实例化: 将模块记录转换为一个模块实例,为所有的模块分配内存空间,依照导出、导入语句把模块指向对应的内存地址。
  • 运行:运行代码,将内存空间填充

从上面实例化的过程可以看出,ESM使用实时绑定的模式,导出和导入的模块都指向相同的内存地址,也就是值引用。而CJS采用的是值拷贝,即所有导出值都是拷贝值。

Esbuild

Vite底层使用Esbuild实现对.ts、.jsx、.js代码文件的转化,所以先看下什么是es-build:

Esbuild是一个JavaScript Bundler 打包和压缩工具,它提供了与Webpack、Rollup等工具相似的资源打包能力。可以将JavaScript和TypeScript代码打包分发在网页上运行。但其打包速度却是其他工具的10~100倍。

目前他支持以下的功能:

  • 加载器
  • 压缩
  • 打包
  • Tree shaking
  • Source map生成

esbuild总共提供了四个函数:transform、build、buildSync、Service。有兴趣的可以移步官方文档了解。

Rollup

在生产环境下,Vite使用Rollup来进行打包:

Rollup是基于ESM的JavaScript打包工具。相比于其他打包工具如Webpack,他总是能打出更小、更快的包。因为 Rollup 基于 ESM 模块,比 Webpack 和 Browserify 使用的 CommonJS模块机制更高效。Rollup的亮点在于同一个地方,一次性加载。能针对源码进行 Tree Shaking(去除那些已被定义但没被使用的代码),以及 Scope Hoisting 以减小输出文件大小提升运行性能。

Rollup分为build(构建)阶段和output generate(输出生成)阶段。主要过程如下:

  • 获取入口文件的内容,包装成module,生成抽象语法树
  • 对入口文件抽象语法树进行依赖解析
  • 生成最终代码
  • 写入目标文件

如果你的项目(特别是类库)只有JavaScript,而没有其他的静态资源文件,使用Webpack就有点大才小用了。因为Webpack 打包的文件的体积略大,运行略慢,可读性略低。这时候Rollup也不失为一个好选择。

这里想对Rollp进行更深入的学习可以看看官网的介绍。

核心原理

详细阐述下:

  1. 当声明一个 script标签类型为 module 时,如
<script type="module" src="/src/main.js"></script>
  1. 当浏览器解析资源时,会往当前域名发起一个GET请求main.js文件
// main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
  1. 请求到了main.js文件,会检测到内部含有import引入的包,又会import 引用发起HTTP请求获取模块的内容文件,如App.vue、vue文件

Vite其核心原理是利用浏览器现在已经支持ES6的import,碰见import就会发送一个HTTP请求去加载文件,Vite启动一个 koa 服务器拦截这些请求,并在后端进行相应的处理将项目中使用的文件通过简单的分解与整合,然后再以ESM格式返回返回给浏览器。Vite整个过程中没有对文件进行打包编译,做到了真正的按需加载,所以其运行速度比原始的webpack开发编译速度快出许多。

基于ESM的Dev server

在Vite出来之前,传统的打包工具如Webpack是先解析依赖、打包构建再启动开发服务器,Dev Server 必须等待所有模块构建完成,当我们修改了 bundle模块中的一个子模块, 整个 bundle 文件都会重新打包然后输出。项目应用越大,启动时间越长。

深入理解Vite核心原理

而Vite利用浏览器对ESM的支持,当 import 模块时,浏览器就会下载被导入的模块。先启动开发服务器,当代码执行到模块加载时再请求对应模块的文件,本质上实现了动态加载。灰色部分是暂时没有用到的路由,所有这部分不会参与构建过程。随着项目里的应用越来越多,增加route,也不会影响其构建速度。

深入理解Vite核心原理

基于ESM 的 HMR 热更新

目前所有的打包工具实现热更新的思路都大同小异:主要是通过WebSocket创建浏览器和服务器的通信监听文件的改变,当文件被修改时,服务端发送消息通知客户端修改相应的代码,客户端对应不同的文件进行不同的操作的更新。

核心流程

Vite整个热更新过程可以分成四步

  1. 创建一个websocket服务端和client文件,启动服务
  2. 通过chokidar监听文件变更
  3. 当代码变更后,服务端进行判断并推送到客户端
  4. 客户端根据推送的信息执行不同操作的更新

整体流程图:

深入理解Vite核心原理

你觉得Vite相比于Webpack哪些方面更好

Vite和Webpack都是前端构建工具,它们在一些方面有相似之处,但也有一些显著的区别。以下是Vite相对于Webpack的一些优势:

  1. 快速的冷启动(Fast Cold Start):
  • Vite的冷启动速度非常快。由于采用按需构建和原生ES模块的特性,Vite在启动时只需构建必要的模块,而不是整体构建整个项目。这降低了开发者等待构建的时间,提高了开发效率。
  1. 快速的热模块替换(HMR):
  • Vite通过热模块替换实现了快速的页面刷新。在开发过程中,当代码发生变化时,只有受到影响的模块会被替换,而不是整个页面刷新。这使得开发者能够在保持应用状态的同时快速看到代码变更的效果。
  1. 原生ES模块支持:
  • Vite天生支持原生ES模块,这使得开发者可以直接在浏览器中运行未经过打包的模块化代码,而不需要额外的转译和打包步骤。这对于开发体验和调试非常有益。
  1. 按需加载:
  • Vite通过按需构建和服务端渲染(SSR)的方式,只生成和提供实际需要的代码,而不是预先打包整个应用。这降低了构建和加载的成本,尤其对于大型项目而言效果更为显著。
  1. 易配置和零配置:
  • Vite在项目创建时提供零配置的选项,使得初始设置非常简单。同时,Vite的配置也非常灵活,开发者可以根据需要进行更高级的配置。


原文始发于微信公众号(前端大大大):深入理解Vite核心原理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/174071.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!