@infly/vue2-vite 1.0.0 → 1.0.1
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/bin/vue-cli-service.mjs +135 -135
- package/package.json +1 -1
- package/src/compat/assets.mjs +165 -165
- package/src/compat/html.mjs +1 -1
- package/src/compat/import-interop.mjs +2 -2
- package/src/compat/jsx.mjs +142 -142
- package/src/compat/mock.mjs +125 -125
- package/src/compat/require-context.mjs +1 -1
- package/src/compat/sass-export.mjs +112 -112
- package/src/config/discover.mjs +261 -261
- package/src/config/vue-cli-reader.mjs +1 -0
- package/src/factory/create-vite-config.mjs +7 -8
- package/src/factory/manual-chunks.mjs +1 -0
package/src/compat/jsx.mjs
CHANGED
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vue 2 JSX 兼容
|
|
3
|
-
*
|
|
4
|
-
* 使用 Babel + @vue/babel-preset-jsx 将 JSX 语法转换为 h() 调用。
|
|
5
|
-
* 同时处理 .js 文件和 .vue 文件的 script 块。
|
|
6
|
-
* 回退方案:Vite 内置 esbuild。
|
|
7
|
-
*
|
|
8
|
-
* 从 factory.js transformJsx 和相关插件提取。
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { createRequire } from 'node:module';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 将 JSX 代码转换为 JS
|
|
16
|
-
*
|
|
17
|
-
* @param {string} code - 源代码
|
|
18
|
-
* @param {string} id - 文件路径
|
|
19
|
-
* @param {string} projectRoot - 项目根目录
|
|
20
|
-
* @returns {{ code: string } | null}
|
|
21
|
-
*/
|
|
22
|
-
export function transformJsx(code, id, projectRoot) {
|
|
23
|
-
const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
|
|
24
|
-
|
|
25
|
-
// 优先使用 Babel + @vue/babel-preset-jsx
|
|
26
|
-
try {
|
|
27
|
-
const babel = projectRequire('@babel/core');
|
|
28
|
-
const jsxPreset = (() => {
|
|
29
|
-
try {
|
|
30
|
-
return projectRequire('@vue/babel-preset-jsx');
|
|
31
|
-
} catch
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
})();
|
|
35
|
-
|
|
36
|
-
if (jsxPreset) {
|
|
37
|
-
const r = babel.transformSync(code, {
|
|
38
|
-
presets: [[jsxPreset, { injectH: true }]],
|
|
39
|
-
filename: id,
|
|
40
|
-
babelrc: false,
|
|
41
|
-
configFile: false,
|
|
42
|
-
compact: false,
|
|
43
|
-
shouldPrintComment: () => false,
|
|
44
|
-
minified: false,
|
|
45
|
-
});
|
|
46
|
-
return { code: r.code };
|
|
47
|
-
}
|
|
48
|
-
} catch
|
|
49
|
-
// 回退到 esbuild
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 回退:Vite 内置 esbuild
|
|
53
|
-
try {
|
|
54
|
-
const viteReq = createRequire(import.meta.resolve('vite'));
|
|
55
|
-
const esbuild = viteReq('esbuild');
|
|
56
|
-
const r = esbuild.transformSync(code, {
|
|
57
|
-
loader: 'jsx',
|
|
58
|
-
jsxFactory: 'h',
|
|
59
|
-
jsxFragment: 'Fragment',
|
|
60
|
-
});
|
|
61
|
-
return { code: r.code };
|
|
62
|
-
} catch
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 判断文件是否为 .vue 且包含 JSX script
|
|
69
|
-
*/
|
|
70
|
-
function isJsxCode(code) {
|
|
71
|
-
return code.includes('</') || code.includes('/>');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* 创建 JSX 预处理插件(enforce: pre,在 @vitejs/plugin-vue2 之前运行)
|
|
76
|
-
*
|
|
77
|
-
* @param {string} projectRoot
|
|
78
|
-
* @returns {import('vite').Plugin}
|
|
79
|
-
*/
|
|
80
|
-
export function jsxPrePlugin(projectRoot) {
|
|
81
|
-
return {
|
|
82
|
-
name: 'infly-vue2:jsx-pre',
|
|
83
|
-
enforce: 'pre',
|
|
84
|
-
transform(code, id) {
|
|
85
|
-
// 仅处理项目源码中的 .js 文件
|
|
86
|
-
if (!id.endsWith('.js')) return null;
|
|
87
|
-
if (id.includes('node_modules') || id.includes('.cache') || id.includes('.vite')) return null;
|
|
88
|
-
if (!isJsxCode(code)) return null;
|
|
89
|
-
return transformJsx(code, id, projectRoot);
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* 创建 .vue script 块 JSX 预处理插件
|
|
96
|
-
*
|
|
97
|
-
* @param {string} projectRoot
|
|
98
|
-
* @returns {import('vite').Plugin}
|
|
99
|
-
*/
|
|
100
|
-
export function vueJsxPrePlugin(projectRoot) {
|
|
101
|
-
return {
|
|
102
|
-
name: 'infly-vue2:vue-jsx-pre',
|
|
103
|
-
enforce: 'pre',
|
|
104
|
-
transform(code, id) {
|
|
105
|
-
if (!id.endsWith('.vue') || id.includes('node_modules')) return null;
|
|
106
|
-
if (!code.includes('<script')) return null;
|
|
107
|
-
|
|
108
|
-
let transformed = false;
|
|
109
|
-
const result = code.replace(
|
|
110
|
-
/<script\b([^>]*)>([\s\S]*?)<\/script>/g,
|
|
111
|
-
(match, attrs, content) => {
|
|
112
|
-
if (isJsxCode(content)) {
|
|
113
|
-
const r = transformJsx(content, id, projectRoot);
|
|
114
|
-
if (r) {
|
|
115
|
-
transformed = true;
|
|
116
|
-
return `<script${attrs}>${r.code}</script>`;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return match;
|
|
120
|
-
}
|
|
121
|
-
);
|
|
122
|
-
return transformed ? { code: result, map: null } : null;
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* 创建 JSX 清理插件(在 @vitejs/plugin-vue2 后捕获残留 JSX)
|
|
129
|
-
*
|
|
130
|
-
* @param {string} projectRoot
|
|
131
|
-
* @returns {import('vite').Plugin}
|
|
132
|
-
*/
|
|
133
|
-
export function jsxCleanupPlugin(projectRoot) {
|
|
134
|
-
return {
|
|
135
|
-
name: 'infly-vue2:jsx-cleanup',
|
|
136
|
-
transform(code, id) {
|
|
137
|
-
if (id.includes('node_modules') || id.includes('.vite')) return null;
|
|
138
|
-
if (!isJsxCode(code)) return null;
|
|
139
|
-
return transformJsx(code, id, projectRoot);
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Vue 2 JSX 兼容
|
|
3
|
+
*
|
|
4
|
+
* 使用 Babel + @vue/babel-preset-jsx 将 JSX 语法转换为 h() 调用。
|
|
5
|
+
* 同时处理 .js 文件和 .vue 文件的 script 块。
|
|
6
|
+
* 回退方案:Vite 内置 esbuild。
|
|
7
|
+
*
|
|
8
|
+
* 从 factory.js transformJsx 和相关插件提取。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 将 JSX 代码转换为 JS
|
|
16
|
+
*
|
|
17
|
+
* @param {string} code - 源代码
|
|
18
|
+
* @param {string} id - 文件路径
|
|
19
|
+
* @param {string} projectRoot - 项目根目录
|
|
20
|
+
* @returns {{ code: string } | null}
|
|
21
|
+
*/
|
|
22
|
+
export function transformJsx(code, id, projectRoot) {
|
|
23
|
+
const projectRequire = createRequire(path.join(projectRoot, 'package.json'));
|
|
24
|
+
|
|
25
|
+
// 优先使用 Babel + @vue/babel-preset-jsx
|
|
26
|
+
try {
|
|
27
|
+
const babel = projectRequire('@babel/core');
|
|
28
|
+
const jsxPreset = (() => {
|
|
29
|
+
try {
|
|
30
|
+
return projectRequire('@vue/babel-preset-jsx');
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
|
|
36
|
+
if (jsxPreset) {
|
|
37
|
+
const r = babel.transformSync(code, {
|
|
38
|
+
presets: [[jsxPreset, { injectH: true }]],
|
|
39
|
+
filename: id,
|
|
40
|
+
babelrc: false,
|
|
41
|
+
configFile: false,
|
|
42
|
+
compact: false,
|
|
43
|
+
shouldPrintComment: () => false,
|
|
44
|
+
minified: false,
|
|
45
|
+
});
|
|
46
|
+
return { code: r.code };
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
// 回退到 esbuild
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 回退:Vite 内置 esbuild
|
|
53
|
+
try {
|
|
54
|
+
const viteReq = createRequire(import.meta.resolve('vite'));
|
|
55
|
+
const esbuild = viteReq('esbuild');
|
|
56
|
+
const r = esbuild.transformSync(code, {
|
|
57
|
+
loader: 'jsx',
|
|
58
|
+
jsxFactory: 'h',
|
|
59
|
+
jsxFragment: 'Fragment',
|
|
60
|
+
});
|
|
61
|
+
return { code: r.code };
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 判断文件是否为 .vue 且包含 JSX script
|
|
69
|
+
*/
|
|
70
|
+
function isJsxCode(code) {
|
|
71
|
+
return code.includes('</') || code.includes('/>');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 创建 JSX 预处理插件(enforce: pre,在 @vitejs/plugin-vue2 之前运行)
|
|
76
|
+
*
|
|
77
|
+
* @param {string} projectRoot
|
|
78
|
+
* @returns {import('vite').Plugin}
|
|
79
|
+
*/
|
|
80
|
+
export function jsxPrePlugin(projectRoot) {
|
|
81
|
+
return {
|
|
82
|
+
name: 'infly-vue2:jsx-pre',
|
|
83
|
+
enforce: 'pre',
|
|
84
|
+
transform(code, id) {
|
|
85
|
+
// 仅处理项目源码中的 .js 文件
|
|
86
|
+
if (!id.endsWith('.js')) return null;
|
|
87
|
+
if (id.includes('node_modules') || id.includes('.cache') || id.includes('.vite')) return null;
|
|
88
|
+
if (!isJsxCode(code)) return null;
|
|
89
|
+
return transformJsx(code, id, projectRoot);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 创建 .vue script 块 JSX 预处理插件
|
|
96
|
+
*
|
|
97
|
+
* @param {string} projectRoot
|
|
98
|
+
* @returns {import('vite').Plugin}
|
|
99
|
+
*/
|
|
100
|
+
export function vueJsxPrePlugin(projectRoot) {
|
|
101
|
+
return {
|
|
102
|
+
name: 'infly-vue2:vue-jsx-pre',
|
|
103
|
+
enforce: 'pre',
|
|
104
|
+
transform(code, id) {
|
|
105
|
+
if (!id.endsWith('.vue') || id.includes('node_modules')) return null;
|
|
106
|
+
if (!code.includes('<script')) return null;
|
|
107
|
+
|
|
108
|
+
let transformed = false;
|
|
109
|
+
const result = code.replace(
|
|
110
|
+
/<script\b([^>]*)>([\s\S]*?)<\/script>/g,
|
|
111
|
+
(match, attrs, content) => {
|
|
112
|
+
if (isJsxCode(content)) {
|
|
113
|
+
const r = transformJsx(content, id, projectRoot);
|
|
114
|
+
if (r) {
|
|
115
|
+
transformed = true;
|
|
116
|
+
return `<script${attrs}>${r.code}</script>`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return match;
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
return transformed ? { code: result, map: null } : null;
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 创建 JSX 清理插件(在 @vitejs/plugin-vue2 后捕获残留 JSX)
|
|
129
|
+
*
|
|
130
|
+
* @param {string} projectRoot
|
|
131
|
+
* @returns {import('vite').Plugin}
|
|
132
|
+
*/
|
|
133
|
+
export function jsxCleanupPlugin(projectRoot) {
|
|
134
|
+
return {
|
|
135
|
+
name: 'infly-vue2:jsx-cleanup',
|
|
136
|
+
transform(code, id) {
|
|
137
|
+
if (id.includes('node_modules') || id.includes('.vite')) return null;
|
|
138
|
+
if (!isJsxCode(code)) return null;
|
|
139
|
+
return transformJsx(code, id, projectRoot);
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
package/src/compat/mock.mjs
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock 服务器兼容层
|
|
3
|
-
*
|
|
4
|
-
* 将项目的 Express mock-server.js 作为中间件挂载到 Vite dev server。
|
|
5
|
-
* 保留 chokidar 热重载功能。
|
|
6
|
-
*
|
|
7
|
-
* 从 compat/mock.js 迁移(70% 可复用)。
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import path from 'node:path';
|
|
11
|
-
import fs from 'node:fs';
|
|
12
|
-
import Module, { createRequire } from 'node:module';
|
|
13
|
-
import { fileURLToPath } from 'node:url';
|
|
14
|
-
|
|
15
|
-
const PACKAGE_ROOT = path.resolve(
|
|
16
|
-
path.dirname(fileURLToPath(import.meta.url)),
|
|
17
|
-
'../..',
|
|
18
|
-
);
|
|
19
|
-
const packageRequire = createRequire(import.meta.url);
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 在 Babel 转译下运行回调函数(兼容 CJS mock 代码)
|
|
23
|
-
*/
|
|
24
|
-
function withMockCommonJsTranspilation(projectRoot, callback) {
|
|
25
|
-
let register;
|
|
26
|
-
try {
|
|
27
|
-
register = packageRequire('@babel/register');
|
|
28
|
-
} catch
|
|
29
|
-
throw new Error(
|
|
30
|
-
'@infly/vue2-vite 安装不完整:缺少 @babel/register'
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
register({
|
|
34
|
-
babelrc: false,
|
|
35
|
-
configFile: false,
|
|
36
|
-
extensions: ['.js'],
|
|
37
|
-
ignore: [/node_modules/],
|
|
38
|
-
only: [projectRoot],
|
|
39
|
-
presets: [[
|
|
40
|
-
packageRequire.resolve('@babel/preset-env'),
|
|
41
|
-
{ targets: { node: 'current' }, modules: 'commonjs' },
|
|
42
|
-
]],
|
|
43
|
-
});
|
|
44
|
-
return callback();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function loadMockModule(mockServerPath, projectRoot) {
|
|
48
|
-
const mockModule = new Module(mockServerPath);
|
|
49
|
-
mockModule.filename = mockServerPath;
|
|
50
|
-
mockModule.paths = [
|
|
51
|
-
...Module._nodeModulePaths(projectRoot),
|
|
52
|
-
...Module._nodeModulePaths(PACKAGE_ROOT),
|
|
53
|
-
];
|
|
54
|
-
mockModule._compile(fs.readFileSync(mockServerPath, 'utf8'), mockServerPath);
|
|
55
|
-
return mockModule.exports;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* 创建 Vite configureServer 钩子,挂载 Express mock 子应用
|
|
60
|
-
*/
|
|
61
|
-
export function createMockMiddleware(options = {}) {
|
|
62
|
-
const { projectRoot, mockEntry = 'mock/mock-server.js', enabled = true } = options;
|
|
63
|
-
|
|
64
|
-
if (!enabled) return undefined;
|
|
65
|
-
|
|
66
|
-
const mockServerPath = path.resolve(projectRoot, mockEntry);
|
|
67
|
-
|
|
68
|
-
if (!fs.existsSync(mockServerPath)) {
|
|
69
|
-
console.warn(`[infly-vue2] mock 已启用但文件不存在: ${mockServerPath}`);
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return function configureMockServer(server) {
|
|
74
|
-
try {
|
|
75
|
-
// 用包自身的 createRequire 加载 express(@infly/vue2-vite 的依赖)
|
|
76
|
-
const express = packageRequire('express');
|
|
77
|
-
const mockApp = express();
|
|
78
|
-
|
|
79
|
-
// 切换 cwd 到项目目录,使 mock-server 中相对路径正确
|
|
80
|
-
const originalCwd = process.cwd();
|
|
81
|
-
process.chdir(projectRoot);
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
// mock 入口属于应用,但它的运行依赖由本包提供。组合两侧的
|
|
85
|
-
// node_modules 搜索路径,避免要求业务子仓重复声明构建适配依赖。
|
|
86
|
-
const mockServer = withMockCommonJsTranspilation(
|
|
87
|
-
projectRoot,
|
|
88
|
-
() => loadMockModule(mockServerPath, projectRoot),
|
|
89
|
-
);
|
|
90
|
-
mockServer(mockApp);
|
|
91
|
-
|
|
92
|
-
// 挂载到 Vite dev server
|
|
93
|
-
server.middlewares.use(mockApp);
|
|
94
|
-
} finally {
|
|
95
|
-
process.chdir(originalCwd);
|
|
96
|
-
}
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.warn(
|
|
99
|
-
`[infly-vue2] 警告:无法加载 mock 服务器 (${mockServerPath}): ${error.message}`
|
|
100
|
-
);
|
|
101
|
-
console.warn(`[infly-vue2] mock 加载失败,dev server 仍可正常使用。`);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function hasMockServer(options = {}) {
|
|
107
|
-
const {
|
|
108
|
-
projectRoot,
|
|
109
|
-
mockEntry = 'mock/mock-server.js',
|
|
110
|
-
enabled = true,
|
|
111
|
-
} = options;
|
|
112
|
-
return enabled && fs.existsSync(path.resolve(projectRoot, mockEntry));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* 创建 mock 兼容 Vite 插件(含 configureServer 钩子)
|
|
117
|
-
*/
|
|
118
|
-
export function mockPlugin(options = {}) {
|
|
119
|
-
const configureServer = createMockMiddleware(options);
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
name: 'infly-vue2:mock',
|
|
123
|
-
configureServer,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Mock 服务器兼容层
|
|
3
|
+
*
|
|
4
|
+
* 将项目的 Express mock-server.js 作为中间件挂载到 Vite dev server。
|
|
5
|
+
* 保留 chokidar 热重载功能。
|
|
6
|
+
*
|
|
7
|
+
* 从 compat/mock.js 迁移(70% 可复用)。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import Module, { createRequire } from 'node:module';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const PACKAGE_ROOT = path.resolve(
|
|
16
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
17
|
+
'../..',
|
|
18
|
+
);
|
|
19
|
+
const packageRequire = createRequire(import.meta.url);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 在 Babel 转译下运行回调函数(兼容 CJS mock 代码)
|
|
23
|
+
*/
|
|
24
|
+
function withMockCommonJsTranspilation(projectRoot, callback) {
|
|
25
|
+
let register;
|
|
26
|
+
try {
|
|
27
|
+
register = packageRequire('@babel/register');
|
|
28
|
+
} catch {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'@infly/vue2-vite 安装不完整:缺少 @babel/register'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
register({
|
|
34
|
+
babelrc: false,
|
|
35
|
+
configFile: false,
|
|
36
|
+
extensions: ['.js'],
|
|
37
|
+
ignore: [/node_modules/],
|
|
38
|
+
only: [projectRoot],
|
|
39
|
+
presets: [[
|
|
40
|
+
packageRequire.resolve('@babel/preset-env'),
|
|
41
|
+
{ targets: { node: 'current' }, modules: 'commonjs' },
|
|
42
|
+
]],
|
|
43
|
+
});
|
|
44
|
+
return callback();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function loadMockModule(mockServerPath, projectRoot) {
|
|
48
|
+
const mockModule = new Module(mockServerPath);
|
|
49
|
+
mockModule.filename = mockServerPath;
|
|
50
|
+
mockModule.paths = [
|
|
51
|
+
...Module._nodeModulePaths(projectRoot),
|
|
52
|
+
...Module._nodeModulePaths(PACKAGE_ROOT),
|
|
53
|
+
];
|
|
54
|
+
mockModule._compile(fs.readFileSync(mockServerPath, 'utf8'), mockServerPath);
|
|
55
|
+
return mockModule.exports;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 创建 Vite configureServer 钩子,挂载 Express mock 子应用
|
|
60
|
+
*/
|
|
61
|
+
export function createMockMiddleware(options = {}) {
|
|
62
|
+
const { projectRoot, mockEntry = 'mock/mock-server.js', enabled = true } = options;
|
|
63
|
+
|
|
64
|
+
if (!enabled) return undefined;
|
|
65
|
+
|
|
66
|
+
const mockServerPath = path.resolve(projectRoot, mockEntry);
|
|
67
|
+
|
|
68
|
+
if (!fs.existsSync(mockServerPath)) {
|
|
69
|
+
console.warn(`[infly-vue2] mock 已启用但文件不存在: ${mockServerPath}`);
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return function configureMockServer(server) {
|
|
74
|
+
try {
|
|
75
|
+
// 用包自身的 createRequire 加载 express(@infly/vue2-vite 的依赖)
|
|
76
|
+
const express = packageRequire('express');
|
|
77
|
+
const mockApp = express();
|
|
78
|
+
|
|
79
|
+
// 切换 cwd 到项目目录,使 mock-server 中相对路径正确
|
|
80
|
+
const originalCwd = process.cwd();
|
|
81
|
+
process.chdir(projectRoot);
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// mock 入口属于应用,但它的运行依赖由本包提供。组合两侧的
|
|
85
|
+
// node_modules 搜索路径,避免要求业务子仓重复声明构建适配依赖。
|
|
86
|
+
const mockServer = withMockCommonJsTranspilation(
|
|
87
|
+
projectRoot,
|
|
88
|
+
() => loadMockModule(mockServerPath, projectRoot),
|
|
89
|
+
);
|
|
90
|
+
mockServer(mockApp);
|
|
91
|
+
|
|
92
|
+
// 挂载到 Vite dev server
|
|
93
|
+
server.middlewares.use(mockApp);
|
|
94
|
+
} finally {
|
|
95
|
+
process.chdir(originalCwd);
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.warn(
|
|
99
|
+
`[infly-vue2] 警告:无法加载 mock 服务器 (${mockServerPath}): ${error.message}`
|
|
100
|
+
);
|
|
101
|
+
console.warn(`[infly-vue2] mock 加载失败,dev server 仍可正常使用。`);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function hasMockServer(options = {}) {
|
|
107
|
+
const {
|
|
108
|
+
projectRoot,
|
|
109
|
+
mockEntry = 'mock/mock-server.js',
|
|
110
|
+
enabled = true,
|
|
111
|
+
} = options;
|
|
112
|
+
return enabled && fs.existsSync(path.resolve(projectRoot, mockEntry));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 创建 mock 兼容 Vite 插件(含 configureServer 钩子)
|
|
117
|
+
*/
|
|
118
|
+
export function mockPlugin(options = {}) {
|
|
119
|
+
const configureServer = createMockMiddleware(options);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
name: 'infly-vue2:mock',
|
|
123
|
+
configureServer,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -68,7 +68,7 @@ function regexToGlob(regexStr, recursive) {
|
|
|
68
68
|
let glob = inner.replace(/\\\.\\\//g, '');
|
|
69
69
|
glob = glob.replace(/\.\+/g, '*').replace(/\.\*/g, '*');
|
|
70
70
|
glob = glob.replace(/\^/g, '').replace(/\$/g, '');
|
|
71
|
-
glob = glob.replace(/[()
|
|
71
|
+
glob = glob.replace(/[()[\]{}]/g, '');
|
|
72
72
|
|
|
73
73
|
const extMatch = glob.match(/\*\\\.(\w+)/);
|
|
74
74
|
if (extMatch) return `*.${extMatch[1]}`;
|