Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于 vite 的 mock 插件实现 #24

Open
chiyan-lin opened this issue Dec 23, 2021 · 0 comments
Open

基于 vite 的 mock 插件实现 #24

chiyan-lin opened this issue Dec 23, 2021 · 0 comments

Comments

@chiyan-lin
Copy link
Owner

chiyan-lin commented Dec 23, 2021

#25 ,我们再来看看如何生成 mock 数据以及在使用 vite 脚手架的情况下,mock要怎么实现才是最佳方案

回到实际使用上来,在开发过程中,我们关注的是,在后端接口没有 ready 的时候,可以

  1. 快捷地进行mock,自动生成 mock 数据
  2. 最大化减少 mock 过程的手动复制的操作
  3. mock数据支持函数操作,可以写一些简单的逻辑判断返回不同的值

基于上述三个目标进行 mock 功能的开发,最终希望获得的mock数据如下

GetFamilyLvConfsRes.js 文件内容

module.exports = function(req) {
  return {
    result: { errcode: "@integer", errmsg: "@string", magic: "@integer" },
    sequence: "@integer",
    current_phase: {
      phase: function() {
        var enums = {
          PHASE_NONE: 0,
          PHASE_NOT_STARTED: 10
        };
        return enums["PHASE_NONE"];
      },
      begin_ts: "@integer",
      end_ts: "@integer",
      is_rest: "@boolean",
      join_count: "@integer",
      win_count: "@integer"
    },
    is_in_rank: function() {
      return !!req.sequence === 123
    }
  };
};

导出为 commonjs 函数的形式,并且将 req 传入,这样形式的导出可以解决提到的三个目标

@xxx 的格式是 mockjs 的语法,mockjs 可以根据语法自动生成一些更有意义的数据,具体可以 github 过去看看。

vite 的插件只需要在拦截到是 GetFamilyLvConfsRes 的请求,然后 require 这个 js 文件并传入 req 执行返回即可。

mock 文件的生成

如上面的代码文件,再参考 pb 文件,代码间的相互引用是实现 pb 直接转换的成 js 的最大阻碍。

// GetFamilyLvConfsRes 的 interface 
export interface GetFamilyLvConfsRes {
  result: common.Result;
  confs: FamilyLvConf[];
}

如果仅仅只对 文件进行编译,生成形如

const  common = require('./common')
const FamilyLvConf = {}

module.exports = function(req) {
  return {
      result: common.Result;
      confs: FamilyLvConf[];
  }
}

的格式,那么其他 mothods 也会相同地引用到这些公共文件,而有时候需要区分开来。所以最好的方案就是把引用去掉,将值直接放到 return 中去。

在编译过程中,存在 import 的问题,而对于编译过程是一个字符串解析的过程,处理 import 进来的变量处理起来没有什么比较好的方式,于是想到了一个比较灵活的方案。

类似生成 interface 的方式,将 ts 的关键字替换成 js 的关键字,保留文件之前的相互引用

image

生成这样的文件之后,就可以把左边的文件在 js 中 require,在生成具体代码的时候,使用 JOSN.stringify 格式化。

export const generateServiceToMock = (result: any, basename: string, callback: Function) => {
  // 根据 basename 把上面的文件导入到进程中
  const mockOriginData = require(path.resolve(config.mockOriginDataRoot + '/' + basename + '.js'));
  result.services.map((item: any) => {
    const serviceName = item.name;
    item.methods
      .filter((child: any) => child.type === 'rpc' || child.type === 'comment')
      .forEach((child: RpcField) => {
        const name = child.name;
        // 🏪所有 mothods ,生成整个 service 所有的 mothod mock 数据
        const req = child.argTypeName.identifier.name;
        const res = child.returnTypeName.identifier.name;
        const mock = `
          module.exports = function(req) {
            return ${JSON.stringify(mockOriginData[res], jsonReplacer).replace(/"\{func_(\d+)\}"/g, funcReplacer)}
          }`;
        const mockDataRoute = path.resolve(config.mockDataRoot + '/' + serviceName + '/' + name + '.js')
        callback(mockDataRoute, mock);
      })
  });
};

最后在生成好全部数据之后,可以看到下面的文件结构
image
具体的文件内容
image

vite 插件的简单实现

对 host 进行处理,原则上只在 开发环境 也就是 import.meta.env.DEV 为 true 的时候,讲请求的 host 指向本地的域名,其他情况指向具体的服务。

vite 中的插件,启动一个服务器,这里使用 express ,解析请求发起的 method 和 service ,然后去生成的 mock 文件夹中取 mock 数据。

  app.post("/api", (req, res) => {
    const { serviceName, method } = req.body;
    // 根据服务名和mothod名称,获取不同的 mock 文件
    const root = path.resolve("src/api/mock/" + serviceName + "/" + method + ".js");
    const rsp = require(root);
    res.send(Mock.mock(rsp(req.body)));
    // 清除缓存,确保每次修改 mock 文件再次访问的时候是新的
    delete require.cache[root];
  });

插件的作用就是修改 vite 的 service proxy ,使页面的请求可以指向本地的具体服务

 export default function mock() {
  const port = serve()
  return {
    name: 'mock',
    config: () => ({
      server: {
        proxy: {
          // 选项写法
          '/api': {
            target: `http://localhost:${port}`,
            changeOrigin: true,
            // rewrite: (path) => path.replace(/^\/api/, '')
          }
        }
      }
    })
  }
}

最后的效果

增加了一些 mockjs 的语法的mock
image

在浏览器中获取到的数据
image

@chiyan-lin chiyan-lin changed the title protobuf 生成 ts interface & api 基于 vite 的 mock 插件实现 Dec 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant