Skip to main content

One post tagged with "前端工程化"

View All Tags

Vite 的简单实现

· 2 min read
zhang13pro
代码狗

实现一个简易的 Vite 打包 .vue 文件

前端工程化辨析#

webpack 的核心原理就是通过分析 JavaScript 中的 require 语句,分析出当前 JavaScript 文件所有的依赖文件,然后递归分析之后,就得到了整个项目的一个依赖图。对图中不同格式的文件执行不同的 loader,比如会把 CSS 文件解析成加载 CSS 标签的 JavaScript 代码,最后基于这个依赖图获取所有的文件。

代码打包处理之后,放在内存中提供给浏览器使用,然后 dev-server 会启动一个测试服务器打开页面,并且在代码文件修改之后可以通过 WebSocket 通知前端自动更新页面,也就是我们熟悉的热更新功能。

针对 webpack 这种打包 bundle 的思路,社区就诞生了 bundless 的框架,比如 Vite。之所以要使用 webpack 是因为浏览器里的 JavaScript 没有很好的方式去引入其他文件。但是这个世界唯一不变的就是变化本身,属于大人的时代终究会变。

且看 ES6 的 module 功能:

<script type="module" src="/src/main.js"></script>

Vite 原理#

Vite 就是借助了 ESModule 的编译时静态分析,不需要打包所有的依赖,大大减少项目的冷启动时间。

import { createApp } from "vue"import App from "./App.vue"import "./index.css"
const app = createApp(App)app.mount("#app")

TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".

剩下来要做的就是

  • 找到 node_modules 下的依赖
  • 加载非 js 文件,如 .css .vue

流程:

  1. 请求 首页http://xxx.xxx.xxx/
  2. 返回 index.html
  3. 请求 /src/main.js
  4. 发现请求 js 文件,替换路径为相对路径后,返回修改后的 js 文件
  5. 请求 @module/vue
  6. 发现请求@module 内的文件,替换文件内为相对路径后,返回 package.json 中 module 定义的入口文件
  7. 请求 ./App.vue
  8. 判断 .vue 的请求后,通过 compilerSFC.parse 解析 Vue 组件,通过返回的 descriptor.script 获取 js 代码
  9. 请求 ./App.vue?type=template
  10. 调用 compilerDom.compile 解析 template 内容,直接返回 render 函数

热更新#

客户端和服务器建立 WebSocket 连接,服务器监听文件变化,通过 WebSocket 去通知浏览器进行相应更新。

小结#

webpack 启动服务器之前需要进行项目的打包,而 Vite 则是可以直接启动服务,通过对浏览器运行时的请求拦截,实现首页文件的按需加载,这样开发服务器启动的时间就和整个项目的复杂度解耦。任何时候我们启动 Vite 的调试服务器,基本都可以在一秒以内响应,这极大地提升了开发者的体验,也是 Vite 的使用率越来越高的原因。

Vite 的主要目的就是提供一个调试服务器。Vite 也可以和 Vue 解耦,实现对任何框架的支持,如果使用 Vite 支持 React,只需要解析 React 中的 JSX 就可以实现。只需要使用框架对应的 Vite 插件就可以支持任意框架。

Vite 能够做到这么快,还有一部分的原因是使用了 esbuild 去解析 JavaScript 文件。esbuild 是一个用 Go 语言实现的 JavaScript 打包器,支持 JavaScript 和 TypeScript 语法,现在前端工程化领域的工具也越来越多地使用 Go 和 Rust 等更高效的语言书写,这也是性能优化的一个方向。

如果一个模块文件是分散的,导致 Vite 首页一下子要加载 1000 个 JavaScript 文件的情况通常需要进行依赖预构建