Vue作者尤雨溪在今年4月提出了一个由Vue3搭载的前端开发工具Vite。Vite主要提供了前端开发服务器的功能以及生产环境打包的功能,而其主要突破则是在前端开发服务器这一方面,提供了一种基于ES Module的快速的本地开发服务器。
在本文编辑时,Vite版本仍处于1.0.0-rc.9,尚未正式发布,并且Vite目前主要支持Vue3项目,尚不识别Vue2语法。下面是引用尤雨溪在微博上对Vite的介绍。
Vite,一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。同时不仅有 Vue 文件支持,还搞定了热更新,而且热更新的速度不会随着模块增多而变慢。针对生产环境则可以把同一份代码用 rollup 打。虽然现在还比较粗糙,但这个方向我觉得是有潜力的,做得好可以彻底解决改一行代码等半天热更新的问题。
使用下面的命令即可快速搭建一个使用Vite作为开发服务器的项目,使用十分方便,类似于Vue-cli。
$ npm init vite-app <project-name> $ cd <project-name> $ npm install $ npm run dev
第一行命令的目的就是从npm仓库拉取 create-vite-app
这个包,然后全局安装,最后使用它创建基于Vite的模板项目。
官方文档介绍,Vite主要有下面三个特性
create-vite-app
和 Vue-cli
创建的项目,来看一下Vite快在哪里,下图分别是使用Vite和 Vue-cli(webpack)
启动本地开发服务器的过程。可以看出Vite相对于Vue-cli(webpack)在本地服务器启动时省略了打包步骤,因而做到了冷启动秒开的效果,并且这个速度提升会随着项目模块增多而愈加明显。下面我们就看一下Vite是如何实现其快速的特性。
Vite 是基于浏览器原生 ES imports 的开发服务器。因而我们首先需要了解浏览器是如何支持ES Module的
首先,我们来看一下在浏览器如何使用ES Module。打开浏览器调试面板, 清空network,使用下面代码在页面动态插入一段 <script>
代码
const script = document.createElement('script')script.setAttribute('type', 'module');script.innerHTML = 'import {test} from "./test.js"'document.body.append(script)
在运行上述代码后,浏览器向当前服务器目录发送了 http://km.oa.com/test.js
的请求。我们都知道本地项目中我们使用ES import会从文件系统读取相应路径的模块,浏览器则是将模块路径转换为Url。
浏览器解析ES module的过程如上图所示。
type="module"
的 <script>标签
import
语法,生成请求url,向服务器请求该地址的模块可以说浏览器对于ES Module的支持实现了真正的按需加载,省略了前端打包的过程,对于减少首屏加载时间是有极大帮助的。但是我们要在生产环境中使用它必须知道浏览器的支持度到底如何。
下面是一张caniuse中说明的浏览器对于 ES Module的静态import语法的支持情况。可以看出除了IE外的主流浏览器基本上都支持了 ES Module的import语法。
那么,对于不支持ES Module的浏览器,难道我们就让项目跑不起来吗?
当然不是,在 script 标签中使用 nomodule 属性,可以确保向后兼容。
像上图一样提供ES Module方式和非ES Module方式的代码,对于支持ES Module的浏览器,其会忽视 nomodule
类型的script,而对于无法识别 Es Module的浏览器则会直接使用 nomodule
的script代码。因此我们只需提供一份打包好的代码,放在 nomodule
标签内就可以实现向后兼容
值得注意的是,浏览器只能解析以’/’, ‘./’, 或 '…/'开头的模块路径,对于像引用nodemodules中的模块,比如像下面引用Vue的方式,浏览器无法识别,会报错。因此对于nodemodules的引用,需要另外处理,而Vite也给出了解决方案。
import Vue from 'vue'
我们启动Vite本地开发服务器,用浏览器打开入口页面,观察浏览器的NetWork面板.如下图所示,
main.js
,main.js
中包含ES Module, 解析 import
语法,发现有三个 import
import
,发出所依赖的模块的Http请求对比源码和网络请求,我们会发现网络请求数明显要多于源码中 import
的个数。多出的网络请求主要是两类
.vue
文件相关 对于一个Vue组件SFC(Single File Components),其主要包含三类代码,模板、script、样式。由于浏览器是无法识别vue文件的,一个vue文件会被拆分为三个请求 .vue
, .vue?type=template
, .vue?type=style
,这些都需要借助Vite的本地服务器实现,具体实现方法下文会详细阐述。clent.js
,还有websocket请求,这些都是为热更新服务的,而在代码中插入建立websocket连接需要的 clent.js
逻辑也是由Vite开发服务器实现的。对于浏览器不识别的node_module引用如何处理?对于 .vue
文件如何处理都是由Vite开发服务器实现的。首先我们看一下Vite开发服务器架构图
Vite开发服务器是基于Koa框架的,利用Koa中间件实现模块解析以及热更新的主要功能。这一节我们主要看一下Vite是如何处理模块的。
nodemodules 模块处理过程 对nodemodules的处理主要由中间件
serverPluginModuleRewrite
完成,其主要过程如下
vue文件处理过程 对vue组件的处理由
serverPluginVue
来实现,其处理流程如下
js
template
内容的渲染函数,返回类型为 js
style
标签内样式的动态插入函数如上图所示,Vite热更新也是基于Websocket。在Vite服务器启动时,Vite利用中间件 serverPluginHtml
在html中插入 client.js
. 这个js文件主要用于在建立浏览器和Vite服务器之间的Websocket通信。热更新的步骤如下
clientjs监听的更新消息类型
Vite 提供了一个更快的开发环境服务器, 其实现原理基于ES模块,通过开发环境去打包将构建时间从 O(n) 减少到 O(1), 其搭载Vue3发布,借助Vue生态,在未来有更广泛的使用场景。