企业定位是网站建设的,广州网站建设网站优化网站推广,.net网站建设实例,如何自助建网站一站式建网站vite分享ppt#xff0c;感兴趣的可以下载#xff1a;
Vite分享、原理介绍ppt 什么是vite系列目录#xff1a;
#xff08;一#xff09;什么是Vite——vite介绍与使用-CSDN博客
#xff08;二#xff09;什么是Vite——Vite 和 Webpack 区别#xff0… 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主要遵循的是使用 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核心中间件处理代码
indexHtmlMiddlewarehtml 相关请求处理中间件 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.htmlmain.jstext.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 . 再启用中间件后如下图。 看图我们大概知道了有哪些区别。浏览器支持原生 typemodule 模块请求加载。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 vueMiddlewarevueMiddleware 最终返回一个函数。这个函数里主要做了四件事
对 .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/vueconst 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、.jsxvite都会对其做不同的处理
.vue文件
vite 默认支持 Vue 项目并提供了一些 Vue 相关的插件如 vitejs/plugin-vue用于解析和编译 Vue 单文件组件。
Vue 3 单文件组件支持vitejs/plugin-vueVue 3 JSX 支持vitejs/plugin-vue-jsxVue 2 支持underfin/vite-plugin-vue2 npm install vitejs/plugin-vue 在 vite.config.js 中使用 Vue 插件
import { createVuePlugin } from vite-plugin-vueexport 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-cssexport default {plugins: [createCssPlugin(/* options */)]
} 裸模块重写
packages/vite/src/node/plugins/resolve.tspackages/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?vbc6c6eed 由于 import vue 这种模块引入方式使用的是 Nodejs 特有的模块查找算法到 node_modules 中取查找浏览器无法使用因此 Vite 会将 vue 替换成一个另一个路径当浏览器解析到这行 import 语句时会发送一个 /node_modules/.vite/deps/vuex.js?vbc6c6eed Vite Server 会到该目录下拿到 vue 预构建之后的产物代码。 你会发现引入的 vuex 是在.vite文件夹里头而不是在 node_modules 的 vuex 文件夹中这是因为 vite 做了一个优化 —— 依赖预构建。
依赖预构建做了什么
扫描入口文件扫描所有用到的依赖将多个依赖进行打包修改这些模块的引入路径
简单来说vite会对 package.json 中的 dependencies 部分先进行构建然后把构建后的文件换存在 node_modules/.vite 文件夹中当启动项目时直接请求该缓存内容。