(三)什么是Vite——Vite 主体流程(运行npm run dev后发生了什么?)

 vite分享ppt,感兴趣的可以下载:

​​​​​​​Vite分享、原理介绍ppt

什么是vite系列目录:

(一)什么是Vite——vite介绍与使用-CSDN博客

(二)什么是Vite——Vite 和 Webpack 区别(冷启动)-CSDN博客

(三)什么是Vite——Vite 主体流程(运行npm run dev后发生了什么?)-CSDN博客

(四)什么是Vite——冷启动时vite做了什么(源码、middlewares)-CSDN博客

(五)什么是Vite——冷启动时vite做了什么(依赖、预构建)-CSDN博客

(六)什么是Vite——热更新时vite、webpack做了什么-CSDN博客

(七)什么是Vite——vite优劣势、命令-CSDN博客

vite 源码总体目录结构

|
-CHANGELOG.md
|-LICENSE.md
|-README.md
|-bin
|  |-openChrome.applescript
|  |-vite.js
|-client.d.ts
|-package.json
|-rollup.config.js #打包配置文件
|-scripts
|  |-patchTypes.js
|-src
|  |-client #客户端
|  |  |-client.ts
|  |  |-env.ts
|  |  |-overlay.ts
|  |  |-tsconfig.json
|  |-node #服务端
|  |  |-build.ts
|  |  |-cli.ts #命令入口文件
|  |  |-config.ts
|  |  |-constants.ts #常量
|  |  |-importGlob.ts
|  |  |-index.ts
|  |  |-logger.ts
|  |  |-optimizer
|  |  |  |-esbuildDepPlugin.ts
|  |  |  |-index.ts
|  |  |  |-registerMissing.ts
|  |  |  |-scan.ts
|  |  |-plugin.ts #rollup 插件
|  |  |-plugins   #插件相关文件
|  |  |  |-asset.ts
|  |  |  |-clientInjections.ts
|  |  |  |-css.ts
|  |  |  |-esbuild.ts
|  |  |  |-html.ts
|  |  |  |-index.ts 
|  |  |  |-...
|  |  |-preview.ts
|  |  |-server
|  |  |  |-hmr.ts #热更新
|  |  |  |-http.ts
|  |  |  |-index.ts
|  |  |  |-middlewares #中间件
|  |  |  |  |-...
|  |  |  |-moduleGraph.ts #模块间关系组装(树形)
|  |  |  |-openBrowser.ts #打开浏览器
|  |  |  |-pluginContainer.ts
|  |  |  |-send.ts
|  |  |  |-sourcemap.ts
|  |  |  |-transformRequest.ts
|  |  |  |-ws.ts
|  |  |-ssr
|  |  |  |-__tests__
|  |  |  |  |-ssrTransform.spec.ts
|  |  |  |-ssrExternal.ts
|  |  |  |-ssrManifestPlugin.ts
|  |  |  |-ssrModuleLoader.ts
|  |  |  |-ssrStacktrace.ts
|  |  |  |-ssrTransform.ts
|  |  |-tsconfig.json
|  |  |-utils.ts
|-tsconfig.base.json
|-types
|  |-...                  

运行npm run dev后发生了什么?

(初识 vite 原理,vite 是如何启动项目的)(源码调试:下一代前端构建工具 - Vite 2.x 源码级分析)

vite命令是在哪里注册的呢,在 node_modules/vite/package.json 中查看bin字段。"bin" 字段的作用是能让我们在命令窗口全局输入命令执行。vite启动的时候,会执行 bin 目录下的 vite.js 文件,在这个文件里面我们会看到获取了当前的电脑的 绝对路径 ,如果不包含 node_module 路径,就需要引入 source-map-support 这个包来处理,如果是相对路径则会进行路径补全,当然在 dev 环境下都会有 node_module 路径,在 prod 环境下, vite 会使用 rollup 来进行打包。

示例项目下:package-lock.json

再示例项目下bin文件下看到三个vite文件,分别是针对unity,windows,跨平台三个方向链接对应的环境变量:

server 核心方法:执行命令行脚本

打开项目中的vite.js看到,其中主要运行的是从入口文件 cli.js。

vite.js 中的核心内容就是执行了 start 方法,动态引入了 ../dist/node/cli.js ,这个地址是打包后的地址,在 vite 源码中,脚本地址在 packages/vite/src/node/cli.ts 。

这里的/dist/node/cli.js是打包后的文件,可能有点长,可以配合vite打包前的源码一起阅读:

在 /dist/node/cli.js 中,首先使用 cac 命令工具处理用户的输入。

然后命令执行的是 createServer,这个 createServer 从 ./chunks/dep-df561101.js 引入,这里也是打包后的代码,比较长。

cli.ts 的核心功能是解析命令行参数并启动本地项目,解析命令行参数通过 cac 库,这里我们主要看启动本地项目的命令。在 cac 库中,通过 command 定义基础命令,通过 alias 方法定于命令别名,通过 option 方法定义命令行参数,最后通过 action 方法执行具体的操作。在 action 方法中,最核心的部分就是引入了 createServer 方法,通过 listen 启动本地 server。

同时在 cli.js 文件中,可以看到四个命令对应了 4 个核心的文件&方法:

1. dev 命令

文件路径:./server/index.ts;

主要方法:createServer;

主要功能:项目的本地开发命令,基于 httpServer 启动服务,Vite 通过对请求路径的劫持获取资源的内容返回给浏览器,服务端将文件路径进行了重写。例如:

项目源码如下:

import { createApp } from 'vue';
import App from './index.vue';

 经服务端重写后,node_modules 文件夹下的三方包代码路径也会被拼接完整。

import __vite__cjsImport0_vue from "/node_modules/.vite/vue.js?v=ed69bae0"; 
const createApp = __vite__cjsImport0_vue["createApp"];
import App from '/src/pages/back-sky/index.vue';

2. build 命令文件路径:./build.ts ;

主要方法:build;

主要功能:使用 rollup 打包编译

3.optimize 命令

文件路径:./optimizer/index.ts;

主要方法:optimizeDeps;

主要功能:主要针对第三方包,Vite 在执行 runOptimize 的时候中会使用 rollup 对三方包重新编译,将编译成符合 esm 模块规范的新的包放入 node_modules 下的 .vite 中,然后配合 resolver 对三方包的导入进行处理:使用编译后的包内容代替原来包的内容,这样就解决了 Vite 中不能使用 cjs 包的问题。

下面是 .vite 文件夹中的 _metadata.json 文件,它在预编译的过程中生成,罗列了所有被预编译完成的文件及其路径。例如:

{"hash": "1848098d","browserHash": "f4266ce6","optimized": {"./src/lib/index.js": {"src": "../../../src/lib/index.js","file": "___src_lib_index__js.js","fileHash": "58a83bbc","needsInterop": false},"lodash-es": {"src": "../../lodash-es/lodash.js","file": "lodash-es.js","fileHash": "915b5f31","needsInterop": false},"vue": {"src": "../../vue/dist/vue.runtime.esm-bundler.js","file": "vue.js","fileHash": "c91074d2","needsInterop": false}},"chunks": {}
}

4. preview 命令

文件路径:./preview/index.ts;

主要方法:preview;

主要功能:本地预览构建产物。不要将其用作生产服务器,因为它不是为此而设计的。

createServer #

我们找到了前面大概执行的顺序后,这里回到源码,在 packages/vite/src/node/server/index.ts 里面找到 createServer:

export async function createServer(inlineConfig: InlineConfig = {}
): Promise<ViteDevServer> {// Vite 配置整合// resolveConfig  方法解析 vite 核心配置,包括来自命令行、vite.config 文件的配置参数const config = await resolveConfig(inlineConfig, 'serve', 'development')const root = config.rootconst serverConfig = config.server// 创建http服务,根目录的 index.html 就是服务器的入口const httpServer = await resolveHttpServer(serverConfig, middlewares, httpsOptions)// 创建ws服务,主要是用于实现热更新(HMR),当代码发生变化时,服务器通过 WebSocket 向客户端发送更新通知const ws = createWebSocketServer(httpServer, config, httpsOptions)// 创建watcher,设置代码文件监听,实时地响应文件的增删改操作,也是用于实现热更新功能const watcher = chokidar.watch(path.resolve(root), {ignored: ['**/node_modules/**','**/.git/**',...(Array.isArray(ignored) ? ignored : [ignored])],...watchOptions}) as FSWatcher// 创建server对象const server: ViteDevServer = {config, // 配置属性middlewares,  // 中间件httpServer, // HTTP server 实例watcher, // chokidar 文件监听实例pluginContainer: container, // 插件容器ws, // WebSocket 实例moduleGraph, // 模块依赖图listen,...}// 文件监听变动,websocket向前端通信watcher.on('change', async (file) => {...handleHMRUpdate()})// 服务 middleware,通过 use 方法添加启动项目阶段需要的中间件middlewares.use(...)// optimize: 预构建await initDepsOptimizer(config, server)// 监听端口,启动服务httpServer.listen = (async (port, ...args) => { ... })return server
}

可以看到 createServer 做了很多事情:

  • 配置参数解析,包括 vite 核心配置、https 配置、chokidar 配置
  • 创建 HTTP 和 WebSocket server,用于启动开发 server 和热更新通信:
    • 通过 createHttpServer 创建一个 HTTP 服务器实例,根目录的 index.html 就是服务器的入口。
    • 通过 createWebSocketServer 创建 WebSocket 服务器,主要是用于实现热更新(HMR),当代码发生变化时,服务器通过 WebSocket 向客户端发送更新通知
  • 启动 chokidar 文件监听器,监听文件变化,实现热更新 HMR:
    • chokidar 能够创建一个文件监听器,监听文件和目录的变化,实时地响应文件的增删改操作,也是用于实现热更新功能。
  • 创建 ModuleGraph 实例,记录模块依赖关系:
    • 通过 ModuleGraph class 创建一个模块依赖图实例,模块依赖图主要用于维护各个模块之间的依赖关系,主要有两个用处:
      1. 热更新过程中,通过模块依赖图获取所有相关依赖,保证正确完整的实现热更新。
      2. 打包过程中,根据模块之间的依赖关系进行优化,比如将多个模块合并为一个请求、按需加载模块等,提高打包速度和加载性能。
  • 创建插件容器,管理插件生命周期、执行过程、插件之间传递上下文:
    • 通过 createPluginContainer 方法创建插件容器,插件容器主要有三个功能:
      1. 管理的插件的生命周期;
      2. 根据插件的钩子函数,在特定的时机执行插件;
      3. 在插件之间传递上下文对象,上下文对象包含 vite 的内部状态和配置信息,这样插件通过上下文对象就能访问和修改 vite 内部状态。
  • 定义 ViteDevServer 对象,包含核心配置和启动开发 server 核心方法:
    • ViteDevServer 对象就是 createServer 方法最终返回的对象,主要包含前几步创建的对象实例和启动 server 相关的核心方法。
    • 其中比较特殊的是 createDevHtmlTransformFn 方法,这个方法用于在开发环境下转换 index.html 文件,默认注入一段客户端代码 /@vite/client ,用于在客户端创建 WebSocket,接收服务端热更新传递的消息。
  • 执行 configureServer 定义函数,创建自定义中间件:
    • configureServer 主要用于配置开发服务器,比如在内部 connect 中添加自定义中间件。在这一步,从配置中获取所有 configureServer 钩子并放入 postHooks 钩子中,在内部中间中间件定义好之后,执行 postHooks 钩子。
    • 注意到 postHooks 是在处理 index.html 中间件之前执行,目的是为了自定义的中间件能够在返回 index.html 之前处理请求。
  • 定义内部中间件:
    • 通过 connect 包创建 middlewares 中间件。中间件主要是用来处理 HTTP 请求和响应,通过定义一系列的中间件并且按照一定的顺序执行,每个中间件函数对请求和响应进行处理,然后将处理后的请求和响应传递给下一个中间件函数,直到最后一个中间件函数处理完毕并发送响应。定义好 middlewares 之后,通过 use 方法添加启动项目阶段需要的中间件。

最后总结一下,在开发过程中,vite 启动命令 npm run dev 执行后,实际执行的是 node_module/.bin 目录下的 vite 脚本,在解析命令行参数之后,通过执行 createServer.listen 方法启动 vite 。

Vite开发环境主体流程

下图是 Vite 在开发环境运行时加载文件的主体流程。

具体如下:

在项目根目录下有一个index.html文件,在其script标签设置type='module':

  • 当声明一个 script 标签类型为 module 时:
 <script type="module" src="/src/main.js"></script>

 

  • 启动项目,vite会启动一个 dev server,然后加载各种中间件,进而监听对应的前端访问请求。github.com/vitejs/vite...同时,会在开发环境中注入 Vite 自身的 client 客户端代码,用于监听HMR等处理。github.com/vitejs/vite...

浏览器会向服务器发起一个GET请求,拿到main.js文件:

http://localhost:3000/src/main.js请求main.js文件:// /src/main.js:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

  • 浏览器请求到了main.js文件,检测到内部含有import引入的包,又会对其内部的 import 引用发起 HTTP 请求获取模块的内容文件。如:GET http://localhost:3000/@modules/vue.js 如:GET http://localhost:3000/src/App.vue

  • Vite 的主要功能就是通过劫持浏览器的这些请求,并在后端进行相应的处理将项目中使用的文件通过简单的分解与整合,然后再返回给浏览器,vite整个过程中没有对文件进行打包编译,所以其运行速度比原始的 webpack 开发编译速度快出许多!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/147354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode 配置 lua

https://luabinaries.sourceforge.net/ 官网链接 主要分为4个步骤 下载压缩包&#xff0c;然后解压配置系统环境变量配置vscode的插件测试 这里你可以选择用户变量或者系统环境变量都行。 不推荐空格的原因是 再配置插件的时候含空格的路径 会出错&#xff0c;原因是空格会断…

linux 网络 cat /proc/net/dev 查看测试网络丢包情况

可以通过 cat /proc/net/dev 查看测试网络丢包情况&#xff0c;drop关键字&#xff0c;查看所有网卡的丢包情况 还可以看其他数据&#xff0c; /proc/net/下面有如下文件

性能测试 —— Jmeter接口处理不低于200次/秒-场景

需求&#xff1a;期望某个接口系统的处理能力不低于200次/秒&#xff0c;如何设计&#xff1f; ①这个场景是看服务器对某个接口的TPS值是否能大于等于200&#xff0c;就可以了&#xff1b; ②系统处理能力&#xff1a;说的就是我们性能测试中的TPS&#xff1b; ③只要设计一…

Visual Studio Code---介绍

0 Preface/Foreword 1、安装VScode 官网&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 文档&#xff1a;Documentation for Visual Studio Code 1.1 优点 Intelligent code completion: code smarter with intellisense - completions for variables, me…

哈希

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;那个传说中的man的主页 &#x1f3e0;个人专栏&#xff1a;题目解析 &#x1f30e;推荐文章&#xff1a;题目大解析&#xff08;3&#xff09; 目录 &#x1f449;&#x1f3fb;unordered系列关联式容器un…

锐捷练习-ospf虚链路及rip路由相互引入

一、相关知识补充 1、ospf基本概述 OSPF&#xff08;Open Shortest Path First&#xff09;是一种链路状态路由协议&#xff0c;用于在计算机网络中进行路由选择。它是内部网关协议&#xff08;IGP&#xff09;之一&#xff0c;常用于大规模企业网络或互联网服务提供商的网络…

Pytorch torch.dot、torch.mv、torch.mm、torch.norm的用法详解

torch.dot的用法&#xff1a; 使用numpy求点积&#xff0c;对于二维的且一个二维的维数为1 torch.mv的用法&#xff1a; torch.mm的用法 torch.norm 名词解释&#xff1a;L2范数也就是向量的模&#xff0c;L1范数就是各个元素的绝对值之和例如&#xff1a;

flutter仿支付宝余额宝年化收益折线图

绘制&#xff1a; 1.在pubspec.yaml中引入&#xff1a;fl_chart: 0.55.2 2.绘制&#xff1a; import package:jade/utils/JadeColors.dart; import package:util/easy_loading_util.dart; import package:fl_chart/fl_chart.dart; import package:flutter/material.dart; impo…

微服务实战系列之Sentinel

前言 微服务架构&#xff08;Microservice Architecture&#xff09;是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。 近年来&#xff0c;微服务已赫然崛起于IT界&#xff0c;越来越多的程序员不得不向之靠拢。也正因为各行各业都愿为…

【入门篇】1.4 redis 客户端 之 Lettuce 详解

文章目录 1. 简介1. 什么是Lettuce2. Lettuce与其他Redis客户端的比较3. Lettuce的特性和优势 2. 安装和配置3. 连接池配置1. 什么是连接池2. Lettuce的连接池使用与配置3. 连接池配置项 4. 基本操作1. 如何创建Lettuce连接2. Lettuce的基本操作如增删改查3. Lettuce的事务操作…

【Python基础篇】运算符

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录 一 Python中的运算符二 算术运算符1 Python所有算术运算符的说明2 Python算术运算符的所有操作…

Mysql MMM

MMM概述 MMM(Master-Master replication manager for MvSQL&#xff0c;MySQL主主复制管理器&#xff09; 是一套支持双主故障切换和双主日常管理的脚本程序。 MMM 使用 Perl 语言开发&#xff0c;主要用来监控和管理MySQL Master-Master&#xff08;双主&#xff09;复制&…

YOLOv8改进 | DAttention (DAT)注意力机制实现极限涨点

论文地址&#xff1a; DAT论文地址 官方地址&#xff1a;官方代码的地址 代码地址&#xff1a;文末有修改了官方代码BUG的代码块复制粘贴即可 一、本文介绍 本文给大家带来的是YOLOv8改进DAT(Vision Transformer with Deformable Attention)的教程&#xff0c;其发布于2022…

uniapp 手动调用form表单submit事件

背景&#xff1a; UI把提交的按钮弄成了图片&#xff0c;之前的button不能用了。 <button form-type"submit">搜索</button> 实现&#xff1a; html&#xff1a; 通过 this.$refs.fd 获取到form的vue对象。手动调用里面的_onSubmit()方法。 methods:…

MySQL内部组件与日志详解

MySQL的内部组件结构 MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层主要包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、时间、数学和加密函数等&#xff09;&am…

Spring面试题:(八)Spring事务

Spring事务概述 Spring事务基于数据库&#xff0c;基于数据库的事务封装了统一的接口。 编程式事务和声明式事务。 声明式事务分为Xml声明式或者注解声明式 实现事务相关的三个类 事务管理器 事务定义 事务状态 XML声明式事务的使用方法 导入坐标配置目标类配置切面 导入…

【LeetCode刷题-双指针】--259.较小的三数之和

259.较小的三数之和 方法&#xff1a;排序双指针 class Solution {public int threeSumSmaller(int[] nums, int target) {Arrays.sort(nums);int k 0;for(int i 0;i<nums.length;i){int start i 1,end nums.length - 1;while(start < end){int sum nums[start] …

FPGA UDP RGMII 千兆以太网(4)ARP ICMP UDP

1 以太网帧 1.1 1以太网帧格式 下图为以太网的帧格式: 前导码(Preamble):8 字节,连续 7 个 8’h55 加 1 个 8’hd5,表示一个帧的开始,用于双方 设备数据的同步。 目的 MAC 地址:6 字节,存放目的设备的物理地址,即 MAC 地址 源 MAC 地址:6 字节,存放发送端设备的…

受电诱骗快充取电芯片XSP08:PD+QC+华为+三星多种协议9V12V15V20V

目前市面上很多家的快充充电器&#xff0c;都有自己的私有快充协议&#xff0c;如PD协议、QC协议、华为快充协议、三星快充协议、OPPO快充协议等待&#xff0c;为了让它们都能输出快充电压&#xff0c;就需要在受电端也增加快充协议取电芯片XSP08&#xff0c;它可以和充电器通讯…

Java学习 10.Java-类和对象

一、面向对象的初步认知 1.1 什么是面向对象 面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情&#xff0c;用面向对象的思想来设计程序&#xff0c;更符合人们对事物的认知&#xff0c;对于大型程序的设计、拓展以及维护都非常友好 1.2 面向对…