vue3+vite插件开发

插件开发目的:由于我司使用的前端技术栈为vue3+ts+vite2.X+axios,在前端代码框架设计初期,做了把axios挂载到proxy对象上的操作,具体可见我的另一篇文章vue3+TS自动化封装全局api_ts 封装+腾讯位置api-CSDN博客

现在可以实现vue2的类似this.$api.xxx去调用接口,但是vue2源码使用的是flow来实现,并且搭配typeScript不太友好(由于装饰器语法过于复杂,这里不讨论vue2+装饰器来使用typeScript),故vue2项目没有开发webpack插件去实现代码补全

这篇文章主要介绍的是vue3+ts+vite来开发时的代码补全情况

在使用vue/react+ts开发时,我们把api挂载到全局后,例如封装好axios后需要按模块划分请求,此时会创建一个modules文件夹,里面存放各个模块的请求,当把module所有的文件都动态挂载到proxy实例上时,我们可以通过proxy.$api.文件名.请求名去发起请求

例如:proxy.$api.test_api.test()

1.把modules下所有的api挂载到proxy对象上

这里以vite2和vite4.X举例

// vite 2.X
// src/api/index.ts
// 动态加载module下所有的文件
const files = import.meta.globEager('./module/*.ts')
const models= {}
for (const key in files) {
  const keys = {}


  for (const v in files[key]) {
    Object.assign(keys, { [v]: files[key][v] })
  }
    
  models[key.replace(/(\.\/module\/|\.ts)/g, '')] = keys
}
export default models
// vite4.X以上版本
// src/api/index.ts

const models = {}

const modules = import.meta.glob('./module/*.ts')
const moduleEntries = Object.entries(module)

for (const [key, apiFetchFn] of moduleEntries) {
  try {
    const module = await apiFetchFn()
    const keys = Object.fromEntries(Object.entries(module))
    models[key.replace(/(\.\/module\/|\.ts)/g, '')] = keys
  } catch (error) {
    console.error('API挂载初始化异常:', error)
  }
}

export default models
// src/main.ts
import { createApp } from 'vue'
import api from '@/api'
const app = createApp(App)
app.config.globalProperties.$api = api
//src/xxx.vue
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()!

async function foo(){
    const res = await proxy.$api.test_api.testFetch()
}

2.为proxy使用$api添加类型提示

第一点我们已经完成把所有的请求挂载proxy上并且可以通过proxy.$api.xxx.xxx去发起请求,为proxy添加拥有$api的类型很简单,只需要在xxx.d.ts文件声明@vue/runtime-core添加类型即可

//src/global.d.ts
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $api: any
  }
}

以上我们为proxy添加了$api属性,值为any,所以我们在使用proxy是会出现$api的代码提示,如下图

3.为$api添加代码提示

众所周知,在vue+ts开发的项目中,只要全局声明了XXX.d.ts文件,并且在里面使用declare声明的类型可以在全局访问到,那么我们思路可以放在声明一个xxx.d.ts文件,该文件的key可以取api/module下面的所有文件名,值直接使用typeScript的typeof import该文件即可获取到

3.1在api文件下新建Api.d.ts文件,里面声明所需要的文件类型,如下

        这里假使module文件夹已有test_api文件

declare namespace GlobalApi {
  interface Api {
    test_api: typeof import('@/api/module/test_api')
  }
}

3.2使用$api时出现代码提示

4.如何自动生成Api.d.ts文件内容呢

我想大家第一反应肯定是写脚本去处理,当module文件下的文件变动时,重新执行脚本即可,那么如何监听到module文件夹下文件的改动呢?但是我不想手动执行脚本怎么处理,这里我们可以使用nodejs的fs模块

4.1在根目录声明一个ts文件,起名为generateApi.ts(随意)

import fs from 'fs'
import type { Plugin } from 'vite'

/**
 * @type 插件配置项
 */
interface IPluginConfig {
  /**生成的.d.ts文件名 */
  fileName: string
  /**查找的文件夹名 */
  folderName: string
}

/**
 * @method 更新Api.d.ts内容
 * @description 生成Api类型后挂载到proxy上获取proxy?.$api.xxx代码提示
 */
function updateApiDeclaration(config: IPluginConfig) {
  const { fileName, folderName } = config
  const moduleFiles = fs.readdirSync(folderName)
  const apiContent = generateApiDeclaration(moduleFiles)
  fs.writeFileSync(fileName, apiContent)
}

/**
 * @method 根据api/module文件名生成Api.d.ts内容
 * @param {string[]}  moduleFiles 文件名
 */
function generateApiDeclaration(moduleFiles: string[]) {
  const interfaceEntries = moduleFiles.map((filename) => `  ${filename.replace('.ts', '')}: typeof import('@/api/module/${filename.replace('.ts', '')}')`).join('\n  ')
  return `declare namespace GlobalApi {
  interface Api {
  ${interfaceEntries}
  }
}
`
}

/**
 * @method 使用fs观察module文件夹变动
 * @description 观察到文件夹内的文件变动后重新生成Api.d.ts文件
 */
export default function watchFolderChange(pluginConfig: IPluginConfig): Plugin {
  return {
    name: 'watch-folder-plugin',
    config(config, { mode }) {
      if (mode === 'development') {
        fs.watch(pluginConfig.folderName, (eventType) => {
          if (['change', 'rename'].includes(eventType)) {
            updateApiDeclaration(pluginConfig)
          }
        })
      }
    },
  }
}

4.2 在vite.config.ts里引入

import watchFolderPlugin from './generateApi'

export default defineConfig({
  plugins: [
     //...otherPlugins
     watchFolderPlugin({
       fileName: pathResolve('src/api/Api.d.ts'),
       folderName: pathResolve('src/api/module'),
     }),

  ],
    // ...otherConfig


})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/687868.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Mac 使用Docker安装Elasticsearch、Kibana 、ik分词器、head

安装ElasticSearch 通过docker安装es docker pull elasticsearch:7.8.1 在本地创建elasticsearch.yml文件 mkdir /Users/ky/Documents/learn/es/elasticsearch.yml 编辑yml文件内容 http: host: 0.0.0.0 xpack.security.enabled: false xpack.security.enrollment.enabled: t…

DNF手游攻略:主C职业推荐,云手机强力辅助!

在《地下城与勇士》手游中,你是否厌倦了重复刷图和无休止的手动操作?利用VMOS云手机,你可以一键解决这些烦恼,实现自动打怪、一机多开,让游戏变得更加轻松愉快。下面我们将介绍如何使用VMOS云手机,以及推荐…

图像的IO操作

代码: import cv2 as cvimport matplotlib.pyplot as plt​#读取图像img cv.imread("../data/images/zidane.jpg")​#显示图像#2.1 OpenCVcv.imshow("dili",img)cv.waitKey(0)cv.destroyAllWindows()​#2.2 matplotlibplt.imshow(img[:,:,::-…

什么是阴道菌群CST分型,不同的分型代表哪些女性健康问题

谷禾健康 人体内的各个部位,如皮肤、口腔、肠道和阴道等,都是微生物的重要栖息地,这些微生物与人体健康紧密相关,并能反映人体的疾病状态。这些部位因受基因、环境和生活方式等影响,具有独特的菌群特征。 女性生殖系统…

【css3】png图片实现动态动画

.border_style {width: 400px;height: 400px;background-color: black;margin: auto;}keyframes sprite-animation {0% {background-position: 0 0;}100% {background-position: 0 -2064px;/* 假设每个图像的宽度为100px */}}.wrj_box {width: 86px;height: 86px;background-im…

《广告数据定量分析》读书笔记之统计原理2

3.相关分析:描述的是两个数值变量间关系的强度。(两个数值型变量之间的关系) (1)图表表示:散点图 (2)衡量关系强度指标:相关系数r。 (r的取值为-1到 1&…

基础概念解析:SOCKS5代理究竟是什么?SOCKS5代理ip使用场景有哪些?

在当今数字化时代,网络安全和隐私保护已成为我们日常生活中不可忽视的问题。随着网络攻击手段的日益复杂,如何安全地访问互联网资源成为了一个亟待解决的问题。SOCKS5代理作为一种先进的网络协议,为我们提供了解决这一问题的有效方案。 本文…

从品牌的角度看老字号五芳斋如何“粽”出年轻味?

端午划着龙舟的浆又来到了我们身边,咸鸭蛋和粽子已经裹上精美的包装在货架上等待着它们的“有缘人”,其实长期以来,说起吃粽子除了“甜咸口”的辩论赛,貌似在产品上却并没有太多的创新,但近几年随着消费市场的不断创新…

【电气学习六】HART仪表与HART信号

【电气学习六】HART仪表与HART信号 学习使人快乐 文章目录 【电气学习六】HART仪表与HART信号前言一、HART仪表是什么?二、HART协议1.什么是HART协议?2.HART协议的工作原理3.HART协议的特点4.HART协议的命令格式5.无源信号与有源信号的定义6.如何采集无源…

自定义模块设置示例

CSDN 针对部分博主开放了自定义模块设置&#xff0c;我也是简单的使用了一下这个功能&#xff0c;感觉很不错&#xff0c;下面是我编写的参考代码大家可以复制下面代码来使自己的博客主页多样化。 <div class"pmusic"><iframe frameborder"no" bo…

美琳莱卡:创新消费模式引领新零售时代

公司成立时间与定位 美琳莱卡自创立之初,便以独特的视角和前瞻性的战略定位,立足于消费市场的变革前沿。公司成立于2024年,正值全球数字化浪潮蓬勃兴起,消费升级趋势日益明显之际。美琳莱卡敏锐地捕捉到这一时代机遇,将自身定位为创新消费模式的引领者,致力于通过线上线下高度…

大模型在信用卡行业的应用探索

2022年11月&#xff0c;OpenAI发布ChatGPT3.5&#xff0c;迅速引起各界广泛关注&#xff0c;引发了人工智能领域新一轮发展热潮。ChatGPT作为一款基于人工智能技术的大语言模型&#xff08;LLMs&#xff09;&#xff0c;在文本生成、对话理解、多领域知识覆盖等方面具有卓越表现…

servlet实现图片上传和下载

图片上传 前端 后端 protected void dopost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {Part filePart request.getPart("file"); // 获取上传的文件String fileName filePart.getSubmittedFileName(); …

[word] word文档字体间距怎么调整? #其他#经验分享

word文档字体间距怎么调整&#xff1f; 调整word文档字体间距的方法&#xff1a; 打开一个预先写好文字的文档。选中所有文字&#xff0c;点击字体右下角的“更多选项”。 在弹出的“字体”对话框中进入“字符间距”选项卡&#xff0c;在“间距”选项中即可设置字体间距。 设…

【机器学习】训练GNN图神经网络模型进行节点分类

1. 引言 1.1 图神经网络GNN概述 图神经网络&#xff08;Graph Neural Network&#xff0c;GNN&#xff09;是一种专门用于处理图结构数据的神经网络方法。它起源于2005年&#xff0c;当时Gori等人首次提出了GNN的概念&#xff0c;用于学习图中的节点特征以及它们之间的关系。…

mac安装nigix且配置 vue/springboot项目(本地/服务器)

一、mac安装Nigix 1. 查看是否存在 nginx 执行brew search nginx 命令查询要安装的软件是否存在 brew search nginx 2. 安装nginx brew install nginx 3. 查看版本 nginx -v 4. 查看信息 查看ngxin下载的位置以及nginx配置文件存放路径等信息 brew info nginx 下载的存…

Linux基础2-基本指令4(cp,mv,cat,tac)

上篇文章我们说到了rmdir,rm,man,echo.重定向等知识。 Linux基础1-基本指令3-CSDN博客 本文继续梳理其他基础指令 1.本章重点 1.使用cp命令拷贝文件 2.使用mv命令移动文件 3.使用cat&#xff0c;tac查看小文本文件 2.cp命令 在linux中使用cp命令来拷贝粘贴文件 cp src(原文…

Codeforces Round 951 (Div. 2) F. Kostyanych‘s Theorem(思维题 交互好题)

题目 交互题&#xff0c;n&#xff08;n<1e5&#xff09;个点的完全图&#xff0c;无向的&#xff0c;初始恰好删了n-2条边 每次询问可以输入一个d&#xff1a;? d 交互器会输出一个当前度>d的点v&#xff0c; 如果有多个这样的点&#xff0c;输出度最小的&#xff…

esp8266阿里云上线(小程序控制)

此wechatproject已上传在页面最上方 由图可见&#xff0c;项目只有两个页面&#xff0c;一个是获取该产品下的设备信息列表&#xff0c;一个是某设备对应的详情控制页面&#xff0c;由于这个项目只利用esp8266板子上自带的led&#xff0c;功能简单&#xff0c;只需要控制开关即…

传统产品经理AI产品经理

前言 随着科技的发展&#xff0c;技术的革新&#xff0c;AI技术当今已经渗入到各个行业里边&#xff0c;身处其中的产品经理也面临的新的挑战和机遇&#xff0c;下面是笔者整理分享的关于传统的产品经理如何顺应时代发展&#xff0c;成功转换成AI产品经理的相关内容&#xff0…