(四)什么是Vite——冷启动时vite做了什么(源码、middlewares)
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做了什么:
vite主要遵循的是使用 ESM ( Es modules 模块)的规范来执行代码,由于现代浏览器基本上都支持了 ESM 规范,所以在开发阶段并不需要将代码打包编译成 es5 模块即可在浏览器上运行。我们只需要从入口文件出发, 在遇到对应的 import 语句时,将对应的模块加载到浏览器中就可以了(按需加载)。同时 ts/jsx 等文件的转译工作也会借助了 esbuild 来提升速度。Vite在内部实现上,会启动一个 dev server , 并接受独立模块的HTTP请求,并让浏览器自身去解析和处理模块加载。
模块解析
对于引用的模块,vite将其分为了 依赖 和 源码 两类,对其进行不同的处理。
先来看一下对于 源码 的处理。我们打开请求的App.vue文件,可以看到里面的内容已经不是源码了,而是经过处理后的代码。
middlewares 中内容转换
Vite 中源文件的转换是在 dev server 启动以后通过 middlewares 实现的。
当浏览器发起请求以后,dev sever 会通过相应的 middlewares (transformMiddleware 、indexHtmlMiddleware)对请求做处理,然后将处理以后的内容返回给浏览器。
middlewares 对源文件的处理,分为 resolve、load、transform、parser 四个过程:
- resolve - 解析 url,找到源文件的绝对路径;
- load - 加载源文件。如果是第三方依赖,直接将预构建内容返回给浏览器;如果是业务代码,继续 transform、parser。
- transfrom - 对源文件内容做转换,即 ts -> js, less -> css 等。转换完成的内容可以直接返回给浏览器了。
- parser - 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4。
- pre transform 是 Vite 做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。
Vite 在处理步骤 3 时,是通过 esbuild.transform 实现的,对比 Webpack 使用各个 loader 处理源文件,那是非常简单、快捷的。
模块请求加载过程:一个请求的 Vite 之旅
当浏览器一个请求到vite服务时,发生了什么?
主要由以下两个中间件来统一处理请求的内容,并在中间件处理的流程中调用 vite 插件容器的相关钩子函数
- transformMiddleware:核心中间件处理代码
- indexHtmlMiddleware:html 相关请求处理中间件
GET localhost :实际 GET / => /index.html
当访问页面的时候,实际是有一个 GET / => /index.html 的重定向进入 indexHtmlMiddleware 这个过程,主要做了一件事情,注入 dev 环境需要的一些依赖,@vite/client 主要用来和服务器进行 ws 通信并处理一些 hmr 相关的工作。
GET client :实际 GET /@vite/client
这个请求会直接进入 transformMiddleware 中间件中,进入中间件的处理过程:中间件会调用 transformRequest(url, server, options = {}) 函数
- @vite/client 是如何映射到对应的内容呢,在调用 pluginContainer.resolveId 的过程中会遇到 aliasPlugin 插件的钩子,执行名称替换,最终替换成 vite/dist/client/client.mjs
- 继续将改写过的路径传给下一个插件,最终进入 resolvePlugin 插件的 tryNodeResolve 函数,最终解析获得该文件的 id 为/lib/node_modules/vite/dist/client/client.mjs
- 最终通过 pluginContainer.load 获取加载本地文件,然后通过 pluginContainer.transform 进行代码转换,将转换后的代码通过 send 方法发送给浏览器。
有无 middlewares 的影响:例子—— vue-dev-server-analysis
(尤雨溪开发vue dev server理解vite原理 - 编程宝库)
# 克隆官方仓库
git clone https://github.com/vuejs/vue-dev-server.git
cd vue-dev-server
# npm i -g yarn
# 安装依赖
yarn
一般来说,我们看源码先从package.json文件开始:
// vue-dev-server/package.json
{"name": "@vue/dev-server","version": "0.1.1","description": "Instant dev server for Vue single file components","main": "middleware.js",// 指定可执行的命令"bin": {"vue-dev-server": "./bin/vue-dev-server.js"},"scripts": {// 先跳转到 test 文件夹,再用 Node 执行 vue-dev-server 文件"test": "cd test && node ../bin/vue-dev-server.js"}
}
根据 scripts test 命令。我们来看 test 文件夹。
test 文件夹:
vue-dev-server/test 文件夹下有三个文件,代码不长。
- index.html
- main.js
- text.vue
如图下图所示。
接着我们找到 vue-dev-server/bin/vue-dev-server.js 文件,代码也不长。
主要是启动了端口 3000 的服务,重点在 vueMiddleware 中间件。接着我们来调试这个中间件。
vue-dev-server/bin/vue-dev-server.js 文件中这行 app.use(vueMiddleware()) 打上断点。
找到 vue-dev-server/package.json 的 scripts,把鼠标移动到 test 命令上,会出现运行脚本和调试脚本命令。如下图所示,选择调试脚本。
点击 进入函数(F11)按钮可以进入 vueMiddleware 函数。如果发现断点走到不是本项目的文件中,不想看,看不懂的情况,可以退出或者重新来过。可以用浏览器无痕(隐私)模式(快捷键Ctrl + Shift + N,防止插件干扰)打开 http://localhost:3000,可以继续调试 vueMiddleware 函数返回的函数。
有无 vueMiddleware 中间件对比:
先看结果,在具体分析:
不在调试情况状态下,我们可以在 vue-dev-server/bin/vue-dev-server.js 文件中注释 app.use(vueMiddleware()),执行 npm run test 打开 http://localhost:3000 .
再启用中间件后,如下图。
看图我们大概知道了有哪些区别。浏览器支持原生 type=module 模块请求加载。vue-dev-server 对其拦截处理,返回浏览器支持内容,因为无需打包构建,所以速度很快。
具体分析
接下来,我们来具体分析:
我们可以找到vue-dev-server/middleware.js,查看这个中间件函数的概览。
// vue-dev-server/middleware.jsconst vueMiddleware = (options = defaultOptions) => {// 省略return async (req, res, next) => {// 省略// 对 .vue 结尾的文件进行处理if (req.path.endsWith('.vue')) {// 对 .js 结尾的文件进行处理} else if (req.path.endsWith('.js')) {// 对 /__modules/ 开头的文件进行处理} else if (req.path.startsWith('/__modules/')) {} else {next()}}
}
exports.vueMiddleware = vueMiddleware
vueMiddleware 最终返回一个函数。这个函数里主要做了四件事:
- 对 .vue 结尾的文件进行处理
- 对 .js 结尾的文件进行处理
- 对 /__modules/ 开头的文件进行处理
- 如果不是以上三种情况,执行 next 方法,把控制权交给下一个中间件
对 .vue 结尾的文件进行处理
if (req.path.endsWith('.vue')) {
const key = parseUrl(req).pathname
let out = await tryCache(key)
if (!out) {// Bundle Single-File Componentconst result = await bundleSFC(req) // 具体见下文,bundleSFC 编译单文件组件out = resultcacheData(key, out, result.updateTime)
}
send(res, out.code, 'application/javascript')
}
bundleSFC 编译单文件组件
这个函数,根据 @vue/component-compiler 转换单文件组件,最终返回浏览器能够识别的文件。
const vueCompiler = require('@vue/component-compiler')
async function bundleSFC (req) {
const { filepath, source, updateTime } = await readSource(req) // 看下文,readSource 读取文件资源
const descriptorResult = compiler.compileToDescriptor(filepath, source)
const assembledResult = vueCompiler.assemble(compiler, filepath, {...descriptorResult,script: injectSourceMapToScript(descriptorResult.script),styles: injectSourceMapsToStyles(descriptorResult.styles)
})
return { ...assembledResult, updateTime }
}
接着来看 readSource 函数实现。
readSource 读取文件资源
这个函数主要作用:根据请求获取文件资源。返回文件路径 filepath、资源 source、和更新时间 updateTime。
const path = require('path')
const fs = require('fs')
const readFile = require('util').promisify(fs.readFile)
const stat = require('util').promisify(fs.stat)
const parseUrl = require('parseurl')
const root = process.cwd()
async function readSource(req) {
const { pathname } = parseUrl(req)
const filepath = path.resolve(root, pathname.replace(/^\//, ''))
// 根据请求获取文件资源。返回文件路径 filepath、资源 source、和更新时间 updateTime。
return {filepath,source: await readFile(filepath, 'utf-8'),updateTime: (await stat(filepath)).mtime.getTime()
}
}
exports.readSource = readSource
接着我们来看对 .js 文件的处理
对 .js 结尾的文件进行处理
if (req.path.endsWith('.js')) {
const key = parseUrl(req).pathname
let out = await tryCache(key)
if (!out) {// transform import statements// 转换 import 语句 // import Vue from 'vue'// => import Vue from "/__modules/vue"const result = await readSource(req)out = transformModuleImports(result.source) // 转换 import 引入cacheData(key, out, result.updateTime)
}
send(res, out, 'application/javascript')
}
针对 vue-dev-server/test/main.js 转换
import Vue from 'vue'
import App from './test.vue'
new Vue({render: h => h(App)
}).$mount('#app')
转换:
import Vue from "/__modules/vue"
import App from './test.vue'
new Vue({render: h => h(App)
}).$mount('#app')
main.js 中的 import 语句import Vue from 'vue'通过 recast 生成 ast 转换成 import Vue from "/__modules/vue" 而最终返回给浏览器的是 vue-dev-server/node_modules/vue/dist/vue.esm.browser.js
main.js 中的引入 .vue 的文件,import App from './test.vue' 则用 @vue/component-compiler 转换成浏览器支持的文件,具体见下文。
对 /__modules/ 开头的文件进行处理
import Vue from "/__modules/vue"
这段代码最终返回的是读取路径 vue-dev-server/node_modules/vue/dist/vue.esm.browser.js 下的文件。
if (req.path.startsWith('/__modules/')) {
//
const key = parseUrl(req).pathname
const pkg = req.path.replace(/^\/__modules\//, '')
let out = await tryCache(key, false) // Do not outdate modules
if (!out) {out = (await loadPkg(pkg)).toString() // loadPkg 加载包(这里只支持Vue文件)cacheData(key, out, false) // Do not outdate modules
}
send(res, out, 'application/javascript')
}
loadPkg 加载包(这里只支持Vue文件)
目前只支持 Vue 文件,也就是读取路径 vue-dev-server/node_modules/vue/dist/vue.esm.browser.js 下的文件返回。
// vue-dev-server/loadPkg.js
const fs = require('fs')
const path = require('path')
const readFile = require('util').promisify(fs.readFile)
async function loadPkg(pkg) {
if (pkg === 'vue') {// 路径// vue-dev-server/node_modules/vue/distconst dir = path.dirname(require.resolve('vue'))const filepath = path.join(dir, 'vue.esm.browser.js')return readFile(filepath)
}
else {// TODO// check if the package has a browser es module that can be used// otherwise bundle it with rollup on the fly?throw new Error('npm imports support are not ready yet.')
}
}
exports.loadPkg = loadPkg
至此,我们就基本分析完毕了主文件和一些引入的文件。对主流程有个了解。
Vite 提供了哪些常用的构建插件和中间件?如何使用它们?
上文讲到了对于不同的资源会有不同的插件去处理。Vite 提供了一些常用的构建插件和中间件,以帮助你在项目中进行开发和构建。
vite的内置插件:
vite在返回源码时,已经对源码做了一层处理,编译为浏览器可以运行的代码。实际上,对于不同的文件后缀,比如.ts、.vue、.tsx、.jsx,vite都会对其做不同的处理:
.vue文件
vite 默认支持 Vue 项目,并提供了一些 Vue 相关的插件,如 @vitejs/plugin-vue,用于解析和编译 Vue 单文件组件。
- Vue 3 单文件组件支持:@vitejs/plugin-vue
- Vue 3 JSX 支持:@vitejs/plugin-vue-jsx
- Vue 2 支持:underfin/vite-plugin-vue2
npm install @vitejs/plugin-vue
在 vite.config.js 中使用 Vue 插件:
import { createVuePlugin } from 'vite-plugin-vue'export default {plugins: [createVuePlugin(/* options */)]
}
.ts文件
(packages/vite/src/node/plugins/esbuild.ts)
Vite 内置支持 TypeScript,无需额外的插件,其内部使用esbuild将TypeScript 转译到 JavaScript。可以直接在项目中使用 TypeScript。
.jsx文件、.tsx文件
(packages/vite/src/node/plugins/esbuild.ts)
JSX 的转译同样是通过 esbuild,默认为 React 16 风格。
.css文件
(packages/vite/src/node/plugins/css.ts)
Vite 支持处理 CSS 相关的插件,比如 vite-plugin-css,用于处理 CSS 文件和样式。导入 .css 文件将会把内容插入到标签中。
npm install vite-plugin-css
在 vite.config.js 中使用 CSS 插件:
import { createCssPlugin } from 'vite-plugin-css'export default {plugins: [createCssPlugin(/* options */)]
}
裸模块重写
(packages/vite/src/node/plugins/resolve.ts)(packages/vite/src/node/plugins/importAnalysis.ts)
从下面这张图中,我们可以看到, vuex.js、vue-router.js 这种依赖模块文件名后面是有后缀的,而 main.js 等这种源代码文件是没有的。为什么会有这样的不同呢?这是因为 vuex.js、vue-router.js 是裸模块,而浏览器在加载文件时,只能加载相对地址,类似于 import Vuex from 'vuex'; 这种裸模块的加载,浏览器是不支持的,所以 vite 会对其做一层裸模块重写的处理,例如将引入 vuex 的url改写为 /node_modules/.vite/deps/vuex.js?v=bc6c6eed
由于 import vue 这种模块引入方式,使用的是 Nodejs 特有的模块查找算法(到 node_modules 中取查找),浏览器无法使用,因此 Vite 会将 vue 替换成一个另一个路径,当浏览器解析到这行 import 语句时,会发送一个 /node_modules/.vite/deps/vuex.js?v=bc6c6eed, Vite Server 会到该目录下,拿到 vue 预构建之后的产物代码。
你会发现,引入的 vuex 是在.vite文件夹里头,而不是在 node_modules 的 vuex 文件夹中,这是因为 vite 做了一个优化 —— 依赖预构建。
依赖预构建做了什么:
- 扫描入口文件
- 扫描所有用到的依赖
- 将多个依赖进行打包
- 修改这些模块的引入路径
简单来说,vite会对 package.json 中的 dependencies 部分先进行构建,然后把构建后的文件换存在 node_modules/.vite 文件夹中,当启动项目时,直接请求该缓存内容。
相关文章:

(四)什么是Vite——冷启动时vite做了什么(源码、middlewares)
vite分享ppt,感兴趣的可以下载: Vite分享、原理介绍ppt 什么是vite系列目录: (一)什么是Vite——vite介绍与使用-CSDN博客 (二)什么是Vite——Vite 和 Webpack 区别࿰…...

Docker部署MinIO对象存储服务器结合Cpolar实现远程访问
🔥博客主页: 小羊失眠啦. 🎥系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞👍收藏⭐评论✍️ 文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远…...

C#入门(1):程序结构、数据类型
一、C#程序结构 第一个C#程序 using System;namespace base_01 {class Program{#region 代码折叠块static void Main(string[] args){//控制台输出Console.WriteLine("Hello World!");Console.Write("C#是微软的编程语言"); //不换行输出//Console.Rea…...
Scala---元组
1、元组定义 与列表一样,与列表不同的是元组可以包含不同类型的元素。元组的值是通过将单个的值包含在圆括号中构成的。 2、创建元组与取值 val tuple new Tuple(1) 可以使用newval tuple2 Tuple(1,2) 可以不使…...

【Linux】冯诺依曼体系结构、操作系统、进程概念、进程状态、环境变量、进程地址空间
目录 一、冯诺依曼体系结构二、操作系统(OS)1. 操作系统是什么2. 操作系统如何做管理3. 系统调用和库函数概念 三、进程1. 进程是什么?2. 描述进程-PCB3. 查看进程的方法 四、进程状态1 运行、阻塞和挂起状态2 Linux中的进程状态 五、进程优先级1. 什么是优先级2.查…...

【hive-解决】HiveAccessControlException Permission denied: CREATEFUNCTION
文章目录 一.任务描述二. 解决 一.任务描述 Error while compiling statement: FAILED: HiveAccessControlException Permission denied: Principal [nameroot, typeUSER] does not have following privileges for operation CREATEFUNCTION [ADMIN PRIVILEGE on INPUT, ADMIN…...

内网穿透的应用-通过内网穿透快速搭建公网可访问的Spring Boot接口调试环境
文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…...

解决 uniapp 开发微信小程序 不能使用本地图片作为背景图 问题
参考博文:uniapp微信小程序无法使用本地静态资源图片(背景图在真机不显示)的解决方法_javascript技巧_脚本之家 问题:uniapp 开发微信小程序,当使用本地图片作为 background-image 时,真机无法显示 解决: 方法一&am…...
常用中间件封装思路粗记
MQ 自定义注解 ,编写配置类在bean属性初始化SmartInitializingSingleton#afterSingletonsInstantiated后至处理器 去扫描有自定义注解的bean,去创建对应消费者的容器 并启动消费者容器类主要组件DefaultMQPushConsumer SmartInitializingSingleton#afte…...

探索SPI:深入理解原理、源码与应用场景
文章目录 一、初步认识1、概念2、工作原理3、作用场景 二、源码分析1、ServiceLoader结构2、相关字段3、核心方法 三、案例connector连接器小案例1、新建SPI项目2、创建扩展实现项目1-MongoDB3、创建扩展实现项目2-Oracle4、测试 Spring应用1、创建study工程2、创建forlan-test…...
Web3名词解释
Web3名词解释 以太坊 ERC20 Defi去中心化金融 Defi是Decentralized Finance的英文缩写。 简单理解点就是与传统的高度中心化金融体系相比,去中心化金融是通过区块链技术,比如基于区块链技术开发的手机钱包软件,通过智能合约代码以实现去除…...

Vatee万腾外汇市场新力量:vatee科技决策力
在当今数字化时代,Vatee万腾崭露头角,以其强大的科技决策力进军外汇市场,成为该领域的新力量。这一新动向将不仅塑造外汇市场的未来,也展现Vatee科技决策力在金融领域的引领作用。 Vatee万腾带着先进的科技决策力进入外汇市场&…...

【HarmonyOS开发】配置开发工具DevEco Studio
1、下载 注意: 1、安装过程中,一定要自定义安装位置,包比较大,包比较大,包比较大!!! 2、可以将该工具添加到右键中,否则,如果你的项目不是HarmonyOSÿ…...

探索亚马逊大语言模型:开启人工智能时代的语言创作新篇章
文章目录 前言一、大语言模型是什么?应用范围 二、Amazon Bedrock总结 前言 想必大家在ChatGPT的突然兴起,大家多多少少都会有各种各样的问题,比如:大语言模型和生成式AI有什么关系呢?大语言模型为什么这么火…...

zabbix-proxy分布式监控
Zabbix是一款开源的企业级网络监控软件,可以监测服务器、网络设备、应用程序等各种资源的状态和性能指标。在大型环境中,如果只有一个Zabbix Server来监控所有的节点,可能会遇到性能瓶颈和数据处理难题。 为了解决这个问题,Zabbi…...
springboot生成PDF,并且添加水印
/*** 导出调查问卷*/ApiLog("导出调查问卷")PostMapping("/print/{id}")ApiOperationSupport(order 23)ApiOperation(value "导出报告", notes "导出报告")public void print(PathVariable Long id, HttpServletResponse response…...
Tensorflow2.0:CNN、ResNet实现MNIST分类识别
以下仅是个人的学习笔记 ,内容可能是错误 CNN: import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers# 导入数据 (x_train, y_train), (x_test, y_test) keras.datasets.mnist.load_data()# 数据预处理 x_tra…...

本地jar导入maven
一、通过dependency引入 1.1. jar包放置,建造lib目录 1.2. pom.xml文件 <dependency><groupId>zip4j</groupId><artifactId>zip4j</artifactId><version>1.3.2</version><!--system,类似provided&#x…...

数据结构与算法【堆】的Java实现
前言 之前已经说过堆的特点了,具体文章在数据结构与算法【队列】的Java实现-CSDN博客。因此直接实现堆的其他功能。 建堆 所谓建堆,就是将一个初始的堆变为大顶堆或是小顶堆。这里以大顶堆为例。展示如何建堆。 找到最后一个非叶子节点从后向前&…...

同创永益联合红帽打造一站式数字韧性解决方案
随着AI技术的快速兴起,IT技术已成为推动业务持续增长的重要驱动力,这要求企业不断尝试新事物,改变固有流程,加强IT技术与业务的合作,同时提升数字韧性能力,以实现业务目标。10月26日,红帽2023中…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...