1.Vite 深入浅出及原理分析
2.Vite 源码学习3. package.json分析
3.Vite源码解析(三)之热更新篇
4.Vite 技术揭秘之调试
5.你还不会写vite插件吗?没关系,手写手写识别我教你啊!源码
6.Vite 热更新(HMR)原理了解一下
Vite 深入浅出及原理分析
Vite,开源作为新一代的手写手写识别前端构建工具,以其显著的源码加速性能脱颖而出。官网cn.vitejs.dev提供了详细信息。开源封单额度指标源码Vite的手写手写识别设计初衷是为了解决Webpack构建过程中存在的问题,特别是源码针对大型应用的开发速度和实时热更新(HMR)效率。
首先,开源Vite通过区分依赖和源码,手写手写识别极大地优化了开发服务器启动时间。源码它使用原生ESM(EcmaScript Modules)支持,开源让浏览器在请求源代码时进行按需转换,手写手写识别降低了模块处理的源码复杂性。HMR在原生ESM基础上运行,开源仅更新已编辑模块及其关联部分,确保无论应用规模如何,更新都保持高效。
此外,Vite利用HTTP头技术,如 Not Modified和Cache-Control,加速页面重新加载。源码模块通过协商缓存,依赖模块则采用强缓存策略,避免重复请求。深入研究Vite源代码,我们可以看到其监听文件变化、优化依赖处理和利用esbuild等工具来生成虚拟模块,以适应多标签和内联script的需求。
虚拟模块是编译时生成的,它们并非直接来自磁盘,而是打包工具如esbuild在编译过程中创建。这样做的目的是处理HTML文件中的多个script标签,避免命名冲突等问题。esbuild打包过程的优化,实际上简化了传统的深度遍历,提高了构建效率。
总之,Vite通过革新性的设计和优化,提供了更快、国外源码更高效的前端开发体验。要深入了解其工作原理,不妨深入阅读其官方文档和相关代码库。
Vite 源码学习3. package.json分析
本文着重解析了Vite项目中dependencies和devDependencies依赖包的用途,以理解Vite如何利用第三方库进行开发。Vite的dependencies部分主要用于项目运行时,包含了JavaScript解析器如@babel/parser,支持CommonJS语法的@rollup/plugin-commonjs,以及用于处理TypeScript类型定义的@types/*等。例如,@vue/compiler-dom和@vue/compiler-sfc是Vue模板和SFC底层工具集,brotli-size则用于字符串和Buffer的压缩。devDependencies则主要为开发环境提供支持,如@babel/runtime为Babel运行时工具,jest用于测试,prettier则负责代码格式化。dependencies:关键库如@vue/compiler-dom负责Vue模板编译,@rollup/plugin-node-resolve用于模块定位,@types/*提供TypeScript类型支持。
devDependencies:如jest用于编写和运行测试,postcss和less是CSS处理工具,typescript支持项目使用TypeScript,vue-router和vuex则提供路由和状态管理功能。
这些依赖包的合理配置,使得Vite能够在高效开发的同时,确保项目的稳定性和可维护性。后续内容将继续探讨Vite的其他组件和配置。Vite源码解析(三)之热更新篇
为了提升开发体验,热替换功能使得修改代码后无需刷新页面即可实时生效,避免了频繁的页面重载操作。这一特性在现代化前端框架中被视为一项基本要求,如同 webpack-dev-server 等模块所具备的功能。热替换在 Vite 中的实现主要依赖于 websocket 技术,通过 websocket 实现服务端与浏览器间的高效通信,确保代码更新即时生效。
热替换的实现涵盖了多种文件类型,如 .vue、.js、.css 等,源码录每种类型的文件更新策略可能有所不同。例如,对于 .vue 文件的热替换,主要是通过更新组件的动态引入和条件渲染来实现,确保仅相关部分的组件状态得到更新,而不会影响到其他未修改的部分。
在 Vite 的热替换机制中,`import.meta.hot` API 提供了访问热替换相关状态的功能,允许开发者根据具体需求自定义热替换的行为,如处理错误、执行某些特定逻辑等。
监听文件变化是热替换功能得以实现的基础。通常,框架会利用文件系统监控API,如 Node.js 的 fs.watch 和 fs.watchFile,或更高层次封装的模块如 chokidar,以实时捕捉文件变动事件。在 Vite 中,同样使用这类API,通过 chokidar进行文件系统变动监听,确保一旦文件发生变化,即可触发相应的热替换逻辑。
在处理css文件的热替换时,主要考虑两种情况:一是修改外部css源文件(例如通过`import`引入或直接修改Vue组件内的`style`标签),二是对组件内部的样式进行直接修改。针对这两种情况,Vite会采用不同的策略来实现样式更新,确保用户界面能够即时响应代码变化,而无需页面重载。
总结而言,热替换功能在Vite中的实现是一个涉及代码更新策略、文件监听和实时通信技术的综合过程,旨在显著提升前端开发的效率和体验。通过高效地管理文件变动和代码更新,Vite为开发者提供了一种无缝、高效的工作流程,使得开发、调试和迭代过程更为流畅。
Vite 技术揭秘之调试
首先,快递源码让我们一起深入了解调试 Vite CLI 工具的必要步骤。作为开发者的你,可以通过以下步骤在本地搭建调试环境,每完成一个环节,记得实际操作以提升学习效果哦!调试环境准备
首先,从官方仓库 fork 代码并克隆到本地,可以在源码中添加注释,但请注意,不要在构建后的代码中过多注释,以防构建时丢失。
完成后,执行 pnpm build 以安装依赖并构建工具。理解 build 和 dev 命令的区别,尤其是 dev 带有 watch 参数,这将影响源码调试时的实时反馈。
在项目中启用 sourcemap 功能,以便于源码定位。然后使用 pnpm link 将构建后的 vite 命令链接到全局。
为了减少干扰,推荐建立一个最小的 demo,只包含关键功能,便于集中精力调试。
断点设置与调试
在关键代码段设置断点,如 packages/vite/src/node/cli.ts 中的 dev action。
熟悉 CLI 帮助信息,了解 debug 和 filter 参数的作用,前者开启调试日志,后者用于过滤日志。
在命令行中执行带有 debug 参数的 dev 命令,进入调试模式,查看详细的日志输出。
成功到达断点后,你可以开始探索源码逻辑,理解 Vite 创建 server 的过程。
你还不会写vite插件吗?没关系,我教你啊!
前言
大家好,我是竞价源码易师傅,在现如今Vite工具快开始盛行之下,我们是不是可以去做一件有意义的事呢,比如写一个vite插件,你觉得怎么样?
刚好我们可以趁vite插件生态还未很成熟阶段,做一个让自己顺心,让领导赏心,让社区开心的插件,与之携手共进。
如果大家对vite感兴趣可以去看看专栏:?《Vite从入门到精通》
通过本文你可以学到如何创建一个vite插件模板
vite插件的各个钩子作用
vite插件的钩子执行顺序
如何写一个自己的插件
了解vite插件1.什么是vite插件vite其实就是一个由原生?ESModule?驱动的新型Web开发前端构建工具。
vite插件就可以很好的扩展vite自身不能做到的事情,比如文件的压缩、对commonjs的支持、打包进度条等等。
2.为什么要写vite插件相信在座的每位同学,到现在对webpack的相关配置以及常用插件都了如指掌了吧;
vite作为一个新型的前端构建工具,它还很年轻,也有很多扩展性,那么为什么我们不趁现在与它一起携手前进呢?做一些于你于我于大家更有意义的事呢?
快速体验要想写一个插件,那必须从创建一个项目开始,下面的vite插件通用模板大家以后写插件可以直接clone使用;
插件通用模板github:体验入口
插件github:体验入口
建议包管理器使用优先级:pnpm>yarn>npm>cnpm
长话短说,直接开干~
创建vite插件通用模板1.初始化1.1创建一个文件夹并且初始化:初始化按照提示操作即可
mkdirvite-plugin-progress&&cdvite-plugin-progress&&pnpminit1.2安装typescript
pnpmitypescript@types/node-D1.3配置tsconfig.json
{ "compilerOptions":{ "module":"ESNext","target":"esnext","moduleResolution":"node","strict":true,"declaration":true,"noUnusedLocals":true,"esModuleInterop":true,"outDir":"dist","lib":["ESNext"],"sourceMap":false,"noEmitOnError":true,"noImplicitAny":false},"include":["src/*","*.d.ts"],"exclude":["node_modules","examples","dist"]}1.4安装vite
//进入package.json{ ..."devDependencies":{ "vite":"*"}...}2.配置eslint和prettier(可选)安装eslint
pnpmieslint@typescript-eslint/parser@typescript-eslint/eslint-plugin--save-dev配置.eslintrc:配置连接
安装prettier(可选)
pnpmiprettiereslint-config-prettiereslint-plugin-prettier--save-dev配置.prettierrc:配置连接
3.新增src/index.ts入口importtype{ PluginOption}from'vite';exportdefaultfunctionvitePluginTemplate():PluginOption{ return{ //插件名称name:'vite-plugin-template',//pre会较于post先执行enforce:'pre',//post//指明它们仅在'build'或'serve'模式时调用apply:'build',//apply亦可以是一个函数config(config,{ command}){ console.log('这里是config钩子');},configResolved(resolvedConfig){ console.log('这里是configResolved钩子');},configureServer(server){ console.log('这里是configureServer钩子');},transformIndexHtml(html){ console.log('这里是transformIndexHtml钩子');},}}其中的vite插件函数钩子会在下面详细详解~
到这里,那么我们的基本模版就建好了,但是我们现在思考一下,我们应该怎么去运行这个插件呢?
那么我们就需要创建一些examples例子来运行这个代码了;
4.创建examples目录我这里创建了三套项目demo,大家直接copy就行了,这里就不详细介绍了
vite-react
vite-vue2
vite-vue3
如果你的插件需要多跑一些demo,自行创建项目即可;
那么下面我们就需要配置examples下的项目与当前根目录的插件做一个联调了(下面以examples/vite-vue3为例)。
5.配置examples/vite-vue3项目修改examples/vite-vue3/package.json
{ ..."devDependencies":{ ..."vite":"link:../../node_modules/vite","vite-plugin-template":"link:../../"}}上面意思就是说:
要把examples/vite-vue3项目中的vite版本与根目录vite-plugin-template的版本一致;
同时要把examples/vite-vue3项目中的vite-plugin-template指向你当前根目录所开发的插件;
引入插件:examples/vite-vue3/vite.config.ts
importtemplatefrom'vite-plugin-template';exportdefaultdefineConfig({ ...plugins:[vue(),template()],...});安装:cdexamples/vite-vue3&&pnpminstall
cdexamples/vite-vue3&&pnpminstall注意:examples/vite-vue2和examples/vite-react的配置与这一致
思考:
到这里,我们再思考一下,我们把examples/vite-vue3中的项目配置好了,但是我们应该怎么去运行呢?
直接去examples/vite-vue3目录下运行pnpmrunbuild或者pnpmrundev?
这样显然是不能运行成功的,因为我们的根目录下的src/index.ts是没法直接运行的,所以我们需要把.ts文件转义成.js文件;
那么我们怎么处理呢?
那么我们不得不去试着用用一个轻小且无需配置的工具tsup了。
6.安装tsup配置运行命令tsup是一个轻小且无需配置的,由esbuild支持的构建工具;
同时它可以直接把.ts、.tsx转成不同格式esm、cjs、iife的工具;
安装tsup
pnpmitypescript@types/node-D0在根目录下的package.json中配置
pnpmitypescript@types/node-D.开发环境运行开发环境运行:实时监听文件修改后重新打包(热更新)
pnpmitypescript@types/node-D2运行examples中的任意一个项目(以vite-vue3为例)
pnpmitypescript@types/node-D3注意:
如果你的插件只会在build时运行,那就设置"example:vue3":"cdexamples/vite-vue3&&pnpmrunbuild";
反之就运行pnpmrundev
输出:
到这里你就可以边开发边运行了,尤雨溪看了都说爽歪歪~
8.发布安装bumpp添加版本控制与tag
pnpmitypescript@types/node-D4配置package.json
pnpmitypescript@types/node-D5开发完插件后运行发布
pnpmitypescript@types/node-D6那么到这里,我们的vite插件模板就已经写好了,大家可以直接克隆vite-plugin-template模板使用;
如果你对vite的插件钩子和实现一个真正的vite插件感兴趣可以继续往下面看;
vite的插件钩子hooks们1.vite独有的钩子enforce:值可以是pre?或?post,pre会较于post先执行;
apply:值可以是build或serve?亦可以是一个函数,指明它们仅在build或serve模式时调用;
config(config,env):可以在vite被解析之前修改vite的相关配置。钩子接收原始用户配置config和一个描述配置环境的变量env;
configResolved(resolvedConfig):在解析vite配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它很有用。
configureServer(server):主要用来配置开发服务器,为dev-server(connect应用程序)添加自定义的中间件;
transformIndexHtml(html):转换index.html的专用钩子。钩子接收当前的HTML字符串和转换上下文;
handleHotUpdate(ctx):执行自定义HMR更新,可以通过ws往客户端发送自定义的事件;
2.vite与rollup的通用钩子之构建阶段options(options):在服务器启动时被调用:获取、操纵Rollup选项,严格意义上来讲,它执行于属于构建阶段之前;
buildStart(options):在每次开始构建时调用;
resolveId(source,importer,options):在每个传入模块请求时被调用,创建自定义确认函数,可以用来定位第三方依赖;
load(id):在每个传入模块请求时被调用,可以自定义加载器,可用来返回自定义的内容;
transform(code,id):在每个传入模块请求时被调用,主要是用来转换单个模块;
buildEnd():在构建阶段结束后被调用,此处构建结束只是代表所有模块转义完成;
3.vite与rollup的通用钩子之输出阶段outputOptions(options):接受输出参数;
renderStart(outputOptions,inputOptions):每次bundle.generate和bundle.write调用时都会被触发;
augmentChunkHash(chunkInfo):用来给chunk增加hash;
renderChunk(code,chunk,options):转译单个的chunk时触发。rollup输出每一个chunk文件的时候都会调用;
generateBundle(options,bundle,isWrite):在调用bundle.write之前立即触发这个hook;
writeBundle(options,bundle):在调用bundle.write后,所有的chunk都写入文件后,最后会调用一次writeBundle;
closeBundle():在服务器关闭时被调用
4.插件钩子函数hooks的执行顺序(如下图)5.插件的执行顺序别名处理Alias
用户插件设置enforce:'pre'
vite核心插件
用户插件未设置enforce
vite构建插件
用户插件设置enforce:'post'
vite构建后置插件(minify,manifest,reporting)
手撸一个vite插件下面以vite打包进度条插件为例;
插件地址:github如果您觉得不错欢迎star?
该插件已被vite官方收集至官方文档:链接地址
因为文章的重点不在于这个插件的详细实现过程,所以本文只会贴上源代码供大家参考,详细介绍会在下一篇文章中讲解,请大家拭目以待吧!
inde.ts
pnpmitypescript@types/node-D7cache.ts
pnpmitypescript@types/node-D8最后该系列会是一个持续更新系列,关于整个《Vite从入门到精通》专栏,我主要会从如下图几个方面讲解,请大家拭目以待吧!!!
宝贝们,都看到这里了,要不点个赞呗?
原文:/post/Vite 热更新(HMR)原理了解一下
在开发过程中,我们经常会遇到代码更新需求,尤其是在使用Vite进行项目开发时。Vite在开发环境和生产环境的资源处理方式有所区别,特别是在开发环境中,Vite通过原生ESM方式提供源码,并利用浏览器接管了部分打包程序的工作。这种设计有助于提高开发效率,尤其是代码修改后的即时反馈。然而,如何在不刷新页面的情况下进行代码替换呢?这就涉及到HMR(Hot Module Replacement)原理。
在开发环境中,为了实现HMR,我们需要启动一个Dev Server。这个服务器会监听代码的变动,并在代码更新时进行相应的处理,避免了整个页面的重新加载。在Vite的配置文件vite.config.ts中,`server`字段就用于配置这个Dev Server。
HMR允许我们在不刷新页面的情况下更新代码,无论是编辑组件标记还是调整样式,这些更改都能立即反映在浏览器中,从而提供更快的代码交互和更好的开发体验。在生产环境中,Vite则会利用Rollup对代码进行打包处理,配合tree-shaking、懒加载和chunk分割,为浏览器提供高效的代码资源。
当我们编辑文件并保存后,HMR便开始工作。文件系统监视器会检测到更改并将文件路径传递给下一步处理。接下来,Vite开发服务器使用这个路径找到相关的模块,并将其传递给插件的handleHotUpdate()钩子进行进一步处理。这个过程可能包括过滤、扩展模块数组等操作,最终确定需要更新的模块及其导入者。
在处理编辑后的模块时,Vite会将最终更新的模块数组及其导入者递归失效,即移除这些模块的转换代码,并附加一个失效时间戳,这将用于客户端的下一个请求中获取新模块。之后,更新的模块数组将通过HMR传播,这个过程的核心在于从更新的模块开始,向四周扩散,直到找到与该模块相关的所有信息,形成一个“HMR边界”。如果所有更新的模块都在这个边界内,Vite开发服务器将通知客户端接受的模块执行HMR更新。如果有些模块不在边界内,则会导致完整的页面重新加载。
HMR客户端在Vite应用中扮演着关键角色,它负责与Vite开发服务器建立WebSocket连接,监听来自服务器的HMR载荷,提供并触发HMR API,以及将任何事件发送回Vite开发服务器。在客户端初始化时,会建立WebSocket连接,并处理来自服务器的信息,如HMR传播结果、HMR更新等。
当HMR更新实际发生时,Vite将找到相应的模块,并调用其import.meta.hot.accept()回调。这个回调允许模块对自身进行更新处理。在客户端处理过程中,会根据路径匹配规则通知拥有者路径接受路径更新,从而触发正确的回调函数。此外,客户端还需要确保正确处理旧模块,使用import.meta.hot.dispose()函数,并在导入新模块前确保执行旧模块的修剪处理。
在处理HMR修剪时,Vite在导入分析阶段内部处理HMR修剪。当一个模块不再被其他模块导入时,Vite开发服务器会向客户端发送一个裁剪模块的指令。此外,客户端还可以监听并处理HMR事件,以及通过import.meta.hot.data共享数据。
总之,Vite通过高效的开发服务器配置和HMR机制,实现了在不刷新页面的情况下进行代码更新,显著提升了开发效率。这一过程包括模块替换、HMR更新、客户端处理、修剪代码和事件监听等多个关键步骤,共同构成了Vite热更新的完整流程。
前端新工具--vite从入门到实战(一)
近期,尤雨溪在B站直播中介绍了一款名为vite的前端开发工具。这款工具利用了浏览器自带的import机制,使得无论项目大小,都能实现快速启动。我对源码进行了深入研究,并在《前端会客厅》节目中得到了尤大亲自讲解的设计思路,从而有了更深刻的感悟。 与尤大面对面交流vue3的设计思路,让我收获颇丰。最近,我也成为了vue3的contributor,希望能在下半年为vue生态贡献更多的代码。 补充实战 关于vite的实战操作,可以参考github上的vite项目:github.com/vitejs/vite 原理 接下来,我们来看一下vite的代码结构。它一如既往地保持精简风格。以index和main为例,它们利用了浏览器自带的import机制。当浏览器识别type="module"引入js文件时,内部的import会发起一个网络请求,尝试获取该文件。 为了演示方便,我们先清空main.js,然后在目录中新建util.js。此时,会出现一个小报错。vite的任务就是使用koa启动一个work,第一步搞定,支持了import底层的js文件。 通过以上步骤,你应该对vite为什么快有一个初步的认识。这是因为vite天生支持按需加载,告别了冗长的webpack打包过程。 第三方库 我们不能满足于此,因为不可能所有模块都自己编写。例如,我们使用的vue是从npm引入的,确切地说,是从node_module引入的。因此,我们需要修改main.js。 不出意外,会报错。我们需要解决两个问题:1. 不是合法的相对路径,浏览器报错;2. 无法解析import语句,因为路径不正确。 为了解决这个问题,我们需要对main.js中返回的内容进行重写,并添加一个规定:将import from后面不是上面三个符号开头的路径,加上/@module/前缀。 接下来,我们需要支持@module的前缀,解析url时添加一个判断即可。主要逻辑是去node_module中查找文件,并返回用rewriteImport包重写后的结果。 然后,会报一个错误,说明模块重写已完成。接下来,我们需要支持@module的前缀。 接下来,我们将讲解vite如何实现热更新,敬请期待。