什么是vite
vite 是一个基于 Vue3单文件组件的非打包开发服务器,它做到了本地快速开发启动, 实现按需编译,不再等待整个应用编译完成。
法语Vite(轻量,轻快)
面向现代浏览器,基于原生模块系统 ESModule 实现。webpack的开发环境很慢(开发时需要进行编译放到内存中)
实现原理
vite高度依赖module script特性
过程如下:
- 执行package.json的bin字段对应的js
- createServer
- 初始化koa、watcher、resolver
- 在 koa 中间件里获取请求 body
- 通过koa middlewares的方式使用一堆plugins
- 对js文件进行拦截,包括*.vue文件中的
<template>和<script> - 通过 es-module-lexer 解析资源 ast 拿到 import 的内容
- 判断 import 的资源是否是 npm 模块
- 返回处理后的资源路径:"vue" => "/@modules/vue"
- 预优化用户项目里dependencies依赖的模块文件
将处理的template,script,style等所需的依赖以http请求的形式,通过query参数形式区分并加载SFC文件各个模块内容。
对比vue-cli
传统打包工具的dev-server
本地运行时需要加载所有模块文件并导出bundle才能展示,并且应用越来,打包启动速度也越慢,而且代码分割是对于生成环境。
基于浏览器ES module的dev-server
使用<script type="module">,浏览器可以解析ES module 的import 并发送http 请求,dev server拦截浏览器对模块的请求处理后返回
什么是ES module
MDN解释说如果标示了module的话会把代码当作js模块来执行,一篇关于es6的文章也很好的介绍了:
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/script
当浏览器解析保留了模块关键字的代码,从而会导致HTTP请求,vite通过koa拦截了这些请求:
.vue => 拦截请求 => 编译 => 返回给客户端
为什么ESbuild这么快?
- 因为Esbuild是用GO语言直接编译成原生代码
- 由于GO语言特点,它的解析和映射并发非常快
- 避免了不必要的配置
- 数据转换很简单很快速
虽然ESbuild是一个非常快速的打包器,但是不支持热模块更新和没有开箱即用的工具,而且要像webpack一样想做一款基于ESbuild的插件.evan you自我实现了HRM 热更新。
HMR
请求得到对应的客户端代码,在客户端中创建了一个websocket服务并与服务端建立了连接,通过chokidar这个库创建watcher实例,监听文件变化,不同的消息触发一些事件做到浏览器端的即时热模块更换
目录结构
├── client # 客户端运行代码,主要是客户端的 socket 通信以及 HMR 相关
│ ├── client.ts
│ ├── env.d.ts
│ ├── tsconfig.json
│ └── vueJsxCompat.ts
├── hmrPayload.ts # HMR 类型定义
└── node # 服务端运行代码
├── build # vite build 命令运行代码
│ ├── buildPluginAsset.ts
│ ├── buildPluginCss.ts
│ ├── buildPluginEsbuild.ts
│ ├── buildPluginHtml.ts
│ ├── buildPluginManifest.ts
│ ├── buildPluginReplace.ts
│ ├── buildPluginResolve.ts
│ ├── buildPluginWasm.ts
│ └── index.ts
├── cli.ts
├── config.ts
├── esbuildService.ts # esbuild 相关代码
├── index.ts
├── optimizer # 预优化
│ ├── entryAnalysisPlugin.ts
│ ├── index.ts
│ └── pluginAssets.ts
├── resolver.ts # 模块加载逻辑
├── server # koa服务使用的一些中间件
│ ├── index.ts
│ ├── serverPluginAssets.ts
│ ├── serverPluginClient.ts
│ ├── serverPluginCss.ts # 处理css和其他css预处理器文件
│ ├── serverPluginEnv.ts
│ ├── serverPluginEsbuild.ts
│ ├── serverPluginHmr.ts # 服务端热模块替换相关
│ ├── serverPluginHtml.ts
│ ├── serverPluginJson.ts
│ ├── serverPluginModuleResolve.ts # 处理 /@modules/:id 开头请求的文件
│ ├── serverPluginModuleRewrite.ts
│ ├── serverPluginProxy.ts
│ ├── serverPluginServeStatic.ts # koa静态服务器
│ ├── serverPluginSourceMap.ts
│ ├── serverPluginVue.ts # 处理.vue文件
│ ├── serverPluginWasm.ts
│ └── serverPluginWebWorker.ts
├── transform.ts
├── tsconfig.json
└── utils
├── babelParse.ts
├── createCertificate.ts
├── cssUtils.ts
├── fsUtils.ts
├── index.ts
├── openBrowser.ts
├── pathUtils.ts
├── resolveVue.ts
├── shims.d.ts
└── transformUtils.ts
总结
vite在浏览器端使用 export import 的方式导入和导出模块,同时实现了按需加载。vite高度依赖module script特性。
vite 大致的原理过程是这样,其中细节 比如 .vue文件怎么处理、解析node_modules、koa拦截等涉及到源码,可以去vite源码一路顺下去。