尤大新作:Vite

347 阅读6分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

正文

直观上的“两快”

  • 服务起的快
  • 文件热更新快

img

Vite 简介

尤大在微博上推广时对 Vite 做的简短介绍:

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

传统构建模式(webpack:你直接说我名字得了)

img

vite 构建模式

img

目的:彻底解决改一行代码等半天热更新的问题,提高开发者的开发效率和幸福感。

不同环境的技术核心点

开发环境:esm + esbuild

生产环境:rollup

开发环境的两大核心

源码:以原生 ESM 方式提供源码

依赖:使用 esbuild 预构建依赖

ESM

ESM:原生模块功能(通俗点就是 importexport 这对海尔兄弟),现代浏览器都有了很好的支持(ie:都看我干嘛,我是传统浏览器科代表)

  1. 添加 type="module" 表示这是个 js 原生模块,<script type="module"></script>
  2. 引入一个模块,会发起服务请求,所以在本地测试引入如 file:// 路径文件的时候将会遇到 CORS 错误
  3. 只支持相对路径和绝对路径,不支持裸模块

esbuild

esbuild 构建速度比较

img

esbuild 是什么?

esbuild 是一个新的模块打包工具,它提供了与 Webpack、Rollup、Parcel 等工具**「相似」**的资源打包能力。

在 vite 中起什么作用

vite 默认开发过程中使用的浏览器是现代浏览器,是能在 script 标签上支持原生 ESM 和原生 ESM 动态导入的,但实际上的文件形式是多种多样的。

作用:

  1. 将作为 CommonJSUMD 发布的依赖项转换为 ESM 导出
  2. 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能,例如:lodash-es
凭什么这么快?

img

语言优势

大部分前端打包工具都是用的 js 编写的,而 esbuild 选择用 go 编写。

1.  `js` 是一门解释型语言,`go` 是一门编译型语言。编译型语言较解释型语言的最大优势就是执行速度
2.  `js` 是一门单线程语言,而 `go` 天生具有多线程运行能力,会尽可能饱和的运用多核,更高效的内存使用率,也就意味着更高的运行性能
设计
  1. 完全重写整套编译流程所需要用到的所有工具!这意味着它重写了 js、ts、jsx、css 、json、图片等资源文件的加载、解析、链接、代码生成逻辑,从源头上就处理了性能问题
  2. webpackloade 相似的加载器,针对性的对单一文件进行编译

vite 项目初始化配置

前置条件:node 版本 >= 12.0.0

聊聊 vite 在开发环境是怎么工作的

根据上面所说的,vite 想在开发环境使用 esm 模式开发,需要解决的五大痛点:

  1. 解决请求 es 模块 CORS 问题
  2. 第三方库有的是以 CommonJSUMD 发布的,需要统一第三方库以 esm 方式导出
  3. 解决裸模块引入问题
  4. 处理类似 .vue 等浏览器和 esbuild 都不支持解析的文件
  5. 文件热更新问题

针对性解决方案:

  1. 在本地启动一个 http 服务,实现对浏览器请求的响应
  2. 服务启动前,会先将 package.json 中的 dependencies 的依赖通过 esbuildesm 的形式导出缓存在 node_modules/.vite 中。在请求拦截中分析请求内容,如果是裸模块或者 .vue 这种浏览器不认识的文件类型,则会重写导入,如 /node_modules/.vite/vue.js?v=796112c2,如果是默认不支持的文件,则通过编译插件进行解析返回。
  3. 文件热更新问题主要分两点,文件监听和服务推送。先创建一个 websocket 服务端,在 transformIndexHtml 解析 html 入口文件的时候将 client 路径注入进去,用来创建客户端的 websocket,接收服务端推送。vite 使用 chokidar 来监听文件变化,当监听到 change 的时候调用 handleHMRUpdate 通知客户端文件更新了,然后在 client 里判断是刷新页面还是更新组件。

至此,开发环境大概流程就清晰了许多,总结一下:

一切起源于一个远古操作:npm run dev,执行了 vite 命令,先在本地启动一个服务,启动后将依赖通过 esbuildesm 的形式导出、缓存,在创建服务的时候同时在服务端创建了一个 websocket 服务,使用 chokidar 监听文件变化,然后在 index.html 注入客户端的 websocket 用来接收服务端的推送来判断刷新页面还是更新文件。

vite 的利与弊

利:

  1. 极大提升了开发效率和幸福感
  2. 上手简单,无需学习一堆复杂的配置项
  3. Rollup 极其接近的插件接口,意味着可以复用 Rollup 生态中大部分已经被反复锤炼的工具
  4. 开发效率提高了,课后学习(摸鱼)时间也就多了

弊:

  1. 启动服务的时间极限缩短了,思考(摸鱼)时间段也没有了,成也萧何败也萧何
  2. 对于 webpack 重度用户 && 未使用过 rollup 用户,内心os:好不容易达到 webpack 大师段位,这会儿跟我说改 rollup

结语:那是用 webpack 还是 vite?.

img

总结

此次就分享了 vite 在开发阶段的工作流程和原理,未涉及 ssr 项目, rollup、vite 插件的开发和使用,架构迁移,项目升级。

关注度比较高的三个构建工具比较:深度分析前端构建工具:Vite2 v.s Snowpack3 v.s. Webpack5

学识有限,还请见谅,不足/错误之处欢迎在评论区讨论~

参考文章

Vite 官方中文文档

Vite 是如何实现的

Esbuild 是什么

Vite 特性和部分源码解析

vite源码分析(4) :vite 热更新原理分析