mocks-server.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /**
  2. * @created by pan
  3. * @updated by helin3 2019-04-08
  4. * @description Mock Express 热更新注册
  5. */
  6. const chokidar = require('chokidar')
  7. const bodyParser = require('body-parser')
  8. const chalk = require('chalk')
  9. const path = require('path')
  10. const mockDir = path.join(process.cwd(), 'mocks')
  11. const mockEnable = process.env.VUE_APP_MOCK_ENABLE === 'true' // Mock是否启用
  12. const mockMode = process.env.VUE_APP_MOCK_MODE === 'true' // 模拟模式,true真实express服务,false XHR拦截方式
  13. /**
  14. * 通过express 路由方式注册mocks api
  15. * @param {*} app express实例
  16. * @returns {object}
  17. * mockStartIndex mock路由开始索引位置
  18. * mockRoutesLength 路由长度mocks api
  19. */
  20. function registerRoutes(app) {
  21. let mockLastIndex
  22. // 读取注册路由
  23. const { default: mocks } = require('./index.js')
  24. console.log('\n Mocks Server Register Routes : \n')
  25. for (const mock of mocks) {
  26. let url = mock.url ? (mock.url.source || mock.url): ''
  27. url = url.replace(/\\\//g, '/')
  28. console.log(' - ' + mock.type + ' - ' + url)
  29. app[mock.type](mock.url, mock.response)
  30. }
  31. mockLastIndex = app._router.stack.length
  32. const mockRoutesLength = Object.keys(mocks).length
  33. return {
  34. mockStartIndex: mockLastIndex - mockRoutesLength,
  35. mockRoutesLength: Object.keys(mocks).length
  36. }
  37. }
  38. /**
  39. * 清除/mocks目录require缓存
  40. * TODO: 待调试
  41. */
  42. function unregisterRoutes() {
  43. Object.keys(require.cache).forEach(i => {
  44. // 清除/mocks目录require缓存
  45. if (i.includes(mockDir)) {
  46. delete require.cache[require.resolve(i)]
  47. }
  48. })
  49. }
  50. module.exports = app => {
  51. // es6 polyfill
  52. require('@babel/register')
  53. // Mock启用,则在开发模式添加mock api拦截
  54. // 此处必须得是字符串方式判断,因其不在浏览器中
  55. if (!mockEnable || !mockMode) {
  56. return
  57. }
  58. // 开发模式,没有统一前缀,如何区分API是Mock服务
  59. app.all('*', function(req, res, next) {
  60. res.header("X-Mock-Api", "xyMock")
  61. next()
  62. })
  63. // parse app.body
  64. // https://expressjs.com/en/4x/api.html#req.body
  65. app.use(bodyParser.json())
  66. app.use(bodyParser.urlencoded({
  67. extended: true
  68. }))
  69. let lastRegReturn = registerRoutes(app)
  70. let mockRoutesLength = lastRegReturn.mockRoutesLength
  71. let mockStartIndex = lastRegReturn.mockStartIndex
  72. // 监听/mocks文件(忽略/mocks/mocks-server.js),热加载Mocks Server
  73. chokidar.watch(mockDir, {
  74. ignored: /mocks-server/,
  75. ignoreInitial: true
  76. }).on('all', (event, path) => {
  77. if (event === 'change' || event === 'add') {
  78. // 移除 mock api Express路由堆栈
  79. app._router.stack.splice(mockStartIndex, mockRoutesLength)
  80. // 清除路由文件缓存
  81. unregisterRoutes()
  82. // 重新注册Mocks api路由
  83. lastRegReturn = registerRoutes(app)
  84. mockRoutesLength = lastRegReturn.mockRoutesLength
  85. mockStartIndex = lastRegReturn.mockStartIndex
  86. console.log(chalk.magentaBright(`\n > Mocks Server hot reload success! changed ${path}`))
  87. }
  88. })
  89. }