百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

一个由 Vue 作者尤雨溪开发的 web 开发工具—vite

liuian 2025-02-28 16:31 12 浏览


作者:木偶 淘系前端团队

转发链接:
https://mp.weixin.qq.com/s/xdg1NIZYdNQgbunVUGh38w

NO.1 vite 是什么

vite —— 一个由 vue 作者尤雨溪开发的 web 开发工具,它具有以下特点:

  1. 快速的冷启动
  2. 即时的模块热更新
  3. 真正的按需编译

从作者在微博上的发言:

Vite,一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。同时不仅有 Vue 文件支持,还搞定了热更新,而且热更新的速度不会随着模块增多而变慢。针对生产环境则可以把同一份代码用 rollup 打。虽然现在还比较粗糙,但这个方向我觉得是有潜力的,做得好可以彻底解决改一行代码等半天热更新的问题。


中可以看出 vite 主要特点是基于浏览器 native 的 ES module (
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) 来开发,省略打包这个步骤,因为需要什么资源直接在浏览器里引入即可。

基于浏览器 ES module 来开发 web 应用也不是什么新鲜事,snowpack 也基于此,不过目前此项目社区中并没有流行起来,vite 的出现也许会让这种开发方式再火一阵子。

有趣的是 vite 算是革了 webpack 的命了(生产环境用 rollup),所以 webpack 的开发者直接喊大哥了...



作者注:本文完成于 vite 早期时候,vite 部分功能和原理有更新。

NO.2 vite 的使用方式

同常见的开发工具一样,vite 提供了用 npm 或者 yarn 一建生成项目结构的方式,使用 yarn 在终端执行:

|____node_modules
|____App.vue?//?应用入口
|____index.html?//?页面入口
|____vite.config.js?//?配置文件
|____package.json

即可初始化一个 vite 项目(默认应用模板为 vue3.x),生成的项目结构十分简洁:

|____node_modules
|____App.vue?//?应用入口
|____index.html?//?页面入口
|____vite.config.js?//?配置文件
|____package.json

执行 yarn dev 即可启动应用 。

NO.3 vite 启动链路

命令解析

这部分代码在 src/node/cli.ts 里,主要内容是借助 minimist —— 一个轻量级的命令解析工具解析 npm scripts,解析的函数是 resolveOptions ,精简后的代码片段如下。

function?resolveOptions()?{
????//?command?可以是?dev/build/optimize
????if?(argv._[0])?{
????????argv.command?=?argv._[0];
????}
????return?argv;
}

拿到 options 后,会根据 options.command 的值判断是执行在开发环境需要的 runServe 命令或生产环境需要的 runBuild 命令。

if?(!options.command?||?options.command?===?'serve')?{
????runServe(options)
?}?else?if?(options.command?===?'build')?{
????runBuild(options)
?}?else?if?(options.command?===?'optimize')?{
????runOptimize(options)
?}

在 runServe 方法中,执行 server 模块的创建开发服务器方法,同样在 runBuild中执行 build 模块的构建方法。

最新的版本中还增加了 optimize 命令的支持,关于 optimize 做了什么,我们下文再说。

server

这部分代码在 src/node/server/index.ts 里,主要暴露一个 createServer 方法。

vite 使用 koa 作 web server,使用 clmloader 创建了一个监听文件改动的 watcher,同时实现了一个插件机制,将 koa-app 和 watcher 以及其他必要工具组合成一个 context 对象注入到每个 plugin 中。

context 组成如下:


plugin 依次从 context 里获取上面这些组成部分,有的 plugin 在 koa 实例添加了几个 middleware,有的借助 watcher 实现对文件的改动监听,这种插件机制带来的好处是整个应用结构清晰,同时每个插件处理不同的事情,职责更分明,

plugin

上文我们说到 plugin,那么有哪些 plugin 呢?它们分别是:

  • 用户注入的 plugins —— 自定义 plugin
  • hmrPlugin —— 处理 hmr
  • htmlRewritePlugin —— 重写 html 内的 script 内容
  • moduleRewritePlugin —— 重写模块中的 import 导入
  • moduleResolvePlugin ——获取模块内容
  • vuePlugin —— 处理 vue 单文件组件
  • esbuildPlugin —— 使用 esbuild 处理资源
  • assetPathPlugin —— 处理静态资源
  • serveStaticPlugin —— 托管静态资源
  • cssPlugin —— 处理 css/less/sass 等引用
  • ...

我们来看 plugin 的实现方式,开发一个用来拦截 json 文件 plugin 可以这么实现:

interface?ServerPluginContext?{
??root:?string
??app:?Koa
??server:?Server
??watcher:?HMRWatcher
??resolver:?InternalResolver
??config:?ServerConfig
}

type?ServerPlugin?=?(ctx:ServerPluginContext)=>?void;

const?JsonInterceptPlugin:ServerPlugin?=?({app})=>{
????app.use(async?(ctx,?next)?=>?{
??????await?next()
??????if?(ctx.path.endsWith('.json')?&&?ctx.body)?{
????????ctx.type?=?'js'
????????ctx.body?=?`export?default?json`
??????}
??})
}


vite 背后的原理都在 plugin 里,这里不再一一解释每个 plugin 的作用,会放在下文背后的原理中一并讨论。

build

这部分代码在 node/build/index.ts 中,build 目录的结构虽然与 server 相似,同样导出一个 build 方法,同样也有许多 plugin,不过这些 plugin 与 server 中的用途不一样,因为 build 使用了 rollup ,所以这些 plugin 也是为 rollup 打包的 plugin ,本文就不再多提。

NO.4 vite 运行原理

ES module

要了解 vite 的运行原理,首先要知道什么是 ES module,目前浏览器对其的支持如下:



主流的浏览器(IE11除外)均已经支持,其最大的特点是在浏览器端使用 exportimport 的方式导入和导出模块,在 script 标签里设置 type="module" ,然后使用模块内容。


??import?{?bar?}?from?'./bar.js‘

当 html 里嵌入上面的 script 标签时候,浏览器会发起 http 请求,请求 htttp server 托管的 bar.js ,在 bar.js 里,我们用 named export 导出 bar 变量,在上面的 script 中能获取到 bar 的定义。

//?bar.js?
export?const?bar?=?'bar';

在 vite 中的作用

打开运行中的 vite 项目,访问 view-source 可以发现 html 里有段这样的代码:


????import?{?createApp?}?from?'/@modules/vue'
????import?App?from?'/App.vue'
????createApp(App).mount('#app')

从这段代码中,我们能 get 到以下几点信息:

  • 从 http://localhost:3000/@modules/vue 中获取 createApp 这个方法
  • 从 http://localhost:3000/App.vue 中获取应用入口
  • 使用 createApp 创建应用并挂载节点

createApp 是 vue3.X 的 api,只需知道这是创建了 vue 应用即可,vite 利用 ES module,把 “构建 vue 应用” 这个本来需要通过 webpack 打包后才能执行的代码直接放在浏览器里执行,这么做是为了:

  1. 去掉打包步骤
  2. 实现按需加载

去掉打包步骤

打包的概念是开发者利用打包工具将应用各个模块集合在一起形成 bundle,以一定规则读取模块的代码——以便在不支持模块化的浏览器里使用。

为了在浏览器里加载各模块,打包工具会借助胶水代码用来组装各模块,比如 webpack 使用 map 存放模块 id 和路径,使用 __webpack_require__ 方法获取模块导出。

vite 利用浏览器原生支持模块化导入这一特性,省略了对模块的组装,也就不需要生成 bundle,所以打包这一步就可以省略了。

实现按需打包

前面说到,webpack 之类的打包工具会将各模块提前打包进 bundle 里,但打包的过程是静态的——不管某个模块的代码是否执行到,这个模块都要打包到 bundle 里,这样的坏处就是随着项目越来越大打包后的 bundle 也越来越大。

开发者为了减少 bundle 大小,会使用动态引入 import() 的方式异步的加载模块( 被引入模块依然需要提前打包),又或者使用 tree shaking 等方式尽力的去掉未引用的模块,然而这些方式都不如 vite 的优雅,vite 可以只在需要某个模块的时候动态(借助 import() )的引入它,而不需要提前打包,虽然只能用在开发环境,不过这就够了。

vite 如何处理 ESM

既然 vite 使用 ESM 在浏览器里使用模块,那么这一步究竟是怎么做的?

上文提到过,在浏览器里使用 ES module 是使用 http 请求拿到模块,所以 vite 必须提供一个 web server 去代理这些模块,上文中提到的 koa 就是负责这个事情,vite 通过对请求路径的劫持获取资源的内容返回给浏览器,不过 vite 对于模块导入做了特殊处理。

@modules 是什么?

通过工程下的 index.html 和开发环境下的 html 源文件对比,发现 script 标签里的内容发生了改变,由


????import?{?createApp?}?from?'vue'
????import?App?from?'/App.vue'
????createApp(App).mount('#app')

变成了

????import?{?createApp?}?from?'/@modules/vue'
????import?App?from?'/App.vue'
????createApp(App).mount('#app')
vite 对 import 都做了一层处理,其过程如下:
  1. 在 koa 中间件里获取请求 body
  2. 通过 es-module-lexer 解析资源 ast 拿到 import 的内容
  3. 判断 import 的资源是否是绝对路径,绝对视为 npm 模块
  4. 返回处理后的资源路径:"vue" => "/@modules/vue"

这部分代码在 serverPluginModuleRewrite 这个 plugin 中,

为什么需要 @modules?

如果我们在模块里写下以下代码的时候,浏览器中的 esm 是不可能获取到导入的模块内容的:

import?vue?from?'vue'

因为 vue 这个模块安装在 node_modules 里,以往使用 webpack,webpack遇到上面的代码,会帮我们做以下几件事

  • 获取这段代码的内容
  • 解析成 AST
  • 遍历 AST 拿到 import 语句中的包的名称
  • 使用 enhanced-resolve 拿到包的实际地址进行打包,


但是浏览器中 ESM 无法直接访问项目下的 node_modules,所以 vite 对所有 import 都做了处理,用带有 @modules 的前缀重写它们。

从另外一个角度来看这是非常比较巧妙的做法,把文件路径的 rewrite 都写在同一个 plugin 里,这样后续如果加入更多逻辑,改动起来不会影响其他 plugin,其他 plugin 拿到资源路径都是 @modules ,比如说后续可能加入 alias 的配置:就像 webpack alias 一样:可以将项目里的本地文件配置成绝对路径的引用。

怎么返回模块内容

在下一个 koa middleware 中,用正则匹配到路径上带有 @modules 的资源,再通过 require('xxx') 拿到 包的导出返回给浏览器。

以往使用 webpack 之类的打包工具,它们除了将模块组装到一起形成 bundle,还可以让使用了不同模块规范的包互相引用,比如:


ES module (esm) 导入 cjs

CommonJS (cjs) 导入 esm

dynamic import 导入 esm

dynamic import 导入 cjs

关于 es module 的坑可以看这篇文章(
https://zhuanlan.zhihu.com/p/40733281)。


起初在 vite 还只是为 vue3.x 设计的时候,对 vue esm 包是经过特殊处理的,比如:需要 @vue/runtime-dom 这个包的内容,不能直接通过 require('@vue/runtime-dom')得到,而需要通过 require('@
vue/runtime-dom/dist/runtime-dom.esm-bundler.js' 的方式,这样可以使得 vite 拿到符合 esm 模块标准的 vue 包。

目前社区中大部分模块都没有设置默认导出 esm,而是导出了 cjs 的包,既然 vue3.0 需要额外处理才能拿到 esm 的包内容,那么其他日常使用的 npm 包是不是也同样需要支持?答案是肯定的,目前在 vite 项目里直接使用 lodash 还是会报错的。



不过 vite 在最近的更新中,加入了 optimize 命令,这个命令专门为解决模块引用的坑而开发,例如我们要在 vite 中使用 lodash,只需要在 vite.config.js (vite 配置文件)中,配置 optimizeDeps 对象,在 include 数组中添加 lodash。

//?vite.config.js
module.exports?=?{
??optimizeDeps:?{
????include:?["lodash"]
??}
}
这样 vite 在执行 runOptimize 的时候中会使用 roolup 对 lodash 包重新编译,将编译成符合 esm 模块规范的新的包放入 node_modules 下的 .vite_opt_cache 中,然后配合 resolver 对 lodash 的导入进行处理:使用编译后的包内容代替原来 lodash 的包的内容,这样就解决了 vite 中不能使用 cjs 包的问题,这部分代码在  depOptimizer.ts 里。

不过这里还有个问题,由于在 depOptimizer.ts 中,vite 只会处理在项目下 package.json 里的 dependencies 里声明好的包进行处理,所以无法在项目里使用

import?pick?from?'lodash/pick'

的方式单使用 pick 方法,而要使用

import?lodash?from?'lodash'

lodash.pick()

的方式,这可能在生产环境下使用某些包的时候对 bundle 的体积有影响。

返回模块的内容的代码在:
serverPluginModuleResolve.ts 这个 plugin 中。

vite 如何编译模块

最初 vite 为 vue3.x 开发,所以这里的编译指的是编译 vue 单文件组件,其他 es 模块可以直接导入内容。

SFC

vue 单文件组件(简称 SFC) 是 vue 的一个亮点,前端届对 SFC 褒贬不一,个人看来,SFC 是利大于弊的,虽然 SFC 带来了额外的开发工作量,比如为了解析 template 要写模板解析器,还要在 SFC 中解析出逻辑和样式,在 vscode 里要写 vscode 插件,在 webpack 里要写 vue-loader,但是对于使用方来说可以在一个文件里可以同时写 template、js、style,省了各文件互相跳转。

与 vue-loader 相似,vite 在解析 vue 文件的时候也要分别处理多次,我们打开浏览器的 network,可以看到:

1 个请求的 query 中什么都没有,另 2 个请求分别通过在 query 里指定了 type 为 style 和 template。

先来看看如何将一个 SFC 变成多个请求,我们从第一次请求开始分析,简化后的代码如下:

function?vuePlugin({app}){
??app.use(async?(ctx,?next)?=>?{
????if?(!ctx.path.endsWith('.vue')?&&?!ctx.vue)?{
??????return?next()
????}

????const?query?=?ctx.query
????//?获取文件名称
????let?filename?=?resolver.requestToFile(publicPath)

????//?解析器解析?SFC
????const?descriptor?=?await?parseSFC(root,?filename,?ctx.body)
????if?(!descriptor)?{
??????ctx.status?=?404
??????return
????}
????//?第一次请求?.vue
????if?(!query.type)?{
??????if?(descriptor.script?&&?descriptor.script.src)?{
????????filename?=?await?resolveSrcImport(descriptor.script,?ctx,?resolver)
??????}
??????ctx.type?=?'js'
??????//?body?返回解析后的代码
??????ctx.body?=?await?compileSFCMain(descriptor,?filename,?publicPath)
????}
????
????//?...
}

在 compileSFCMain 中是一段长长的 generate 代码:

function?compileSFCMain(descriptor,?filePath:?string,?publicPath:?string)?{
??let?code?=?''
??if?(descriptor.script)?{
????let?content?=?descriptor.script.content
????code?+=?content.replace(`export?default`,?'const?__script?=')
??}?else?{
????code?+=?`const?__script?=?{}`
??}

??if?(descriptor.styles)?{
????code?+=?`\nimport?{?updateStyle?}?from?"${hmrClientId}"\n`
????descriptor.styles.forEach((s,?i)?=>?{
??????const?styleRequest?=?publicPath?+?`?type=style&index=${i}`
??????code?+=?`\nupdateStyle("${id}-${i}",?${JSON.stringify(styleRequest)})`
????})
????if?(hasScoped)?{
??????code?+=?`\n__script.__scopeId?=?"data-v-${id}"`
????}
??}

??if?(descriptor.template)?{
????code?+=?`\nimport?{?render?as?__render?}?from?${JSON.stringify(
??????publicPath?+?`?type=template`
????)}`
????code?+=?`\n__script.render?=?__render`
??}
??code?+=?`\n__script.__hmrId?=?${JSON.stringify(publicPath)}`
??code?+=?`\n__script.__file?=?${JSON.stringify(filePath)}`
??code?+=?`\nexport?default?__script`
??return?code
}

直接看 generate 后的代码:

import?{?updateStyle?}?from?"/vite/hmr"
updateStyle("c44b8200-0",?"/App.vue?type=style&index=0")
__script.__scopeId?=?"data-v-c44b8200"
import?{?render?as?__render?}?from?"/App.vue?type=template"
__script.render?=?__render
__script.__hmrId?=?"/App.vue"
__script.__file?=?"/Users/muou/work/playground/vite-app/App.vue"
export?default?__script

出现了 vite/hmr 的导入,vite/hmr 具体内容我们下文再分析,从这段代码中可以看到,对于 style vite 使用 updateStyle 这个方法处理,updateStyle 内容非常简单,这里就不贴代码了,就做了 1 件事:通过创建 style 元素,设置了它的 innerHtml 为 css 内容。

这两种方式都会使得浏览器发起 http 请求,这样就能被 koa 中间件捕获到了,所以就形成了上文我们看到的:对一个 .vue 文件处理三次的情景。

这部分代码在:serverPluginVue 这个 plugin 里。

css

如果在 vite 项目里引入一个 sass 文件会怎么样?

最初 vite 只是为 vue 项目开发,所以并没有对 css 预编译的支持,不过随着后续的几次大更新,在 vite 项目里使用 sass/less 等也可以跟使用 webpack 的时候一样优雅了,只需要安装对应的 css 预处理器即可。

在 cssPlugin 中,通过正则:/(.+).(less|sass|scss|styl|stylus)$/ 判断路径是否需要 css 预编译,如果命中正则,就借助 cssUtils 里的方法借助 postcss 对要导入的 css 文件编译。

vite 热更新的实现

上文中出现了 vite/hmr ,这就是 vite 处理热更新的关键,在 serverPluginHmr plugin 中,对于 path 等于 vite/hmr 做了一次判断:

?app.use(async?(ctx,?next)?=>?{
??if?(ctx.path?===?'/vite/hmr')?{
??????ctx.type?=?'js'
??????ctx.status?=?200
??????ctx.body?=?hmrClient
??}
?}

hmrClient 是 vite 热更新的客户端代码,需要在浏览器里执行,这里先来说说通用的热更新实现,热更新一般需要四个部分:

  1. 首先需要 web 框架支持模块的 rerender/reload
  2. 通过 watcher 监听文件改动
  3. 通过 server 端编译资源,并推送新模块内容给 client 。
  1. client 收到新的模块内容,执行 rerender/reload

vite 也不例外同样有这四个部分,其中客户端代码在:client.ts 里,服务端代码在 serverPluginHmr 里,对于 vue 组件的更新,通过 vue3.x 中的 HMRRuntime 处理的。

client 端

在 client 端, WebSocket 监听了一些更新的类型,然后分别处理,它们是:

  • vue-reload —— vue 组件更新:通过 import 导入新的 vue 组件,然后执行 HMRRuntime.reload
  • vue-rerender —— vue template 更新:通过 import 导入新的 template ,然后执行 HMRRuntime.rerender
  • vue-style-update —— vue style 更新:直接插入新的 stylesheet
  • style-update —— css 更新:document 插入新的 stylesheet
  • style-remove —— css 移除:document 删除 stylesheet
  • js-update —— js 更新:直接执行
  • full-reload —— 页面 roload:使用 window.reload 刷新页面

server 端

在 server 端,通过 watcher 监听页面改动,根据文件类型判断是 js Reload 还是 Vue Reload:

?watcher.on('change',?async?(file)?=>?{
????const?timestamp?=?Date.now()
????if?(file.endsWith('.vue'))?{
??????handleVueReload(file,?timestamp)
????}?else?if?(
??????file.endsWith('.module.css')?||
??????!(file.endsWith('.css')?||?cssTransforms.some((t)?=>?t.test(file,?{})))
????)?{
??????//?everything?except?plain?.css?are?considered?HMR?dependencies.
??????//?plain?css?has?its?own?HMR?logic?in?./serverPluginCss.ts.
??????handleJSReload(file,?timestamp)
????}
??})

在 handleVueReload 方法里,会使用解析器拿到当前文件的 template/script/style ,并且与缓存里的上一次解析的结果进行比较,如果 template 发生改变就执行 vue-rerender,如果 style 发生改变就执行 vue-style-update,简化后的逻辑如下:

async?function?handleVueReload(????file
????timestamp,
????content
??)?{
????//?获取缓存
????const?cacheEntry?=?vueCache.get(file)

????//?解析?vue?文件?????????????????????????????????
????const?descriptor?=?await?parseSFC(root,?file,?content)
????if?(!descriptor)?{
??????//?read?failed
??????return
????}
????//?拿到上一次解析结果
????const?prevDescriptor?=?cacheEntry?&&?cacheEntry.descriptor
????
????//?设置刷新变量
????let?needReload?=?false?//?script?改变标记
????let?needCssModuleReload?=?false?//?css?改变标记
????let?needRerender?=?false?//?template?改变标记

????//?判断?script?是否相同
????if?(!isEqual(descriptor.script,?prevDescriptor.script))?{
??????needReload?=?true
????}

?????//?判断?template?是否相同
????if?(!isEqual(descriptor.template,?prevDescriptor.template))?{
??????needRerender?=?true
????}
??????
????//?通过?send?发送?socket
????if?(needRerender){
??????send({
????????type:?'vue-rerender',
????????path:?publicPath,
????????timestamp
??????})??
????}
??}

handleJSReload 方法则是根据文件路径引用,判断被哪个 vue 组件所依赖,如果未找到 vue 组件依赖,则判断页面需要刷新,否则走组件更新逻辑,这里就不贴代码了。

整体代码在 client.ts 和 serverPluginHmr.ts 里。

NO.5 结语

本文分析了 vite 的启动链路以及背后的部分原理,虽然在短时间内 vite 不会替代 webpack,但是能够看到社区中多了一种方案还是很兴奋的,这也是我写下这篇文章的原因。

vite 更新的实在太快了,佩服尤大的勤奋和开源精神,短短一个月就加入了诸如 css 预编译/react支持/通用 hmr 的支持,由于篇幅有限本文不再一一介绍这些新特性,这些新的特性等待读者朋友们自行去探讨了。

推荐Vue学习资料文章:

是什么让我爱上了Vue.js

1.1万字深入细品Vue3.0源码响应式系统笔记「上」

1.1万字深入细品Vue3.0源码响应式系统笔记「下」

「实践」Vue 数据更新7 种情况汇总及延伸解决总结

尤大大细说Vue3 的诞生之路「译」

提高10倍打包速度工具Snowpack 2.0正式发布,再也不需要打包器

大厂Code Review总结Vue开发规范经验「值得学习」

Vue3 插件开发详解尝鲜版「值得收藏」

带你五步学会Vue SSR

记一次Vue3.0技术干货分享会

Vue 3.x 如何有惊无险地快速入门「进阶篇」

「干货」微信支付前后端流程整理(Vue+Node)

带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」

「干货」Vue+高德地图实现页面点击绘制多边形及多边形切割拆分

「干货」Vue+Element前端导入导出Excel

「实践」Deno bytes 模块全解析

细品pdf.js实践解决含水印、电子签章问题「Vue篇」

基于vue + element的后台管理系统解决方案

Vue仿蘑菇街商城项目(vue+koa+mongodb)

基于 electron-vue 开发的音乐播放器「实践」

「实践」Vue项目中标配编辑器插件Vue-Quill-Editor

基于 Vue 技术栈的微前端方案实践

消息队列助你成为高薪 Node.js 工程师

Node.js 中的 stream 模块详解

「干货」Deno TCP Echo Server 是怎么运行的?

「干货」了不起的 Deno 实战教程

「干货」通俗易懂的Deno 入门教程

Deno 正式发布,彻底弄明白和 node 的区别

「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台

「实践」深入对比 Vue 3.0 Composition API 和 React Hooks

前端网红框架的插件机制全梳理(axios、koa、redux、vuex)

深入Vue 必学高阶组件 HOC「进阶篇」

深入学习Vue的data、computed、watch来实现最精简响应式系统

10个实例小练习,快速入门熟练 Vue3 核心新特性(一)

10个实例小练习,快速入门熟练 Vue3 核心新特性(二)

教你部署搭建一个Vue-cli4+Webpack移动端框架「实践」

2020前端就业Vue框架篇「实践」

详解Vue3中 router 带来了哪些变化?

Vue项目部署及性能优化指导篇「实践」

Vue高性能渲染大数据Tree组件「实践」

尤大大细品VuePress搭建技术网站与个人博客「实践」

10个Vue开发技巧「实践」

是什么导致尤大大选择放弃Webpack?【vite 原理解析】

带你了解 vue-next(Vue 3.0)之 小试牛刀【实践】

带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】

实践Vue 3.0做JSX(TSX)风格的组件开发

一篇文章教你并列比较React.js和Vue.js的语法【实践】

手拉手带你开启Vue3世界的鬼斧神工【实践】

深入浅出通过vue-cli3构建一个SSR应用程序【实践】

怎样为你的 Vue.js 单页应用提速

聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总

【新消息】Vue 3.0 Beta 版本发布,你还学的动么?

Vue真是太好了 壹万多字的Vue知识点 超详细!

Vue + Koa从零打造一个H5页面可视化编辑器——Quark-h5

深入浅出Vue3 跟着尤雨溪学 TypeScript 之 Ref 【实践】

手把手教你深入浅出vue-cli3升级vue-cli4的方法

Vue 3.0 Beta 和React 开发者分别杠上了

手把手教你用vue drag chart 实现一个可以拖动 / 缩放的图表组件

Vue3 尝鲜

总结Vue组件的通信

Vue 开源项目 TOP45

2020 年,Vue 受欢迎程度是否会超过 React?

尤雨溪:Vue 3.0的设计原则

使用vue实现HTML页面生成图片

实现全栈收银系统(Node+Vue)(上)

实现全栈收银系统(Node+Vue)(下)

vue引入原生高德地图

Vue合理配置WebSocket并实现群聊

多年vue项目实战经验汇总

vue之将echart封装为组件

基于 Vue 的两层吸顶踩坑总结

Vue插件总结【前端开发必备】

Vue 开发必须知道的 36 个技巧【近1W字】

构建大型 Vue.js 项目的10条建议

深入理解vue中的slot与slot-scope

手把手教你Vue解析pdf(base64)转图片【实践】

使用vue+node搭建前端异常监控系统

推荐 8 个漂亮的 vue.js 进度条组件

基于Vue实现拖拽升级(九宫格拖拽)

手摸手,带你用vue撸后台 系列二(登录权限篇)

手摸手,带你用vue撸后台 系列三(实战篇)

前端框架用vue还是react?清晰对比两者差异

Vue组件间通信几种方式,你用哪种?【实践】

浅析 React / Vue 跨端渲染原理与实现

10个Vue开发技巧助力成为更好的工程师

手把手教你Vue之父子组件间通信实践讲解【props、$ref 、$emit】

1W字长文+多图,带你了解vue的双向数据绑定源码实现

深入浅出Vue3 的响应式和以前的区别到底在哪里?【实践】

干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)

基于Vue/VueRouter/Vuex/Axios登录路由和接口级拦截原理与实现

手把手教你D3.js 实现数据可视化极速上手到Vue应用

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【上】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】

吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【下】

Vue3.0权限管理实现流程【实践】

后台管理系统,前端Vue根据角色动态设置菜单栏和路由

作者:木偶 淘系前端团队

转发链接:
https://mp.weixin.qq.com/s/xdg1NIZYdNQgbunVUGh38w

相关推荐

2023年最新微信小程序抓包教程(微信小程序 抓包)

声明:本公众号大部分文章来自作者日常学习笔记,部分文章经作者授权及其他公众号白名单转载。未经授权严禁转载。如需转载,请联系开百。请不要利用文章中的相关技术从事非法测试。由此产生的任何不良后果与文...

测试人员必看的软件测试面试文档(软件测试面试怎么说)

前言又到了毕业季,我们将会迎来许多需要面试的小伙伴,在这里呢笔者给从事软件测试的小伙伴准备了一份顶级的面试文档。1、什么是bug?bug由哪些字段(要素)组成?1)将在电脑系统或程序中,隐藏着的...

复活,视频号一键下载,有手就会,长期更新(2023-12-21)

视频号下载的话题,也算是流量密码了。但也是比较麻烦的问题,频频失效不说,使用方法也难以入手。今天,奶酪就来讲讲视频号下载的新方案,更关键的是,它们有手就会有用,最后一个方法万能。实测2023-12-...

新款HTTP代理抓包工具Proxyman(界面美观、功能强大)

不论是普通的前后端开发人员,还是做爬虫、逆向的爬虫工程师和安全逆向工程,必不可少会使用的一种工具就是HTTP抓包工具。说到抓包工具,脱口而出的肯定是浏览器F12开发者调试界面、Charles(青花瓷)...

使用Charles工具对手机进行HTTPS抓包

本次用到的工具:Charles、雷电模拟器。比较常用的抓包工具有fiddler和Charles,今天讲Charles如何对手机端的HTTS包进行抓包。fiddler抓包工具不做讲解,网上有很多fidd...

苹果手机下载 TikTok 旧版本安装包教程

目前苹果手机能在国内免拔卡使用的TikTok版本只有21.1.0版本,而AppStore是高于21.1.0版本,本次教程就是解决如何下载TikTok旧版本安装包。前期准备准备美区...

【0基础学爬虫】爬虫基础之抓包工具的使用

大数据时代,各行各业对数据采集的需求日益增多,网络爬虫的运用也更为广泛,越来越多的人开始学习网络爬虫这项技术,K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章,为实现从易到难全方位覆盖,特设【0基础学爬...

防止应用调试分析IP被扫描加固实战教程

防止应用调试分析IP被扫描加固实战教程一、概述在当今数字化时代,应用程序的安全性已成为开发者关注的焦点。特别是在应用调试过程中,保护应用的网络安全显得尤为重要。为了防止应用调试过程中IP被扫描和潜在的...

一文了解 Telerik Test Studio 测试神器

1.简介TelerikTestStudio(以下称TestStudio)是一个易于使用的自动化测试工具,可用于Web、WPF应用的界面功能测试,也可以用于API测试,以及负载和性能测试。Te...

HLS实战之Wireshark抓包分析(wireshark抓包总结)

0.引言Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接...

信息安全之HTTPS协议详解(加密方式、证书原理、中间人攻击 )

HTTPS协议详解(加密方式、证书原理、中间人攻击)HTTPS协议的加密方式有哪些?HTTPS证书的原理是什么?如何防止中间人攻击?一:HTTPS基本介绍:1.HTTPS是什么:HTTPS也是一个...

Fiddler 怎么抓取手机APP:抖音、小程序、小红书数据接口

使用Fiddler抓取移动应用程序(APP)的数据接口需要进行以下步骤:首先,确保手机与计算机连接在同一网络下。在计算机上安装Fiddler工具,并打开它。将手机的代理设置为Fiddler代理。具体方...

python爬虫教程:教你通过 Fiddler 进行手机抓包

今天要说说怎么在我们的手机抓包有时候我们想对请求的数据或者响应的数据进行篡改怎么做呢?我们经常在用的手机手机里面的数据怎么对它抓包呢?那么...接下来就是学习python的正确姿势我们要用到一款强...

Fiddler入门教程全家桶,建议收藏

学习Fiddler工具之前,我们先了解一下Fiddler工具的特点,Fiddler能做什么?如何使用Fidder捕获数据包、修改请求、模拟客户端向服务端发送请求、实施越权的安全性测试等相关知识。本章节...

fiddler如何抓取https请求实现手机抓包(100%成功解决)

一、HTTP协议和HTTPS协议。(1)HTTPS协议=HTTP协议+SSL协议,默认端口:443(2)HTTP协议(HyperTextTransferProtocol):超文本传输协议。默认...