@gx-design-vue/create-gx-cli 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -11
- package/package.json +3 -2
- package/src/main.js +9 -3
- package/template-mobile-vant-cli/.env +0 -0
- package/template-mobile-vant-cli/.env.pro +1 -1
- package/template-mobile-vant-cli/.env.production +2 -2
- package/template-mobile-vant-cli/.eslintignore +0 -1
- package/template-mobile-vant-cli/build/plugin/autoImport.ts +8 -10
- package/template-mobile-vant-cli/build/plugin/index.ts +2 -10
- package/template-mobile-vant-cli/build/plugin/mock.ts +5 -11
- package/template-mobile-vant-cli/build/plugin/viteMock/client.ts +88 -0
- package/template-mobile-vant-cli/build/plugin/viteMock/createMockServer.ts +271 -0
- package/template-mobile-vant-cli/build/plugin/viteMock/index.ts +69 -0
- package/template-mobile-vant-cli/build/plugin/viteMock/types.ts +48 -0
- package/template-mobile-vant-cli/build/plugin/viteMock/utils.ts +48 -0
- package/template-mobile-vant-cli/eslint.config.js +49 -0
- package/template-mobile-vant-cli/mock/_createProductionServer.ts +4 -4
- package/template-mobile-vant-cli/mock/datasSource/api/index.ts +0 -0
- package/template-mobile-vant-cli/package.json +26 -33
- package/template-mobile-vant-cli/src/components/PageContainer/ProSkeleton.tsx +1 -2
- package/template-mobile-vant-cli/src/components/PageContainer/index.tsx +7 -6
- package/template-mobile-vant-cli/src/components/PageContainer/style.module.less +1 -1
- package/template-mobile-vant-cli/src/core/vant-design/index.ts +1 -1
- package/template-mobile-vant-cli/src/hooks/web/usePageLoading.ts +8 -5
- package/template-mobile-vant-cli/src/layout/BasicLayout.vue +3 -3
- package/template-mobile-vant-cli/src/pages/home.vue +27 -27
- package/template-mobile-vant-cli/src/router/index.ts +3 -2
- package/template-mobile-vant-cli/src/router/typings.ts +1 -1
- package/template-mobile-vant-cli/src/settings/index.ts +2 -2
- package/template-mobile-vant-cli/src/store/modules/global.ts +1 -1
- package/template-mobile-vant-cli/src/utils/crypto/base64.ts +101 -0
- package/template-mobile-vant-cli/src/utils/{cryptoJS.ts → crypto/index.ts} +23 -5
- package/template-mobile-vant-cli/src/utils/env.ts +15 -17
- package/template-mobile-vant-cli/src/utils/pageTitle.ts +5 -3
- package/template-mobile-vant-cli/src/utils/request/XHR.ts +38 -30
- package/template-mobile-vant-cli/src/utils/request/axiosCancel.ts +32 -23
- package/template-mobile-vant-cli/src/utils/request/checkStatus.ts +1 -3
- package/template-mobile-vant-cli/src/utils/request/index.ts +3 -4
- package/template-mobile-vant-cli/src/utils/request/typings.ts +74 -17
- package/template-mobile-vant-cli/src/utils/storage.ts +25 -18
- package/template-mobile-vant-cli/src/utils/util.ts +0 -5
- package/template-mobile-vant-cli/src/utils/validate.ts +191 -3
- package/template-mobile-vant-cli/tsconfig.json +8 -9
- package/template-mobile-vant-cli/types/{gx-components.d.ts → ant-design-import.d.ts} +3 -3
- package/template-mobile-vant-cli/types/auto-imports.d.ts +3 -0
- package/template-mobile-vant-cli/types/components.d.ts +2 -5
- package/template-mobile-vant-cli/types/global.d.ts +7 -4
- package/template-mobile-vant-cli/types/module.d.ts +15 -2
- package/template-mobile-vant-cli/types/plugins-auto-import.d.ts +14 -0
- package/template-mobile-vant-cli/types/response.d.ts +8 -5
- package/template-mobile-vant-cli/types/vant-import.d.ts +13 -0
- package/template-mobile-vant-cli/unocss.config.ts +101 -0
- package/template-mobile-vant-cli/vite.config.ts +43 -11
- package/template-mobile-vant-cli/.eslintrc.js +0 -64
- package/template-mobile-vant-cli/.stylelintignore +0 -3
- package/template-mobile-vant-cli/mock/api/index.ts +0 -66
- package/template-mobile-vant-cli/stylelint.config.js +0 -106
- /package/template-mobile-vant-cli/{postcss.config.js → postcss.config.cjs} +0 -0
- /package/template-mobile-vant-cli/{prettier.config.js → prettier.config.cjs} +0 -0
package/README.md
CHANGED
@@ -1,22 +1,15 @@
|
|
1
|
-
# `@
|
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 @
|
8
|
+
npm init @gx-design-vue/create-gx-cli
|
9
9
|
# or
|
10
|
-
npx @
|
10
|
+
npx @gx-design-vue/create-gx-cli
|
11
11
|
# or
|
12
|
-
npm install -g @
|
12
|
+
npm install -g @gx-design-vue/create-gx-cli
|
13
13
|
create-project
|
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
|
+
"version": "0.1.4",
|
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
|
}
|
package/src/main.js
CHANGED
@@ -13,7 +13,7 @@ const copy = promisify(ncp)
|
|
13
13
|
const gitRepositoryList = [
|
14
14
|
{
|
15
15
|
name: 'gx-design-pro',
|
16
|
-
git: 'https://gitee.com/gx12358/
|
16
|
+
git: 'https://gitee.com/gx12358/vue3-antd-admin.git'
|
17
17
|
},
|
18
18
|
{
|
19
19
|
name: 'gx-design-thin',
|
@@ -22,8 +22,15 @@ const gitRepositoryList = [
|
|
22
22
|
]
|
23
23
|
|
24
24
|
async function copyTemplateFiles(templateDir, root) {
|
25
|
+
const exclusions = [ 'node_modules' ]
|
25
26
|
return copy(templateDir, root, {
|
26
|
-
clobber: false
|
27
|
+
clobber: false,
|
28
|
+
filter: (sourcePath) => {
|
29
|
+
const relativePath = path.relative(templateDir, sourcePath);
|
30
|
+
const folders = relativePath.split(path.sep);
|
31
|
+
const folderToCheck = folders.length > 1 ? folders[1] : folders[0];
|
32
|
+
return !exclusions.includes(folderToCheck)
|
33
|
+
}
|
27
34
|
})
|
28
35
|
}
|
29
36
|
|
@@ -49,7 +56,6 @@ function editPackageJson(root, projectName) {
|
|
49
56
|
writeFile(path.join(root, '.npmrc'), 'shamefully-hoist=true')
|
50
57
|
}
|
51
58
|
|
52
|
-
|
53
59
|
writeFile(path.join(root, 'package.json'), JSON.stringify(pkg, null, 2))
|
54
60
|
}
|
55
61
|
}
|
File without changes
|
@@ -2,25 +2,23 @@ import autoImport from 'unplugin-auto-import/vite'
|
|
2
2
|
import Components from 'unplugin-vue-components/vite'
|
3
3
|
import { VantResolver } from 'unplugin-vue-components/resolvers'
|
4
4
|
|
5
|
+
const importsModules = [ 'vue', 'vue-router' ] as any
|
6
|
+
|
5
7
|
export function createAutoImport() {
|
6
8
|
return [
|
7
9
|
autoImport({
|
8
10
|
include: [
|
9
11
|
/\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
|
10
12
|
/\.vue$/, /\.vue\?vue/, // .vue
|
11
|
-
/\.md
|
12
|
-
],
|
13
|
-
imports: [
|
14
|
-
'vue',
|
15
|
-
'vue-router'
|
13
|
+
/\.md$/ // .md
|
16
14
|
],
|
17
|
-
|
15
|
+
imports: importsModules,
|
16
|
+
dts: 'types/auto-imports.d.ts',
|
17
|
+
dirs: [ 'src/store' ]
|
18
18
|
}),
|
19
19
|
Components({
|
20
|
-
resolvers: [
|
21
|
-
|
22
|
-
],
|
23
|
-
dts: 'types/components.d.ts'
|
20
|
+
resolvers: [ VantResolver() ],
|
21
|
+
dts: 'types/plugins-auto-import.d.ts'
|
24
22
|
})
|
25
23
|
]
|
26
24
|
}
|
@@ -5,7 +5,6 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
|
|
5
5
|
|
6
6
|
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
|
7
7
|
|
8
|
-
import { presetAttributify, presetUno, transformerDirectives } from 'unocss'
|
9
8
|
import Unocss from 'unocss/vite'
|
10
9
|
|
11
10
|
import { configHtmlPlugin } from './html'
|
@@ -25,13 +24,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
|
25
24
|
]
|
26
25
|
|
27
26
|
// unocss
|
28
|
-
vitePlugins.push(Unocss(
|
29
|
-
presets: [
|
30
|
-
presetAttributify(),
|
31
|
-
presetUno()
|
32
|
-
],
|
33
|
-
transformers: [ transformerDirectives() ]
|
34
|
-
}))
|
27
|
+
vitePlugins.push(Unocss())
|
35
28
|
|
36
29
|
// vite-plugin-vue-setup-extend
|
37
30
|
vitePlugins.push(vueSetupExtend())
|
@@ -40,8 +33,7 @@ export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
|
40
33
|
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild))
|
41
34
|
|
42
35
|
// vite-plugin-mock
|
43
|
-
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(
|
44
|
-
|
36
|
+
VITE_USE_MOCK && vitePlugins.push(configMockPlugin())
|
45
37
|
|
46
38
|
// unplugin-auto-import/vite
|
47
39
|
vitePlugins.push(createAutoImport())
|
@@ -1,20 +1,14 @@
|
|
1
|
-
|
2
|
-
* Mock plugin for development and production.
|
3
|
-
* https://github.com/anncwb/vite-plugin-mock
|
4
|
-
*/
|
5
|
-
import { viteMockServe } from 'vite-plugin-mock'
|
1
|
+
import { viteMockServe } from './viteMock'
|
6
2
|
|
7
|
-
export function configMockPlugin(
|
3
|
+
export function configMockPlugin() {
|
8
4
|
return viteMockServe({
|
9
|
-
ignore:
|
5
|
+
ignore: /^_/,
|
10
6
|
mockPath: 'mock',
|
11
|
-
|
12
|
-
localEnabled: !isBuild,
|
13
|
-
prodEnabled: isBuild,
|
7
|
+
enable: true,
|
14
8
|
injectCode: `
|
15
9
|
import { setupProdMockServer } from '../mock/_createProductionServer';
|
16
10
|
|
17
11
|
setupProdMockServer();
|
18
|
-
|
12
|
+
`,
|
19
13
|
})
|
20
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
|
+
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
(async () => {
|
2
|
+
try {
|
3
|
+
await import('mockjs')
|
4
|
+
} catch (e) {
|
5
|
+
throw new Error('vite-plugin-vue-mock requires mockjs to be present in the dependency tree.')
|
6
|
+
}
|
7
|
+
})()
|
8
|
+
|
9
|
+
import type { Plugin, ResolvedConfig } from 'vite'
|
10
|
+
import { normalizePath } from 'vite'
|
11
|
+
import path from 'node:path'
|
12
|
+
import type { ViteMockOptions } from './types'
|
13
|
+
import { fileExists } from './utils'
|
14
|
+
import { createMockServer, requestMiddleware } from './createMockServer'
|
15
|
+
|
16
|
+
function getDefaultPath(supportTs = true) {
|
17
|
+
return path.resolve(process.cwd(), `src/main.${supportTs ? 'ts' : 'js'}`)
|
18
|
+
}
|
19
|
+
|
20
|
+
export function viteMockServe(opt: ViteMockOptions = {}): Plugin {
|
21
|
+
let isDev = false
|
22
|
+
let needSourcemap = false
|
23
|
+
let config: ResolvedConfig
|
24
|
+
let defaultPath = getDefaultPath()
|
25
|
+
if (!fileExists(defaultPath)) {
|
26
|
+
defaultPath = getDefaultPath(false)
|
27
|
+
if (!fileExists(defaultPath)) {
|
28
|
+
defaultPath = ''
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
const defaultEnter = normalizePath(defaultPath)
|
33
|
+
|
34
|
+
const { injectFile = defaultEnter } = opt
|
35
|
+
|
36
|
+
return {
|
37
|
+
name: 'vite:mock',
|
38
|
+
enforce: 'pre' as const,
|
39
|
+
configResolved(resolvedConfig) {
|
40
|
+
config = resolvedConfig
|
41
|
+
isDev = config.command === 'serve'
|
42
|
+
needSourcemap = !!resolvedConfig.build.sourcemap
|
43
|
+
isDev && createMockServer(opt, config)
|
44
|
+
},
|
45
|
+
|
46
|
+
configureServer: async ({ middlewares }) => {
|
47
|
+
const { enable = isDev } = opt
|
48
|
+
if (!enable) {
|
49
|
+
return
|
50
|
+
}
|
51
|
+
const middleware = await requestMiddleware(opt)
|
52
|
+
middlewares.use(middleware)
|
53
|
+
},
|
54
|
+
transform: (code, id) => {
|
55
|
+
if (isDev || !injectFile || !id.endsWith(injectFile)) {
|
56
|
+
return null
|
57
|
+
}
|
58
|
+
|
59
|
+
const { injectCode = '' } = opt
|
60
|
+
|
61
|
+
return {
|
62
|
+
map: needSourcemap ? this.getCombinedSourcemap() : null,
|
63
|
+
code: `${code}\n${injectCode}`
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
export * from './types'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'http'
|
2
|
+
|
3
|
+
export interface ViteMockOptions {
|
4
|
+
mockPath?: string;
|
5
|
+
configPath?: string;
|
6
|
+
injectFile?: string;
|
7
|
+
injectCode?: string;
|
8
|
+
ignore?: RegExp | ((fileName: string) => boolean);
|
9
|
+
watchFiles?: boolean;
|
10
|
+
enable?: boolean;
|
11
|
+
cors?: boolean;
|
12
|
+
/**
|
13
|
+
* Automatic recognition, no need to configure again
|
14
|
+
* @deprecated Deprecated after 2.8.0
|
15
|
+
*/
|
16
|
+
supportTs?: boolean;
|
17
|
+
logger?: boolean;
|
18
|
+
}
|
19
|
+
|
20
|
+
export interface RespThisType {
|
21
|
+
req: IncomingMessage
|
22
|
+
res: ServerResponse
|
23
|
+
parseJson: () => any
|
24
|
+
}
|
25
|
+
|
26
|
+
export type MethodType = 'get' | 'post' | 'put' | 'delete' | 'patch'
|
27
|
+
|
28
|
+
export type Recordable<T = any> = Record<string, T>
|
29
|
+
|
30
|
+
export declare interface MockMethod {
|
31
|
+
url: string
|
32
|
+
method?: MethodType
|
33
|
+
timeout?: number
|
34
|
+
statusCode?: number
|
35
|
+
response?:
|
36
|
+
| ((
|
37
|
+
this: RespThisType,
|
38
|
+
opt: { url: Recordable; body: Recordable; query: Recordable; headers: Recordable },
|
39
|
+
) => any)
|
40
|
+
| any
|
41
|
+
rawResponse?: (this: RespThisType, req: IncomingMessage, res: ServerResponse) => void
|
42
|
+
}
|
43
|
+
|
44
|
+
export interface MockConfig {
|
45
|
+
env: Record<string, any>
|
46
|
+
mode: string
|
47
|
+
command: 'build' | 'serve'
|
48
|
+
}
|