dynamic-proxy 一个解决webpack接口代理热重载的工具

1,876 阅读3分钟

0x00 背景

写这个工具的最根本的原因,是因为我司vue2.x项目的逐渐壮大,在与后端联调过程中切换代理每次都需要重启服务,由于项目巨大,每次重新启动都会消耗8-10分钟,效率肉眼可见的低。写这个工具的目的就是为了实现切换代理,而不需要重启项目(就是为了卷)。(别问为什么不使用vite,问就是我司不打算放弃IE)

0x01 摸一摸 webpack-dev-server 的代理

马克思主义告诉我们,认识来源于实践,反作用与实践。所以首先要搞清楚我们原来的代理是怎么实现的。

image-20211203110240810

你以为我要去看源码?不可能的,直接打开webpack的文档配置。

开发服务器使用功能强大的 http-proxy-middleware 软件包。 查看其 documentation 了解更多高级用法。 请注意,http-proxy-middleware 的某些功能不需要target键,例如 它的 router 功能,但是仍然需要在此处的配置中包含target,否则webpack-dev-server 不会将其传递给 http-proxy-middleware

抓住关键字:http-proxy-middleware

0x02 摸一摸 http-proxy-middleware

兴奋的打开了G站,找到了代码:传送门

你以为我要看源码?不可能的,我做为一个无情的API调用工具,怎么可能去看那玩意儿。看看README得了

0x03 如何热重载

热重载不是难题,用chokidar监听文件改变得了,可是要怎么实现删除原来的代理,使用新的代理覆盖。

这里想到了入门vue的时候看的 @panjiachen 大佬的 vue-element-admin相关链接

image-20211203111226949

这里有一个内容极其小的东西,或许你都没有注意过,我直接 “拿来把你” 。具体文件

注册路由

function registerRoutes(app) {
  let mockLastIndex
  const { mocks } = require('./index.js')
  const mocksForServer = mocks.map(route => {
    return responseFake(route.url, route.type, route.response)
  })
  for (const mock of mocksForServer) {
    app[mock.type](mock.url, mock.response)
    mockLastIndex = app._router.stack.length
  }
  const mockRoutesLength = Object.keys(mocksForServer).length
  return {
    mockRoutesLength: mockRoutesLength,
    mockStartIndex: mockLastIndex - mockRoutesLength
  }
}

这是个好东西,这玩意儿基于express,相当于循环加入中间件,然后记录下自己插入的中间件的位置。(如果你不曾了解过express,直接忽略)

清理路由

function unregisterRoutes() {
  Object.keys(require.cache).forEach(i => {
    if (i.includes(mockDir)) {
      delete require.cache[require.resolve(i)]
    }
  })
}

这里个人感觉不是很精髓,这个清除路由的函数没有体现他的用途,只是清理了require的缓存

#66 app._router.stack.splice(mockStartIndex, mockRoutesLength)

第66行的这条代码才是从真正的删除注册的中间件

0x04 写工具

看完上面的东西,大概就有思路了,接下来就是紧张刺激的写代码的环节。

我就不多在这里BB了,话多了都是水,直接上地址: GitHub传送门

当然,你可能觉得我写的代码很辣鸡~这有问题么?没有问题,我也觉得自己很辣鸡。可以拿来就用。

0x05 拿来就用

npm:

npm install dynamic-proxy --save-dev

yarn

yarn add dynamic-proxy -D

0x06 正确食用方法

1、代理文件

创建自己的代理文件或使用默认的proxy.js(默认的文件要放到你的项目根目录,和package.json),准确的说,这个工具会读取你执行命令行命令所在路径下的proxy.js

文件内容:

module.exports = {
  "/api": {
    ws: true,
    changeOrigin: true,
    target: "http://127.0.0.1:8888",
  },
};

不能说和原来配置proxy的方式类似吧,这就是一摸一样,你可以直接把你原来的proxyTable直接拿出来。

2、修改devServer配置

vue.config.js or webpack.config.js

// ...
const { useProxy } = require("dynamic-proxy");

module.exports = {
  // ...
  devServer: {
    // ...
    after(app) {
      useProxy(app); // or useProxy(app, options)
    },
  },
};

关键点:在after里面使用,移除你原来的proxy字段

更多配置信息请参看项目 README

0x07 写在最后

总结一下?不可能的,没有总结。这个文章的最后只是在乞讨。

各位客官如果食用效果甚佳,还请不吝赐star!

再次提供: GitHub传送门

问:为什么项目名称不是webpack-dynamic-proxy?

答:理论上可以用于任何express项目,不限于webpack