当前位置:首页 > 技术分析 > 正文内容

千字长文,前端利器Vite(源码解读,纯干货)

ruisui883个月前 (02-03)技术分析10



Vite的由来

在浏览器支持 ES 模块之前,JavaScript 并没有提供原生机制让开发者以模块化的方式进行开发。这也正是我们对 “打包” 这个概念熟悉的原因:使用工具抓取、处理并将我们的源码模块串联成可以在浏览器中运行的文件

正因如此,产生了很多优秀的打包工具,比如webpackRollupParcel。但是,久而久之开发构建的应用越来越大,就不得不面临一个问题——使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器。周而复始会极大的降低开发效率,以及开发的“幸福感”。

这时候Vite就孕育而生了,Vite之所以能短时间内成为业界的“宠儿”,旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写

服务器启动缓慢以及更新缓慢

服务器启动缓慢

当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。

Vite 通过在一开始将应用中的模块区分为 依赖源码 两类,改进了开发服务器启动时间。

  1. 依赖 大多为在开发时不会变动的纯 JavaScript。一些较大的依赖(例如有上百个模块的组件库)处理的代价也很高。依赖也通常会存在多种模块化格式(例如 ESM 或者 CommonJS)
  2. Vite 将会使用 esbuild 预构建依赖。Esbuild 使用 Go 编写,并且比以 JavaScript 编写的打包器预构建依赖快 10-100 倍
  3. 源码 通常包含一些并非直接是 JavaScript 的文件,需要转换(例如 JSX,CSS 或者 Vue/Svelte 组件),时常会被编辑。同时,并不是所有的源码都需要同时被加载(例如基于路由拆分的代码模块)
  4. Vite 以 原生 ESM 方式提供源码。这实际上是让浏览器接管了打包程序的部分工作:Vite 只需要在浏览器请求源码时进行转换并按需提供源码。根据情景动态导入代码,即只在当前屏幕上实际使用时才会被处理



更新缓慢

基于打包器启动时,重建整个包的效率很低。原因显而易见:因为这样更新速度会随着应用体积增长而直线下降。

一些打包器的开发服务器将构建内容存入内存,这样它们只需要在文件更改时使模块图的一部分失活[1],但它也仍需要整个重新构建并重载页面。这样代价很高,并且重新加载页面会消除应用的当前状态,所以打包器支持了动态模块热重载(HMR):允许一个模块 “热替换” 它自己,而不会影响页面其余部分。这大大改进了开发体验 —— 然而,在实践中我们发现,即使采用了 HMR 模式,其热更新速度也会随着应用规模的增长而显著下降。

在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活[1](大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。

Vite 同时利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦被缓存它们将不需要再次请求。

一旦你体验到 Vite 的神速,你是否愿意再忍受像曾经那样使用打包器开发就要打上一个大大的问号了。

源码初识

先来看下源码结构、比其他的webpack、Roullup之类的简洁明了很多,比较的清晰。


初始化流程

1.调用resolveConfig函数,解析合并各种配置。

2.初始化一个http+connect服务器。

3.创建插件容器 ,createPluginContainer方法,把插件的各个钩子函数串联起来,后续在请求处理的过程中直接执行挂载好的钩子函数。

4.生成一个server对象,包含配置信息、服务器信息、一些辅助函数等。

5.配置一系列内置中间件,各个中间件做的事情,返回 server 对象。

调用 server 的 listen 方法

1.运行插件containerbuildStart钩子,进而运行所有插件的buildStart钩子

2.进行依赖预构建,运行runOptimize函数。

3.开启服务,监听端口。

构建依赖


配置参数

export interface DepOptimizationOptions {
  /**
   * 入口文件,默认从html文件进行解析收集依赖,如果配置了的话,就从配置文件开始进行解析
   */
  entries?: string | string[]
  /**
   * 需要进行预构建的文件
   */
  include?: string[]
  /**
   * 不需要进行预构建的依赖
   */
  exclude?: string[]
  /**
   * 预构建是通过esbuild进行的,所以可以自定义配置esbuild参数
   */
  esbuildOptions?: Omit<
    EsbuildBuildOptions,
    | 'bundle'
    | 'entryPoints'
    | 'external'
    | 'write'
    | 'watch'
    | 'outdir'
    | 'outfile'
    | 'outbase'
    | 'outExtension'
    | 'metafile'
  >
}

构建结果

{
  // 配置的hash值
   hash :  afcda65e ,
  /**
   * 主要用于浏览器获取预构建的 npm 依赖时,添加的查询字符串
   * 在依赖变化时,浏览器能更新缓存
   */
   browserHash :  c369dd06 ,
   optimized : { // 预构建的优化列表
     react : {
      // 构建后的文件地址
       file :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/.vite/react.js ,
      // 原始文件地址
       src :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/react/index.js ,
      // 记录那些在依赖预构建时,使用了commonjs语法的依赖
      // 如果使用了commonjs语法,那么 needsInterop 为 true
       needsInterop : true
    },
     react-dom : {
       file :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/.vite/react-dom.js ,
       src :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/react-dom/index.js ,
       needsInterop : true
    },
     lodash : {
       file :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/.vite/lodash.js ,
       src :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/lodash/lodash.js ,
       needsInterop : true
    },
     react/jsx-dev-runtime : {
       file :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/.vite/react_jsx-dev-runtime.js ,
       src :  /Users/zhachunliu/Desktop/own/demo/vite-demo/vite-react-project/node_modules/react/jsx-dev-runtime.js ,
       needsInterop : true
    }
  }
}

模块加载

加载主要有两个核心函数完成

1.transformMiddleware(中间件代码处理)

2.indexHtmlMiddleware(html 相关请求处理中间件)

模块请求过程


结尾

此文仅供参考,很多细节也是未展开,还是得宝一步一步的摸索。在学习、调试的时候建议引入vite-plugin-inspect,它可以帮助你检查一些中间件的状态,也可以查看项目模块的一些信息、以及堆栈的调用情况等。注意!注意!注意!阅读源码的道路任重而道远,请各位务必慢慢来。



扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/829.html

标签: vite.js
分享给朋友:

“千字长文,前端利器Vite(源码解读,纯干货)” 的相关文章

vue 开发规范

项目运行指南(#项目运行指南)开发本地环境(#开发本地环境)开发相关插件/工具(#开发相关插件工具)开发规范(#开发规范)vue(#vue)【数据流向】(#数据流向)【慎用全局注册】(#慎用全局注册)【组件名称】(#组件名称)【组件中的 CSS】(#组件中的-css)【统一标签顺序】(#统一标签顺序...

Alpine.js 如何火起来的!比 React/Vue 如何?

大家好,很高兴又见面了,我是"高级前端?进阶?",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!前言前端 JavaScript 框架的创新是这个时代最伟大的技术文化现象之一。Alpine 发音为 /??lpa?n/,中文为阿尔卑斯山、...

一文看懂企业微信开发简易教程

为让开发者快速理解开发流程,本篇章展示如何一步步设计一个能与企业后台互动的自建应用。添加自建应用登录企业微信管理端 -> 应用与小程序 -> 应用 -> 自建,点击“创建应用”,设置应用logo、应用名称等信息,创建应用。创建完成后,在管理端的应用列表里进入该应用,可以看到agen...

企业微信自建应用和消息发送配置对接系统指南

本文介绍企业微信应用创建、消息提醒、自动回复、自定义菜单和服务端接口对接过程。企业微信登录:https://work.weixin.qq.com/企业微信接口对接,应用授权和发送消息代码:https://www.easywechat.com/docs/5.x/wework/oauth一、创建自建应用...

微信开发的五大价值应用

企业形象展示微网站是企业在移动互联网时代完美展示企业及品牌形象的最佳选择,表现内容丰富、实时更新、形式多样化,保证品牌形象的有效传播!微网站带来的轻营销模式,更适应现代网站的发展模式,所以微网站的开发也具有更好的商业营销效果,其面对的受众是7亿多的微信用户,蕴含着无限的商机。将企业微网站植入微信公众...

面试题:同步和异步的区别

作者:雅克的一府来源:http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_4832.html答案一:1.异步传输 通常,异步传输是以字符为传输单位,每个字符都要附加 1 位起始位和 1 位停止位,以标记一个字符的开始和结束,并以此实现数据传输同步。所谓异步...