下一代前端构建工具Vite

1、背景

Vue做者尤雨溪在今年4月提出了一个由Vue3搭载的前端开发工具Vite。Vite主要提供了前端开发服务器的功能以及生产环境打包的功能,而其主要突破则是在前端开发服务器这一方面,提供了一种基于ES Module的快速的本地开发服务器。html

2、Vite简介

2.1 什么是Vite

在本文编辑时,Vite版本仍处于1.0.0-rc.9,还没有正式发布,而且Vite目前主要支持Vue3项目,尚不识别Vue2语法。下面是引用尤雨溪在微博上对Vite的介绍。前端

Vite,一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,彻底跳过了打包这个概念,服务器随起随用。同时不只有 Vue 文件支持,还搞定了热更新,并且热更新的速度不会随着模块增多而变慢。针对生产环境则能够把同一份代码用 rollup 打。虽然如今还比较粗糙,但这个方向我以为是有潜力的,作得好能够完全解决改一行代码等半天热更新的问题。vue

2.1 如何使用Vite

使用下面的命令便可快速搭建一个使用Vite做为开发服务器的项目,使用十分方便,相似于Vue-cli。node

npm init vite-app <project-name> 
cd <project-name> 
npm install 
npm run dev
复制代码

第一行命令的目的就是从npm仓库拉取 create-vite-app这个包,而后全局安装,最后使用它建立基于Vite的模板项目。webpack

3、Vite特性

官方文档介绍,Vite主要有下面三个特性web

  1. 快速的冷启动
  2. 及时的热模块更新
  3. 真正的按需加载 咱们对比 create-vite-appVue-cli建立的项目,来看一下Vite快在哪里,下图分别是使用Vite和 Vue-cli(webpack)启动本地开发服务器的过程。

图片

图片

能够看出Vite相对于Vue-cli(webpack)在本地服务器启动时省略了打包步骤,于是作到了冷启动秒开的效果,而且这个速度提高会随着项目模块增多而越发明显。下面咱们就看一下Vite是如何实现其快速的特性。npm

4、Vite原理

Vite 是基于浏览器原生 ES imports 的开发服务器。于是咱们首先须要了解浏览器是如何支持ES Module的浏览器

4.1 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的过程如上图所示。

  1. 识别带有熟悉 type="module"<script>标签
  2. 获取并解析该标签内的js内容。
  3. 识别 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'
复制代码

4.2 Vite开发服务器如何使用ES Module

咱们启动Vite本地开发服务器,用浏览器打开入口页面,观察浏览器的NetWork面板.以下图所示,

  1. 浏览器加载了入口html,解析发现 main.js
  2. 发现 main.js中包含ES Module, 解析 import语法,发现有三个 import
  3. 根据 import,发出所依赖的模块的Http请求
  4. 依次类推,边解析边请求。

图片

图片

对比源码和网络请求,咱们会发现网络请求数明显要多于源码中 import的个数。多出的网络请求主要是两类

  1. .vue文件相关 对于一个Vue组件SFC(Single File Components),其主要包含三类代码,模板、script、样式。因为浏览器是没法识别vue文件的,一个vue文件会被拆分为三个请求 .vue, .vue?type=template, .vue?type=style,这些都须要借助Vite的本地服务器实现,具体实现方法下文会详细阐述。
  2. 热更新相关 咱们看到请求中有个 clent.js,还有websocket请求,这些都是为热更新服务的,而在代码中插入创建websocket链接须要的 clent.js逻辑也是由Vite开发服务器实现的。

4.3 Vite 开发服务器模块处理

对于浏览器不识别的node_module引用如何处理?对于 .vue文件如何处理都是由Vite开发服务器实现的。首先咱们看一下Vite开发服务器架构图

图片

Vite开发服务器是基于Koa框架的,利用Koa中间件实现模块解析以及热更新的主要功能。这一节咱们主要看一下Vite是如何处理模块的。

nodemodules 模块处理过程 对nodemodules的处理主要由中间件 serverPluginModuleRewrite完成,其主要过程以下

  1. 在 koa 中间件里获取请求 body
  2. 经过 es-module-lexer 解析资源 ast 拿到 import 的内容
  3. 判断 import 的资源是不是绝对路径,绝对视为 npm 模块
  4. 返回处理后的资源路径:“vue” => “/@modules/vue”

vue文件处理过程 对vue组件的处理由 serverPluginVue来实现,其处理流程以下

  1. 分析请求路径,是否包含查询字段type
  2. 不包含type的请求视为script内容请求, 返回类型为 js
  3. 对于type为template请求则返回.vue文件的 template内容的渲染函数,返回类型为 js
  4. 对于type为style的请求则返回.vue文件中 style标签内样式的动态插入函数

4.4 Vite 热更新

图片

如上图所示,Vite热更新也是基于Websocket。在Vite服务器启动时,Vite利用中间件 serverPluginHtml在html中插入 client.js. 这个js文件主要用于在创建浏览器和Vite服务器之间的Websocket通讯。热更新的步骤以下

  1. Vite服务器监听本地文件更新
  2. 对比缓存中的文件和变更后的文件,组织更新内容
  3. 服务器经过PostMessage向浏览器通知更新消息,更新消息包含跟新类型,更新后模块的最新地址,时间戳
  4. 浏览器请求热更新文件
  5. 根据跟新类型处理返回的文件

clientjs监听的更新消息类型

  • connected: WebSocket 链接成功
  • vue-reload: Vue 组件从新加载(当你修改了 script 里的内容时)
  • vue-rerender: Vue 组件从新渲染(当你修改了 template 里的内容时)
  • style-update: 样式更新
  • style-remove: 样式移除
  • js-update: js 文件更新
  • full-reload: fallback 机制,网页重刷新

总结

Vite 提供了一个更快的开发环境服务器, 其实现原理基于ES模块,经过开发环境去打包将构建时间从 O(n) 减小到 O(1), 其搭载Vue3发布,借助Vue生态,在将来有更普遍的使用场景。

原做者:李璐

未经赞成,禁止转载!

相关文章
相关标签/搜索