对于这个问题,第一反应是在 vue.config.js 中配置 devServer,通过 proxy 代理让流量流向 mockServer。

于是第一时间查看了 vue.config.js,devServer 配置如下:

devServer: {
  port: port,
  open: true,
  overlay: {
    warnings: false,
    errors: true
  },
  before: require('./mock/mock-server.js')
}

出乎意料的是,并没有 proxy。

线索到这儿断了,那么先去看看 .env 是如何配置的吧:

# .env.stage
VUE_APP_BASE_API = '/stage-api'

# .env.development
VUE_APP_BASE_API = '/dev-api'

# .env.production
VUE_APP_BASE_API = '/prod-api'

可见,这里连打包之后的地址都没有指向服务器,那么这个项目打包之后,是怎么找到服务器的呢?

怀着这个问题,在全局搜索 VUE_APP_BASE_API,找到了下一条线索:

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5d50fc95-738e-4322-a442-3cbbab86091f/Untitled.png

显然,关键在这个 mock-server.js 中,这个时候,再仔细看看 vue.config.js,发现这里其实用到了 mock-server.js

devServer: {
  /* ... */
  before: require('./mock/mock-server.js')
}

那么我们再回到 mock-server.js,这里我们关注点来到 module.exports 的方法:

module.exports = app => {
  app.use(bodyParser.json())
  app.use(
    bodyParser.urlencoded({
      extended: true
    })
  )

  const mockRoutes = registerRoutes(app)
  var mockRoutesLength = mockRoutes.mockRoutesLength
  var mockStartIndex = mockRoutes.mockStartIndex

  chokidar
    .watch(mockDir, {
      ignored: /mock-server/,
      ignoreInitial: true
    })
    .on('all', (event, path) => {
      if (event === 'change' || event === 'add') {
        try {
          app._router.stack.splice(mockStartIndex, mockRoutesLength)
          unregisterRoutes()

          const mockRoutes = registerRoutes(app)
          mockRoutesLength = mockRoutes.mockRoutesLength
          mockStartIndex = mockRoutes.mockStartIndex

          console.log(
            chalk.magentaBright(
              `\\n > Mock Server hot reload success! changed  ${path}`
            )
          )
        } catch (error) {
          console.log(chalk.redBright(error))
        }
      }
    })
}

大致分析一下,不难看出,它总共做了三件事:

那么核心自然是 registerRoutes,我们看看它又是怎么做的:

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
  }
}

可以看到,这里逻辑如下: