@gx-design-vue/create-gx-cli 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. package/README.md +5 -12
  2. package/package.json +3 -2
  3. package/template-mobile-vant-cli/.editorconfig +19 -0
  4. package/template-mobile-vant-cli/.env +0 -0
  5. package/template-mobile-vant-cli/.env.development +19 -0
  6. package/template-mobile-vant-cli/.env.pro +19 -0
  7. package/template-mobile-vant-cli/.env.production +19 -0
  8. package/template-mobile-vant-cli/.eslintignore +15 -0
  9. package/template-mobile-vant-cli/.prettierignore +9 -0
  10. package/template-mobile-vant-cli/build/cdn.ts +5 -0
  11. package/template-mobile-vant-cli/build/generateModifyVars.ts +7 -0
  12. package/template-mobile-vant-cli/build/optimizer.ts +18 -0
  13. package/template-mobile-vant-cli/build/plugin/autoImport.ts +24 -0
  14. package/template-mobile-vant-cli/build/plugin/html.ts +26 -0
  15. package/template-mobile-vant-cli/build/plugin/index.ts +42 -0
  16. package/template-mobile-vant-cli/build/plugin/mock.ts +14 -0
  17. package/template-mobile-vant-cli/build/plugin/viteMock/client.ts +88 -0
  18. package/template-mobile-vant-cli/build/plugin/viteMock/createMockServer.ts +271 -0
  19. package/template-mobile-vant-cli/build/plugin/viteMock/index.ts +69 -0
  20. package/template-mobile-vant-cli/build/plugin/viteMock/types.ts +48 -0
  21. package/template-mobile-vant-cli/build/plugin/viteMock/utils.ts +48 -0
  22. package/template-mobile-vant-cli/build/script/postBuild.ts +14 -0
  23. package/template-mobile-vant-cli/eslint.config.js +49 -0
  24. package/template-mobile-vant-cli/index.html +24 -0
  25. package/template-mobile-vant-cli/mock/_createProductionServer.ts +19 -0
  26. package/template-mobile-vant-cli/mock/datasSource/api/index.ts +0 -0
  27. package/template-mobile-vant-cli/mock/utils.ts +9 -0
  28. package/template-mobile-vant-cli/package.json +57 -0
  29. package/template-mobile-vant-cli/postcss.config.cjs +8 -0
  30. package/template-mobile-vant-cli/prettier.config.cjs +18 -0
  31. package/template-mobile-vant-cli/public/favicon.ico +0 -0
  32. package/template-mobile-vant-cli/public/js/flexible.js +44 -0
  33. package/template-mobile-vant-cli/src/App.vue +5 -0
  34. package/template-mobile-vant-cli/src/components/PageContainer/ProSkeleton.tsx +29 -0
  35. package/template-mobile-vant-cli/src/components/PageContainer/index.tsx +115 -0
  36. package/template-mobile-vant-cli/src/components/PageContainer/style.module.less +14 -0
  37. package/template-mobile-vant-cli/src/core/gx-design/index.ts +7 -0
  38. package/template-mobile-vant-cli/src/core/index.ts +12 -0
  39. package/template-mobile-vant-cli/src/core/vant-design/index.ts +4 -0
  40. package/template-mobile-vant-cli/src/design/config.less +0 -0
  41. package/template-mobile-vant-cli/src/design/index.less +3 -0
  42. package/template-mobile-vant-cli/src/design/reset.less +155 -0
  43. package/template-mobile-vant-cli/src/design/root.less +3 -0
  44. package/template-mobile-vant-cli/src/design/vant.less +2 -0
  45. package/template-mobile-vant-cli/src/global.less +1 -0
  46. package/template-mobile-vant-cli/src/hooks/web/index.ts +5 -0
  47. package/template-mobile-vant-cli/src/hooks/web/usePageLoading.ts +58 -0
  48. package/template-mobile-vant-cli/src/layout/BasicLayout.vue +16 -0
  49. package/template-mobile-vant-cli/src/layout/basicLayout.less +11 -0
  50. package/template-mobile-vant-cli/src/main.ts +27 -0
  51. package/template-mobile-vant-cli/src/pages/home.vue +71 -0
  52. package/template-mobile-vant-cli/src/router/index.ts +25 -0
  53. package/template-mobile-vant-cli/src/router/routes.ts +20 -0
  54. package/template-mobile-vant-cli/src/router/typings.ts +8 -0
  55. package/template-mobile-vant-cli/src/services/index.ts +31 -0
  56. package/template-mobile-vant-cli/src/settings/index.ts +10 -0
  57. package/template-mobile-vant-cli/src/store/index.ts +17 -0
  58. package/template-mobile-vant-cli/src/store/modules/global.ts +30 -0
  59. package/template-mobile-vant-cli/src/utils/crypto/base64.ts +101 -0
  60. package/template-mobile-vant-cli/src/utils/crypto/index.ts +57 -0
  61. package/template-mobile-vant-cli/src/utils/env.ts +50 -0
  62. package/template-mobile-vant-cli/src/utils/pageTitle.ts +14 -0
  63. package/template-mobile-vant-cli/src/utils/request/XHR.ts +139 -0
  64. package/template-mobile-vant-cli/src/utils/request/axiosCancel.ts +69 -0
  65. package/template-mobile-vant-cli/src/utils/request/checkStatus.ts +9 -0
  66. package/template-mobile-vant-cli/src/utils/request/index.ts +142 -0
  67. package/template-mobile-vant-cli/src/utils/request/typings.ts +171 -0
  68. package/template-mobile-vant-cli/src/utils/storage.ts +198 -0
  69. package/template-mobile-vant-cli/src/utils/util.ts +27 -0
  70. package/template-mobile-vant-cli/src/utils/validate.ts +216 -0
  71. package/template-mobile-vant-cli/tsconfig.json +42 -0
  72. package/template-mobile-vant-cli/types/ant-design-import.d.ts +13 -0
  73. package/template-mobile-vant-cli/types/auto-imports.d.ts +64 -0
  74. package/template-mobile-vant-cli/types/components.d.ts +12 -0
  75. package/template-mobile-vant-cli/types/global.d.ts +39 -0
  76. package/template-mobile-vant-cli/types/module.d.ts +20 -0
  77. package/template-mobile-vant-cli/types/plugins-auto-import.d.ts +14 -0
  78. package/template-mobile-vant-cli/types/response.d.ts +15 -0
  79. package/template-mobile-vant-cli/types/vant-import.d.ts +13 -0
  80. package/template-mobile-vant-cli/unocss.config.ts +101 -0
  81. package/template-mobile-vant-cli/vite.config.ts +145 -0
  82. package/template-mobile-vant-html/css/global.css +293 -0
  83. package/template-mobile-vant-html/css/global.css.map +1 -0
  84. package/template-mobile-vant-html/css/global.less +293 -0
  85. package/template-mobile-vant-html/css/index.css +20 -0
  86. package/template-mobile-vant-html/css/index.css.map +1 -0
  87. package/template-mobile-vant-html/css/index.less +21 -0
  88. package/template-mobile-vant-html/image/disconnected.svg +60 -0
  89. package/template-mobile-vant-html/image/empty.svg +52 -0
  90. package/template-mobile-vant-html/image/error.svg +53 -0
  91. package/template-mobile-vant-html/image/loading.svg +1 -0
  92. package/template-mobile-vant-html/index.html +91 -0
  93. package/template-mobile-vant-html/js/index.js +29 -0
  94. package/template-mobile-vant-html/js/plugin/day.min.js +1 -0
  95. package/template-mobile-vant-html/js/plugin/fastclick.js +730 -0
  96. package/template-mobile-vant-html/js/plugin/jquery.min.js +2 -0
  97. package/template-mobile-vant-html/js/plugin/rem.js +28 -0
  98. package/template-mobile-vant-html/js/utils/appUtil.js +70 -0
  99. package/template-mobile-vant-html/js/utils/config.js +3 -0
  100. package/template-mobile-vant-html/js/utils/request.js +61 -0
  101. package/template-mobile-vant-html/js/utils/utils.js +65 -0
  102. package/template-mobile-vant-html/js/utils/validate.js +292 -0
package/README.md CHANGED
@@ -1,22 +1,15 @@
1
- # `@dkundel/create-project`
1
+ # `@gx-design-vue/create-gx-cli`
2
2
 
3
3
  🏗 Personal CLI to bootstrap new projects
4
4
 
5
5
  ## Installation & Usage
6
6
 
7
7
  ```bash
8
- npm init @dkundel/project
8
+ npm init @gx-design-vue/create-gx-cli
9
9
  # or
10
- npx @dkundel/create-project
10
+ npx @gx-design-vue/create-gx-cli
11
11
  # or
12
- npm install -g @dkundel/create-project
13
- create-project
12
+ npm install -g @gx-design-vue/create-gx-cli
13
+ create-gx-cli
14
14
  ```
15
15
 
16
- ## License
17
-
18
- MIT
19
-
20
- ## Collaborators
21
-
22
- - Dominik Kundel <hi@dominik.dev>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gx-design-vue/create-gx-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "license": "MIT",
5
5
  "description": "a cli to bootstrap gx project",
6
6
  "main": "src/index.js",
@@ -28,6 +28,7 @@
28
28
  "files": [
29
29
  "bin/",
30
30
  "src/",
31
- "template-*"
31
+ "template-mobile-vant-html/*",
32
+ "template-mobile-vant-cli/*"
32
33
  ]
33
34
  }
@@ -0,0 +1,19 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset=utf-8
5
+ end_of_line=lf
6
+ insert_final_newline=true
7
+ indent_style=space
8
+ indent_size=2
9
+ max_line_length = 100
10
+
11
+ [*.{yml,yaml,json}]
12
+ indent_style = space
13
+ indent_size = 2
14
+
15
+ [*.md]
16
+ trim_trailing_whitespace = false
17
+
18
+ [Makefile]
19
+ indent_style = tab
File without changes
@@ -0,0 +1,19 @@
1
+ # 实际执行环境 development
2
+ VITE_NODE_ENV= development
3
+
4
+ # environment 代码环境
5
+ VITE_USE_MODE = development
6
+
7
+ VITE_USE_CDN= false
8
+
9
+ # 是否开启mock
10
+ VITE_USE_MOCK = true
11
+
12
+ # 是否使用v-console
13
+ VITE_USE_V_CONSOLE = false
14
+
15
+ # 是否删除console
16
+ VITE_DROP_CONSOLE = false
17
+
18
+ # api前缀
19
+ VITE_BASE_URL=/mock-server
@@ -0,0 +1,19 @@
1
+ # 实际执行环境 production
2
+ VITE_NODE_ENV= production
3
+
4
+ # environment 代码环境
5
+ VITE_USE_MODE = pro
6
+
7
+ VITE_USE_CDN= false
8
+
9
+ # 是否使用v-console
10
+ VITE_USE_V_CONSOLE = false
11
+
12
+ # 是否开启mock
13
+ VITE_USE_MOCK = false
14
+
15
+ # 是否删除console
16
+ VITE_DROP_CONSOLE = true
17
+
18
+ # api前缀
19
+ VITE_BASE_URL=/mock-server
@@ -0,0 +1,19 @@
1
+ # 实际执行环境 production
2
+ VITE_NODE_ENV= production
3
+
4
+ # environment 代码环境
5
+ VITE_USE_MODE = production
6
+
7
+ VITE_USE_CDN= false
8
+
9
+ # 是否使用v-console
10
+ VITE_USE_V_CONSOLE = true
11
+
12
+ # 是否开启mock
13
+ VITE_USE_MOCK = true
14
+
15
+ # 是否删除console
16
+ VITE_DROP_CONSOLE = true
17
+
18
+ # api前缀
19
+ VITE_BASE_URL=/mock-server
@@ -0,0 +1,15 @@
1
+ *.sh
2
+ node_modules
3
+ *.md
4
+ *.woff
5
+ *.ttf
6
+ .vscode
7
+ .idea
8
+ dist
9
+ /public
10
+ /docs
11
+ .husky
12
+ .local
13
+ .history
14
+ /bin
15
+ Dockerfile
@@ -0,0 +1,9 @@
1
+ /dist/*
2
+ .local
3
+ .output.js
4
+ /node_modules/**
5
+
6
+ **/*.svg
7
+ **/*.sh
8
+
9
+ /public/*
@@ -0,0 +1,5 @@
1
+ const css = []
2
+
3
+ const js = []
4
+
5
+ export const cdnConf = { css, js }
@@ -0,0 +1,7 @@
1
+ import { resolve } from 'path'
2
+
3
+ export function generateModifyVars() {
4
+ return {
5
+ hack: `true; @import (reference) "${resolve('src/design/config.less')}";`
6
+ }
7
+ }
@@ -0,0 +1,18 @@
1
+ import type { GetManualChunk } from 'rollup'
2
+
3
+ const vendorLibs: { match: string[]; output: string }[] = [
4
+ {
5
+ match: ['vant'],
6
+ output: 'vant',
7
+ }
8
+ ]
9
+
10
+ export const configManualChunk: GetManualChunk = (id: string) => {
11
+ if (/[\\/]node_modules[\\/]/.test(id)) {
12
+ const matchItem = vendorLibs.find((item) => {
13
+ const reg = new RegExp(`[\\/]node_modules[\\/]_?(${item.match.join('|')})(.*)`, 'ig')
14
+ return reg.test(id)
15
+ })
16
+ return matchItem ? matchItem.output : null
17
+ }
18
+ }
@@ -0,0 +1,24 @@
1
+ import autoImport from 'unplugin-auto-import/vite'
2
+ import Components from 'unplugin-vue-components/vite'
3
+ import { VantResolver } from 'unplugin-vue-components/resolvers'
4
+
5
+ const importsModules = [ 'vue', 'vue-router' ] as any
6
+
7
+ export function createAutoImport() {
8
+ return [
9
+ autoImport({
10
+ include: [
11
+ /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
12
+ /\.vue$/, /\.vue\?vue/, // .vue
13
+ /\.md$/ // .md
14
+ ],
15
+ imports: importsModules,
16
+ dts: 'types/auto-imports.d.ts',
17
+ dirs: [ 'src/store' ]
18
+ }),
19
+ Components({
20
+ resolvers: [ VantResolver() ],
21
+ dts: 'types/plugins-auto-import.d.ts'
22
+ })
23
+ ]
24
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Plugin to minimize and use ejs template syntax in index.html.
3
+ * https://github.com/anncwb/vite-plugin-html
4
+ */
5
+ import { PluginOption } from 'vite'
6
+
7
+ import { createHtmlPlugin } from 'vite-plugin-html'
8
+
9
+ import { cdnConf } from '../cdn'
10
+
11
+ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
12
+
13
+ const htmlPlugin: PluginOption[] = createHtmlPlugin({
14
+ minify: isBuild,
15
+ inject: {
16
+ data: {
17
+ injectScript: env.VITE_USE_CDN ? cdnConf.js : [],
18
+ injectLink: env.VITE_USE_CDN ? cdnConf.css : [],
19
+ injectVlogScript: env.VITE_USE_V_CONSOLE
20
+ ? `<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script><script>var vConsole = new window.VConsole();</script>`
21
+ : ''
22
+ }
23
+ }
24
+ })
25
+ return htmlPlugin
26
+ }
@@ -0,0 +1,42 @@
1
+ import type { Plugin, PluginOption } from 'vite'
2
+
3
+ import vue from '@vitejs/plugin-vue'
4
+ import vueJsx from '@vitejs/plugin-vue-jsx'
5
+
6
+ import vueSetupExtend from 'vite-plugin-vue-setup-extend'
7
+
8
+ import Unocss from 'unocss/vite'
9
+
10
+ import { configHtmlPlugin } from './html'
11
+ import { configMockPlugin } from './mock'
12
+ import { createAutoImport } from './autoImport'
13
+
14
+ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
15
+ const {
16
+ VITE_USE_MOCK
17
+ } = viteEnv
18
+
19
+ const vitePlugins: (Plugin | PluginOption[])[] = [
20
+ // have to
21
+ vue(),
22
+ // have to
23
+ vueJsx()
24
+ ]
25
+
26
+ // unocss
27
+ vitePlugins.push(Unocss())
28
+
29
+ // vite-plugin-vue-setup-extend
30
+ vitePlugins.push(vueSetupExtend())
31
+
32
+ // vite-plugin-html
33
+ vitePlugins.push(configHtmlPlugin(viteEnv, isBuild))
34
+
35
+ // vite-plugin-mock
36
+ VITE_USE_MOCK && vitePlugins.push(configMockPlugin())
37
+
38
+ // unplugin-auto-import/vite
39
+ vitePlugins.push(createAutoImport())
40
+
41
+ return vitePlugins
42
+ }
@@ -0,0 +1,14 @@
1
+ import { viteMockServe } from './viteMock'
2
+
3
+ export function configMockPlugin() {
4
+ return viteMockServe({
5
+ ignore: /^_/,
6
+ mockPath: 'mock',
7
+ enable: true,
8
+ injectCode: `
9
+ import { setupProdMockServer } from '../mock/_createProductionServer';
10
+
11
+ setupProdMockServer();
12
+ `,
13
+ })
14
+ }
@@ -0,0 +1,88 @@
1
+ import mockJs from 'mockjs'
2
+ import { pathToRegexp } from 'path-to-regexp'
3
+
4
+ const Mock = mockJs as any
5
+
6
+ export function createProdMockServer(mockList: any[]) {
7
+ Mock.XHR.prototype.__send = Mock.XHR.prototype.send
8
+ Mock.XHR.prototype.send = function () {
9
+ if (this.custom.xhr) {
10
+ this.custom.xhr.withCredentials = this.withCredentials || false
11
+
12
+ if (this.responseType) {
13
+ this.custom.xhr.responseType = this.responseType
14
+ }
15
+ }
16
+ if (this.custom.requestHeaders) {
17
+ const headers: any = {}
18
+ for (let k in this.custom.requestHeaders) {
19
+ headers[k.toString().toLowerCase()] = this.custom.requestHeaders[k]
20
+ }
21
+ this.custom.options = Object.assign({}, this.custom.options, { headers })
22
+ }
23
+ this.__send.apply(this, arguments)
24
+ }
25
+
26
+ Mock.XHR.prototype.proxy_open = Mock.XHR.prototype.open
27
+
28
+ Mock.XHR.prototype.open = function () {
29
+ let responseType = this.responseType
30
+ this.proxy_open(...arguments)
31
+ if (this.custom.xhr) {
32
+ if (responseType) {
33
+ this.custom.xhr.responseType = responseType
34
+ }
35
+ }
36
+ }
37
+
38
+ for (const { url, method, response, timeout } of mockList) {
39
+ __setupMock__(timeout)
40
+ Mock.mock(
41
+ pathToRegexp(url, undefined, { end: false }),
42
+ method || 'get',
43
+ __XHR2ExpressReqWrapper__(response)
44
+ )
45
+ }
46
+ }
47
+
48
+ function __param2Obj__(url: string) {
49
+ const search = url.split('?')[1]
50
+ if (!search) {
51
+ return {}
52
+ }
53
+ return JSON.parse(
54
+ '{"' +
55
+ decodeURIComponent(search)
56
+ .replace(/"/g, '\\"')
57
+ .replace(/&/g, '","')
58
+ .replace(/=/g, '":"')
59
+ .replace(/\+/g, ' ') +
60
+ '"}'
61
+ )
62
+ }
63
+
64
+ function __XHR2ExpressReqWrapper__(handle: (d: any) => any) {
65
+ return function (options: any) {
66
+ let result = null
67
+ if (typeof handle === 'function') {
68
+ const { body, type, url, headers } = options
69
+ result = handle({
70
+ method: type,
71
+ body: JSON.parse(body),
72
+ query: __param2Obj__(url),
73
+ headers
74
+ })
75
+ } else {
76
+ result = handle
77
+ }
78
+
79
+ return Mock.mock(result)
80
+ }
81
+ }
82
+
83
+ function __setupMock__(timeout = 0) {
84
+ timeout &&
85
+ Mock.setup({
86
+ timeout
87
+ })
88
+ }
@@ -0,0 +1,271 @@
1
+ import type { MockMethod, Recordable, RespThisType, ViteMockOptions } from './types'
2
+ import path from 'node:path'
3
+ import fs from 'node:fs'
4
+ import chokidar from 'chokidar'
5
+ import colors from 'picocolors'
6
+ import url from 'node:url'
7
+ import fg from 'fast-glob'
8
+ import Mock from 'mockjs'
9
+ import type { ResolvedConfig } from 'vite'
10
+ import { match, pathToRegexp } from 'path-to-regexp'
11
+ import type { IncomingMessage, NextHandleFunction } from 'connect'
12
+ import type { GetOutputFile } from 'bundle-require'
13
+ import { bundleRequire, JS_EXT_RE } from 'bundle-require'
14
+ import { isAbsPath, isArray, isFunction, isRegExp, sleep } from './utils'
15
+
16
+ export let mockData: MockMethod[] = []
17
+
18
+ export async function createMockServer(
19
+ opt: ViteMockOptions = { mockPath: 'mock', configPath: 'vite.mock.config' },
20
+ config: ResolvedConfig,
21
+ ) {
22
+ opt = {
23
+ mockPath: 'mock',
24
+ watchFiles: true,
25
+ configPath: 'vite.mock.config.ts',
26
+ logger: true,
27
+ cors: true,
28
+ ...opt,
29
+ }
30
+
31
+ if (mockData.length > 0)
32
+ return
33
+ mockData = await getMockConfig(opt, config)
34
+ await createWatch(opt, config)
35
+ }
36
+
37
+ // request match
38
+ export async function requestMiddleware(opt: ViteMockOptions) {
39
+ const { logger = true } = opt
40
+ const middleware: NextHandleFunction = async (req, res, next) => {
41
+ let queryParams: {
42
+ query?: {
43
+ [key: string]: any
44
+ }
45
+ pathname?: string | null
46
+ } = {}
47
+
48
+ if (req.url) {
49
+ queryParams = url.parse(req.url, true)
50
+ }
51
+
52
+ const reqUrl = queryParams.pathname
53
+
54
+ const matchRequest = mockData.find((item) => {
55
+ if (!reqUrl || !item || !item.url) {
56
+ return false
57
+ }
58
+ if (item.method && item.method.toUpperCase() !== req.method) {
59
+ return false
60
+ }
61
+ return pathToRegexp(item.url).test(reqUrl)
62
+ })
63
+
64
+ if (matchRequest) {
65
+ const isGet = req.method && req.method.toUpperCase() === 'GET'
66
+ const { response, rawResponse, timeout, statusCode, url } = matchRequest
67
+
68
+ if (timeout) {
69
+ await sleep(timeout)
70
+ }
71
+
72
+ const urlMatch = match(url, { decode: decodeURIComponent })
73
+
74
+ let query = queryParams.query as any
75
+ if (reqUrl) {
76
+ if ((isGet && JSON.stringify(query) === '{}') || !isGet) {
77
+ const params = (urlMatch(reqUrl) as any).params
78
+ if (JSON.stringify(params) !== '{}') {
79
+ query = (urlMatch(reqUrl) as any).params || {}
80
+ } else {
81
+ query = queryParams.query || {}
82
+ }
83
+ }
84
+ }
85
+
86
+ const self: RespThisType = { req, res, parseJson: parseJson.bind(null, req) }
87
+ if (isFunction(rawResponse)) {
88
+ await rawResponse.bind(self)(req, res)
89
+ } else {
90
+ const body = await parseJson(req)
91
+ res.setHeader('Content-Type', 'application/json')
92
+ if (opt) {
93
+ res.setHeader('Access-Control-Allow-Credentials', true)
94
+ res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '*')
95
+ }
96
+ res.statusCode = statusCode || 200
97
+ const mockResponse = isFunction(response)
98
+ ? response.bind(self)({ url: req.url as any, body, query, headers: req.headers })
99
+ : response
100
+ res.end(JSON.stringify(Mock.mock(mockResponse)))
101
+ }
102
+
103
+ logger && loggerOutput('request invoke', req.url!)
104
+ return
105
+ }
106
+ next()
107
+ }
108
+ return middleware
109
+ }
110
+
111
+ // create watch mock
112
+ function createWatch(opt: ViteMockOptions, config: ResolvedConfig) {
113
+ const { configPath, logger, watchFiles } = opt
114
+
115
+ if (!watchFiles) {
116
+ return
117
+ }
118
+
119
+ const { absConfigPath, absMockPath } = getPath(opt)
120
+
121
+ if (process.env.VITE_DISABLED_WATCH_MOCK === 'true') {
122
+ return
123
+ }
124
+
125
+ const watchDir = []
126
+ const exitsConfigPath = fs.existsSync(absConfigPath)
127
+
128
+ exitsConfigPath && configPath ? watchDir.push(absConfigPath) : watchDir.push(absMockPath)
129
+
130
+ const watcher = chokidar.watch(watchDir, {
131
+ ignoreInitial: true,
132
+ // ignore files generated by `bundle require`
133
+ ignored: '**/_*.bundled_*.(mjs|cjs)',
134
+ })
135
+
136
+ watcher.on('all', async (event, file) => {
137
+ logger && loggerOutput(`mock file ${event}`, file)
138
+ mockData = await getMockConfig(opt, config)
139
+ })
140
+ }
141
+
142
+ // clear cache
143
+ // function cleanRequireCache(opt: ViteMockOptions) {
144
+ // if (typeof require === 'undefined' || !require.cache) {
145
+ // return
146
+ // }
147
+ // const { absConfigPath, absMockPath } = getPath(opt)
148
+ // Object.keys(require.cache).forEach((file) => {
149
+ // if (file === absConfigPath || file.indexOf(absMockPath) > -1) {
150
+ // delete require.cache[file]
151
+ // }
152
+ // })
153
+ // }
154
+
155
+ function parseJson(req: IncomingMessage): Promise<Recordable> {
156
+ return new Promise((resolve) => {
157
+ let body = ''
158
+ let jsonStr = ''
159
+ req.on('data', function (chunk) {
160
+ body += chunk
161
+ })
162
+ req.on('end', function () {
163
+ try {
164
+ jsonStr = JSON.parse(body)
165
+ } catch (err) {
166
+ jsonStr = ''
167
+ }
168
+ resolve(jsonStr as any)
169
+ return
170
+ })
171
+ })
172
+ }
173
+
174
+ // load mock .ts files and watch
175
+ async function getMockConfig(opt: ViteMockOptions, config: ResolvedConfig) {
176
+ const { absConfigPath, absMockPath } = getPath(opt)
177
+ const { ignore, configPath, logger } = opt
178
+
179
+ let ret: MockMethod[] = []
180
+ if (configPath && fs.existsSync(absConfigPath)) {
181
+ logger && loggerOutput(`load mock data from`, absConfigPath)
182
+ ret = await resolveModule(absConfigPath, config)
183
+ return ret
184
+ }
185
+
186
+ const mockFiles = fg
187
+ .sync(`**/*.{ts,mjs,js}`, {
188
+ cwd: absMockPath,
189
+ })
190
+ .filter((item) => {
191
+ if (!ignore) {
192
+ return true
193
+ }
194
+ if (isFunction(ignore)) {
195
+ return !ignore(item)
196
+ }
197
+ if (isRegExp(ignore)) {
198
+ return !ignore.test(path.basename(item))
199
+ }
200
+ return true
201
+ })
202
+ try {
203
+ ret = []
204
+ const resolveModulePromiseList = []
205
+
206
+ for (let index = 0; index < mockFiles.length; index++) {
207
+ const mockFile = mockFiles[index]
208
+ resolveModulePromiseList.push(resolveModule(path.join(absMockPath, mockFile), config))
209
+ }
210
+ const loadAllResult = await Promise.all(resolveModulePromiseList)
211
+ for (const resultModule of loadAllResult) {
212
+ let mod = resultModule
213
+ if (!isArray(mod)) {
214
+ mod = [mod]
215
+ }
216
+ ret = [...ret, ...mod]
217
+ }
218
+ } catch (error: any) {
219
+ loggerOutput(`mock reload error`, error)
220
+ ret = []
221
+ }
222
+ return ret
223
+ }
224
+
225
+ // fixed file generation format
226
+ // use a random path to avoid import cache
227
+ const getOutputFile: GetOutputFile = (filepath, format) => {
228
+ const dirname = path.dirname(filepath)
229
+ const basename = path.basename(filepath)
230
+ const randomname = `${Date.now()}_${Math.random().toString(36).substring(2, 15)}`
231
+ return path.resolve(
232
+ dirname,
233
+ `_${basename.replace(JS_EXT_RE, `.bundled_${randomname}.${format === 'esm' ? 'mjs' : 'cjs'}`)}`,
234
+ )
235
+ }
236
+
237
+ // Inspired by vite
238
+ // support mock .ts files
239
+ async function resolveModule(p: string, config: ResolvedConfig): Promise<any> {
240
+ const mockData = await bundleRequire({
241
+ filepath: p,
242
+ getOutputFile,
243
+ })
244
+
245
+ let mod = mockData.mod.default || mockData.mod
246
+ if (isFunction(mod)) {
247
+ mod = await mod({ env: config.env, mode: config.mode, command: config.command })
248
+ }
249
+ return mod
250
+ }
251
+
252
+ // get custom config file path and mock dir path
253
+ function getPath(opt: ViteMockOptions) {
254
+ const { mockPath, configPath } = opt
255
+ const cwd = process.cwd()
256
+ const absMockPath = isAbsPath(mockPath) ? mockPath! : path.join(cwd, mockPath || '')
257
+ const absConfigPath = path.join(cwd, configPath || '')
258
+ return {
259
+ absMockPath,
260
+ absConfigPath,
261
+ }
262
+ }
263
+
264
+ function loggerOutput(title: string, msg: string, type: 'info' | 'error' = 'info') {
265
+ const tag = type === 'info' ? colors.cyan(`[vite:mock]`) : colors.red(`[vite:mock-server]`)
266
+ return console.log(
267
+ `${colors.dim(new Date().toLocaleTimeString())} ${tag} ${colors.green(title)} ${colors.dim(
268
+ msg,
269
+ )}`,
270
+ )
271
+ }