vscode插件开发之Swagger生成Ts 原创

不辞冰雪lzl
发布于 2022-11-24 11:55
浏览
0收藏

vscode插件开发之Swagger生成Ts

当后端同学给到我们Swagger接口文档的时候,是不是在为要写接口类型烦恼,为了偷懒,那么就any吧。any一时爽,同事泪两行。为了高质量的偷懒,来开发个插件leizl.swagger-generate-ts

日常案例

  • 摆在我们前面的有一份接口平台地址和我们需要用到的接口名称。日常开发中我们一般需要做以下事情。
  • 写一份类型声明文件xx.d.ts
export interface PropertyValueAddRequest {
  /**
   * Format: int64
   * @description 属性Id
   */
  propId?: number;
  /** @description 属性值列表 */
  propValueList?: string[];
}

export interface ApiResultboolean {
  code?: string;
  data?: boolean;
  msg?: string;
  success?: boolean;
  traceId?: string;
}
  • 写一份service请求代码
import { post } from '@/utils/request';
import {
  PropertyValueAddRequest,
  ApiResultboolean,
} from '@definitions/gmp-product-library-portal/library/manage/property';

export function addPropValue(
  data: PropertyValueAddRequest,
): Promise<ApiResultboolean> {
  return post(
    `/gmp-product-library-portal/library/manage/property/addPropValue`,
    data,
  );
}
  • 相信大家对这个过程挺熟悉的,又爱又恼。爱的是代码提示有了,补全功能很棒。恼的是写类型声明怎么这么烦,得一个一个复制粘贴过来,简直是效率杀手。本文的目的就是让这个过程自动化,爱不释手。

如何开发一个vscode插件

vscode插件中文开发文档

解决思路

flowchart LR
 id1[(OpenApiJson)]-->|openapiTS解析|DefinitionsAst-->|遍历组装| TsFileAst --> |print| File
  • 从接口平台可以拿到一个openApiJson的请求,返回的是标准的openApi的Json格式,可参考https://editor.swagger.io 导出的Json。
  • 通过openapi-typescript,将openApiJson解析成Typescript types。可参考 https://github.com/drwpow/openapi-typescript
  • Ts Types 内容解析成 Ast,这里我定义为 DefinitionsAst。用到了recast,也可以用babel,recast可以帮我保留了注释的节点,所以就用了它。
  • 有了这些前置准备,我们接下来就简单了,只需要遍历我们的DefinitionsAst,找到我们需要的接口RequestDto和ResponseDto,再去组装出我们新的FileAst(类型和Service),写入文件。组装Ast的核心api: recast.types.builders
  • 源代码地址:https://github.com/leizelong/swagger-generate-ts

插件效果展示

  • Cmd+, 打开用户设置,搜索swagger-generate-ts.openApiJsonUrlOptions
    vscode插件开发之Swagger生成Ts-鸿蒙开发者社区
  • 配置项格式 value 是一个标准的openApiJson的get请求
[
    {
      "label": "admin",
      "value": "http://xxx/admin/v2/api-docs"
    },
    {
      "label": "gmp-product-library-portal",
      "value": "http://xxx/gmp-product-library-portal/v2/api-docs"
    },
  ]
  • Cmp+shift+P and typing SwaggerGenerateTs:生成Ts声明和Service请求.

vscode插件开发之Swagger生成Ts-鸿蒙开发者社区

  • 生成的文件

vscode插件开发之Swagger生成Ts-鸿蒙开发者社区

回归到vscode插件开发。(重点讲述与Webview的交互)

  • 可以看到我们的插件中用到了webView与vscode通信交互。官方文档关于WebView的文档内容举的列子太简单了,一个html模板。作为一个有理想的切图仔,肯定是不可能回归到原生js,jQuery之类的,怎么也得Vue、React一把梭。
  • vscode 提供的加载webView Api
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('catCoding.start', () => {
      // 创建和显示webview
      const panel = vscode.window.createWebviewPanel(
        'catCoding',
        'Cat Coding',
        vscode.ViewColumn.One,
        {}
      );

      // 设置HTML内容
      panel.webview.html = getWebviewContent();
    })
  );
}

function getWebviewContent() {
  return
    `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Cat Coding</title>
        </head>
        <body>
            <img src="https://media.giphy.com/media/JIX9t2j0ZTN9S/giphy.gif" width="300" />
        </body>
        </html>
    `;
}

  • Api也很简单嘛,不就是加载一个html模板字符串嘛,我来人造出来不就可以了。可以看到这个html和我们工程化项目构建出的index.html一模一样。那么开始移花接木
    • 打包构建的index.html,这里我把根目录替换为$root,方便后面的替换路径。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <title>React App</title>
    <script defer="defer" src="/$root/static/js/main.e3b97742.js"></script>
    <link href="/$root/static/css/main.9e304a5a.css" rel="stylesheet" />
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
  • 我们的html文件有引入.css和.js文件,这些都是本地资源,vscode的webView对文件访问有限制,得用特殊的方法。 const baseUri = panel.webview.asWebviewUri(rootPath); 这段代码必须要,否则无法读取文件,踩坑出来的,文档上没有写。
  // 加载React项目web-app构建的html文件。
  async function loadLocalHtml() {
    const htmlPath = path.resolve(extensionPath, "web-app/build/index.html");
    const webAppHtml = await fs.promises.readFile(htmlPath, {
      encoding: "utf-8",
    });
    // 
    const rootPath = vscode.Uri.file(path.join(extensionPath, "web-app/build"));
    const baseUri = panel.webview.asWebviewUri(rootPath);
    panel.webview.html = webAppHtml.replace(/\/\$root/g, baseUri.toString());
  }
  • 至此,加载WebView和我们的React工程化打通已完成一大半。剩下的就是Vscode和WebView两者之间的通信了。官方文档中有介绍,不过多阐述。注意点:是通过message事件名来传递消息的,要注意在开发模式下也会对message事件有消息推送,我们打个标识,代表是来着vscode的消息源。
  useEffect(() => {
    function onMessage(event: { data: VsCodeMessage }) {
      const data = event.data; // The JSON data our extension sent
      if (data.source !== "vscode") return;
      console.log("vscode => message", data);
    }
    window.addEventListener("message", onMessage);
    return () => {
      window.removeEventListener("message", onMessage);
    };
  }, []);
  • 我们会发现,我们每次debug插件的时候想要更新webView的内容,都需要去build构建一下html,比较耗费时间。下一个阶段就是优化打通 webView的本地开发模式。也很简单粗暴,直接去下载localhost的html。css,js静态资源是通过http访问的,就没那么多限制。
  async function loadRemoteHtml() {
    const { data: html } = await axios.get("http://localhost:3000");
    panel.webview.html = html.replace(
      /\/\$root/g,
      "http://localhost:3000/$root",
    );
  }

  • 这里还有一个细节问题就是,我没有找到哪个环境变量或者api可以表明是不是处于dev模式。我取了个巧,在本地写了个.config.json, 写入{"debug": true},然后在.vscodeignore文件中忽略它,这样的话,发布之后的插件就读不到这个配置,就认为是生产模式了。

End

  • 欢迎大家下载使用插件leizl.swagger-generate-ts,觉得好用点个赞,一键三连。觉得不好用的地方,提个issue或者留言,好用的插件需要大家的批评与指点。
  • 源码:https://github.com/leizelong/swagger-generate-ts

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
分类
2
收藏
回复
举报
回复
    相关推荐