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

news2024/11/13 11:22:52

 什么是vite系列目录:

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

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

(三)什么是Vite——Vite 主体流程(运行npm run dev后发生了什么?)-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.root
    const 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.coloradmin.cn/o/1212565.html

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

相关文章

慧眼APP开发项目

目录 第1章 项目概述... 3 第2章 可行性分析... 4 2.1 技术可行性... 4 2.2 数据可行性... 4 2.3 应用可行性... 4 第3章 环境搭建... 5 3.1 模型搭建... 5 3.1.1 安装PaddleDetection. 5 3.1.2 自定义数据集... 5 3.2 APP搭建... 5 3.2.1 安装Android Studio. 5 3.…

C++入门(1)—命名空间、缺省参数

目录 一、什么是C 1、C关键字(C98) 2、C兼容C 二、C程序预处理指令 三、命名空间 1、命名冲突 第一种&#xff1a; 第二种&#xff1a; 2、域作用限定符 3、实现命名空间 4、命名空间冲突 5、访问命名空间 6、命名空间“std” 四、输入输出 1、定义 2、自动识…

Python开源项目DifFace——人脸重建(Face Restoration),模糊清晰、划痕修复及黑白上色的实践

无论是自己、家人或是朋友、客户的照片&#xff0c;免不了有些是黑白的、被污损的、模糊的&#xff0c;总想着修复一下。作为一个程序员 或者 程序员的家属&#xff0c;当然都有责任满足他们的需求、实现他们的想法。除了这个&#xff0c;学习了本文的成果&#xff0c;或许你还…

如何在面试中胜出?接口自动化面试题安排上

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Godot4.1 GDExtension 配置VisualStudio方法梳理以及快捷配置工具

写在最前 本篇教程基于之前教程&#xff0c;并且默认为Windows10&#xff0c;64位&#xff0c;Godot版本4.1.3如果遇到任何问题&#xff0c;欢迎及时提出&#xff0c;如果配置成功了请点个赞&#xff0c;球球啦。 之前教程 https://blog.csdn.net/qq_31805591/article/detai…

天机学堂-1、项目搭建,微服务架构设计

1.学习背景 各位同学大家好&#xff0c;经过前面的学习我们已经掌握了《微服务架构》的核心技术栈。相信大家也体会到了微服务架构相对于项目一的单体架构要复杂很多&#xff0c;你的脑袋里也会有很多的问号&#xff1a; 微服务架构该如何拆分&#xff1f; 到了公司中我需要自…

8.查询数据

一、单表查询 MySQL从数据表中查询数据的基本语为SELECT语。SELECT语的基本格式是: SELECT {* | <字段列名>} [ FROM <表 1>, <表 2>… [WHERE <表达式> [GROUP BY <group by definition> [HAVING <expression> [{<operator>…

Linux网络应用层协议之http/https

文章目录 目录 一、http协议 1.URL 2.http协议格式 3.http的方法 4.http的状态码 5.http常见header 6.实现一个http服务器 二、https协议 1.加密 2.为什么要加密 3.常见的加密方式 对称加密 非对称加密 4.https的工作过程探究 方案1 只使用对称加密 方案2 只使…

类似于推箱子的小游戏 寻找 最短路径

实现效果如下 类似 推箱子小游戏 的变种 C/C版本 BFS最短路径 黑色代表墙壁 不能越过 蓝色代表HOME点 灰色代表要找的小箱子 绿色代表路径 最终目标是将灰色的小箱子移动到蓝色的HOME点 需要两次搜索 第一次是 出发点到灰色小箱子 第二次是灰色小箱子到蓝色HOME点 BF…

python爬取网站数据,作为后端数据

一. 内容简介 python爬取网站数据&#xff0c;作为后端数据 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3代码 链接&#xff1a; 三.主要流程 3.1 通过urllib请求网站 里面用的所有的包 ! pip install lxml ! pip install selenium ! pip install…

100G.的DDoS高防够用吗?

很多人以为100G的DDoS防御已经足够了&#xff0c;但殊不知DDoS攻击大小也是需要分行业类型的&#xff0c;比如游戏、金融、影视、电商甚至ZF或者行业龙头等等行业类型&#xff0c;都是大型DDoS攻击的重灾区&#xff0c;别说100G防御&#xff0c;就算300G防御服务器也不一定够用…

开启核磁数据处理新篇章-MestReNova(MNOVA14)助您轻松解读科学界密码

在科学研究领域&#xff0c;核磁共振&#xff08;NMR&#xff09;技术被广泛应用于分析和解读化学物质的结构和性质。而MestReNova&#xff08;MNOVA14&#xff09;作为一款专业的核磁数据处理软件&#xff0c;凭借其强大的功能和易用性&#xff0c;已成为众多科研人员的首选工…

用这个平台制作电子杂志,,还能实时分享,太方便啦!

在我们看电子杂志的时候&#xff0c;总会觉得图文效果有点枯燥&#xff0c;如果能做出翻页书效果的电子杂志&#xff0c;还给人一种身临其境的真实翻书感就好了。 其实制作这种翻页电子杂志很简单&#xff0c;不需要下载安装任何软件&#xff0c;只需登录FLBOOK这个平台 &…

SpringCloud微服务:Nacos的下载和配置

目录 Nacos的下载 Nacos的配置 Nacos的下载 nacos压缩包&#xff0c;点击下载百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固&#xff0c;支持教育网加速&#xff0c;支持手机端。注册使用百度网盘即可享受免费存储空间https://pan.baidu.com/…

NVIDIA安装

电脑显卡类型 两种方法&#xff1a; 选择对应的版本 产品系列下载Notebooks&#xff0c;这样产品才会出现Laptop的GPU&#xff08;Laptop是代表笔记本&#xff09;。 下载完之后双击安装&#xff0c;更改下载路径后&#xff0c;选择默认的下载即可。 卸载 如果之后要卸载…

上位机模块之halcon绘制ROI与获取ROI,在hsmartwindow实现

在上位机中通常需要使用到绘制ROI模块或者获取已经绘制好的ROI区域的参数&#xff0c;在这里通过使用hsmartwindow窗体控件进行对ROI的绘制和获取。 先上代码&#xff1a; /// <summary>/// 创建ROI/// </summary>/// <param name"Win">传入HSmar…

2023鸿蒙预定未来,环境搭建学习

鸿蒙开发基础知识 鸿蒙的基本概念和特点 鸿蒙&#xff08;HarmonyOS&#xff09;是华为公司开发的一款全场景分布式操作系统。它的设计目标是为各种设备提供统一的、无缝的用户体验。鸿蒙的核心特点包括以下几个方面&#xff1a; 分布式架构&#xff1a;鸿蒙采用分布式架构&…

EDA实验------数控分频器设计(QuartusII)

目录 一、实验目的 二、实验原理 三、实验内容 四、实验步骤 五、注意事项 六、思考题 七、实验过程 分频器的基本原理 什么是分频器&#xff1f; 如何去分频&#xff1f; 1.创建新项目 2.创建Verilog文件&#xff0c;写入代码 3.连接电路 ​编辑 锁相环的创建 4…

9.基于SpringBoot3+MybatisPlus定制化代码生成器类

我们在3.基于SpringBoot3集成MybatisPlus中讲到自定义代码生成器&#xff0c;但是往往遗留代码生成的类格式或者命名不符合要求&#xff0c;需要手工修改&#xff0c;但是当表很多时就比较头痛,所以我们自定义模板在进行代码生成 1. 新建MyTemplateEngine.java类 里面大多实现…

企业大文件传输的四大误区:你还在用传统的FTP和网盘吗?

在当前数字化时代&#xff0c;数据已经成为企业的核心资产&#xff0c;而文件传输则是数据流动的重要方式。企业需要高效、安全、稳定地传输各种类型和规模的文件&#xff0c;无论是内部协作还是外部交付。然而&#xff0c;很多企业在文件传输方面存在一些误区&#xff0c;导致…