前端代码生成 · TS加持增强版

为什么要做代码生成?
几乎每个前端项目里大概都是这样的流程,通过模板初始化前端工程,后端同学提供了接口文档后,前端同学就要对照着文档,先是给接口起名字,写上 接口的 path、http method、params、data,勤快的同学会把接口的入参作为函数的注释,就这样完成了一个接口的定义,再看文档,还有几十个接口要这样写,接着 copy,paste,改名字,改path,改method,改参数,可能稍微不注意就改错了某个参数,接着在联调时又浪费不必要的时间。
代码生成会带给哪些优势?
- 免去手写大量复制粘贴的代码,接入pipeline,实现自动化
 - 具体的方法提示,省去在 vue 组件和 api 文件直接来回切换
 - TypeScript 加持,使用 VSCode 类型推导,方便查看参数类型
 - 直达 catalog,准确定位 function 位置
 
一、环境搭建
repo 地址
git clone git@github.com:OpenAPITools/openapi-generator.git
项目环境必备条件
- 安装 Java 8
 - 安装 maven
以上安装成功后,即可进行项目构建brew install maven
配置 maven 私有源移步至 Maven 配置,如果是通过 brew 安装,默认目录为 /usr/local/Cellar/maven/3.x.x/libexec/conf/settings.xmlmvn clean install 
二、定制化开发
针对前端代码生产需要修改的文件及目录包括
Java 文件:modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptAxiosClientCodegen.java
模板目录:modules/openapi-generator/src/main/resources/typescript-axios/
修改后需要重新构建
mvn clean package -Dmaven.test.skip=true
三、代码生成
项目构建完成后,通过以下命令生成代码,其中 typescript-axios-target-es6.json 为配置文件内容
{
  "npmRepository": "http://private.npm.com/repository",
  "snapshot": false,
  "supportsES6": true
}
java -jar ./modules/openapi-generator-cli/target/openapi-generator-cli.jar generate -i ~/some-project.yaml \
    -g typescript-axios \
    -c typescript-axios-target-es6.json \
    --group-id groupId \
    --artifact-id some-project \
    --skip-validate-spec \
    -o ./some-project-api
-g 生成模式
-c 生成所需配置文件
–group-id 传入 groupId
–artifact-id 传入 artifactId
-o 输出项目
–skip-validate-spec 跳过校验
-DdebugModels debug 模式,可选
执行后生成的前端项目结构
.
├── README.md
├── api.ts
├── base.ts
├── configuration.ts
├── dist
│   ├── api.d.ts
│   ├── api.js
│   ├── base.d.ts
│   ├── base.js
│   ├── configuration.d.ts
│   ├── configuration.js
│   ├── index.d.ts
│   └── index.js
├── git_push.sh
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
1 directory, 17 files
四、npm 发布
项目生成后,进入项目目录,手动生成 npm publish 需要的配置文件,安装依赖以及构建
.npmignore
.*.swp
._*
.DS_Store
.git
.hg
.npmrc
.lock-wscript
.svn
.wafpickle-*
config.gypi
CVS
npm-debug.log
cp .npmignore ./some-project-api && cd some-project-api && npm i && npm run build
发布 npm package 到 npm 私服
# npm login 为前提
npm publish
五、使用方法
项目中使用
npm i -S some-project-api
在 /src/apis/index.js  文件中只需要修改项目对应的 npm 名称即可,其他无需操心
import request from '@common/request' // 引入 axios 实例
import { ApiFactory } from 'some-project-api'
export default = ApiFactory({}, process.env.VUE_APP_BASE_URL, request)
// 新模板为 VUE_APP_BASE_URL 现用模板为API_BASE_URL
- 在Vue文件中引入 
import API from ''../../apis''即可通过 `API.getgetBusiness` 调用 api 
// import API from '@/api' 这里暂不推荐使用 @ alias 方式引入,使用 @ 会导致 ts 类型推导失败,后续调研下解决方法.
import API from '../../apis'
export default {
  name: 'demo',
  data() {
    return {
      res: ''
    }
  },
  methods: {
    async getBusiness() {
      // 根据接口 operationId 直接调用
      const res = await API.getBusiness()
      this.res = res
    }
  }
}
</script>
上面提到 ts 类型推导,其实就是借助 VSCode 先天支持 ts 的特性,根据 interface 声明 跳入 npm package 的源码中,源码中对每个方法的传参进行了详细的说明, 如果不习惯或者觉得声明不详细也可通过 方法注释中的 @catalog 一键打开 catalog 中对应的方法。看图 =。=



- 在实际开发过程中,后端同学可能会对 api-spec 修改,当后端修改提交后,pipeline 会重新生成构建发布,这时需要后端同学告知前端同学,前端同学重新安装 api package
避免出现问题直接使用 @latest ,这里稍微科普下 package.json version 相关的知识点npm i -S some-project-api@latest"dependencies": { "vue": "3.0.0", "vuex": "*", "react": "16.x", "typescript": "~5.4.6", "redux": "^14.0.0" } 
前面三个很容易理解:
"vue": "3.0.0": 固定版本号"vuex": "*": 任意版本(>=0.0.0)"react": "16.x": 匹配主要版本(>=16.0.0 <17.0.0)"react": "16.3.x": 匹配主要版本和次要版本(>=16.3.0 <16.4.0)
再来看看后面两个,版本号中引用了 ~ 和 ^ 符号:
~: 当安装依赖时获取到有新版本时,安装到x.y.z中z的最新的版本。即保持主版本号、次版本号不变的情况下,保持修订号的最新版本。^: 当安装依赖时获取到有新版本时,安装到x.y.z中y和z都为最新版本。 即保持主版本号不变的情况下,保持次版本号、修订版本号为最新版本。
在 package.json 文件中最常见的应该是 "yargs": "^14.0.0" 这种格式的 依赖, 因为我们在使用 npm install package 安装包时,npm 默认安装当前最新版本,然后在所安装的版本号前加 ^ 号。
六、遇到的问题
在测试使用过程中发现几个问题
- 对于 
@/apis导入 api,不使用相对路径会丢失类型提示,使用../../apis才可以 - VSCode 提示在 .js 文件和 .vue 文件下行为不一致,在 .js 文件中跳转和提示都准确,按 opt + 点击 function name 跳转会准确的定位到这个 function下,在 .vue 文件中提示准确跳转不准确,按 opt + 点击function name,跳转的 function name 会有误差
 
添加 jsconfig.json 文件,加入相应的配置即可解决以上问题。
Attention !jsconfig.json 为 VSCode 特有,当然不排除其他编辑器借鉴,所以一般只有在 VSCode 中才能工作。
jsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ],
      "@common/*": [
        "src/common/*"
      ],
      "@apis": [
        "src/apis"
      ],
      "@assets": [
        "src/assets"
      ],
      "@common": [
        "src/common"
      ],
      "@components": [
        "src/components"
      ],
      "@views": [
        "src/views"
      ],
      "@utils": [
        "src/utils"
      ]
    }
  },
  "include": [
    "./src/**/*.vue",
    "./src/**/*.js",
  ],
  "exclude": [
    "node_modules"
  ]
}
关于jsconfig.json的更多信息,可以查看 vscode文档相关说明。