warehouse-mock 1.0.3 → 1.1.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/dist/index.d.ts +10 -0
- package/dist/index.js +198 -21
- package/package.json +8 -4
package/dist/index.d.ts
CHANGED
|
@@ -10,11 +10,16 @@ interface MockPluginOptions {
|
|
|
10
10
|
};
|
|
11
11
|
injectEnv?: boolean;
|
|
12
12
|
delay?: number;
|
|
13
|
+
admin?: {
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
port?: number;
|
|
16
|
+
};
|
|
13
17
|
}
|
|
14
18
|
declare class WarehouseMockPlugin {
|
|
15
19
|
private options;
|
|
16
20
|
private resolvedMockPath;
|
|
17
21
|
private isEnabled;
|
|
22
|
+
private adminServer;
|
|
18
23
|
constructor(options?: MockPluginOptions);
|
|
19
24
|
/**
|
|
20
25
|
* 实时扫描 mock 目录,获取所有 mock 文件名列表
|
|
@@ -25,6 +30,10 @@ declare class WarehouseMockPlugin {
|
|
|
25
30
|
*/
|
|
26
31
|
getLocalApiPrefix(): string;
|
|
27
32
|
apply(compiler: Compiler): void;
|
|
33
|
+
/**
|
|
34
|
+
* 启动管理后台服务
|
|
35
|
+
*/
|
|
36
|
+
private startAdminServer;
|
|
28
37
|
/**
|
|
29
38
|
* 自动注入环境变量 VUE_APP_MOCK
|
|
30
39
|
*/
|
|
@@ -40,6 +49,7 @@ declare class WarehouseMockPlugin {
|
|
|
40
49
|
private getResolvedMockPath;
|
|
41
50
|
private ensureMockDirectory;
|
|
42
51
|
private createDemoFile;
|
|
52
|
+
private readInterfaceConfig;
|
|
43
53
|
private handleRequest;
|
|
44
54
|
/**
|
|
45
55
|
* 代理请求到真实 API(改进版)
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
class WarehouseMockPlugin {
|
|
9
9
|
constructor(options = {}) {
|
|
10
|
+
var _a, _b;
|
|
10
11
|
this.resolvedMockPath = '';
|
|
11
12
|
this.isEnabled = true;
|
|
13
|
+
this.adminServer = null;
|
|
12
14
|
// 默认配置
|
|
13
15
|
this.options = {
|
|
14
16
|
mockPath: options.mockPath || 'warehouseMock',
|
|
@@ -18,6 +20,10 @@ class WarehouseMockPlugin {
|
|
|
18
20
|
proxy: options.proxy || undefined,
|
|
19
21
|
injectEnv: options.injectEnv !== undefined ? options.injectEnv : true,
|
|
20
22
|
delay: options.delay || 0,
|
|
23
|
+
admin: {
|
|
24
|
+
enabled: ((_a = options.admin) === null || _a === void 0 ? void 0 : _a.enabled) !== undefined ? options.admin.enabled : true,
|
|
25
|
+
port: ((_b = options.admin) === null || _b === void 0 ? void 0 : _b.port) || 3100,
|
|
26
|
+
},
|
|
21
27
|
};
|
|
22
28
|
// 判断是否启用(支持环境变量控制)
|
|
23
29
|
if (process.env.MOCK === 'false' || process.env.VUE_APP_MOCK === 'false') {
|
|
@@ -79,10 +85,55 @@ class WarehouseMockPlugin {
|
|
|
79
85
|
if (this.options.proxy) {
|
|
80
86
|
console.log(chalk_1.default.cyan(`[WarehouseMock] 代理模式: 未匹配请求 → ${this.options.proxy.target}`));
|
|
81
87
|
}
|
|
88
|
+
// 启动管理后台
|
|
89
|
+
if (this.options.admin && this.options.admin.enabled) {
|
|
90
|
+
this.startAdminServer();
|
|
91
|
+
}
|
|
82
92
|
// 注意:devServer 的配置需要在 vue.config.js 中手动配置
|
|
83
93
|
// 对于 Webpack 5 使用 setupMiddlewares
|
|
84
94
|
// 对于 Webpack 4 使用 before
|
|
85
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* 启动管理后台服务
|
|
98
|
+
*/
|
|
99
|
+
startAdminServer() {
|
|
100
|
+
var _a;
|
|
101
|
+
try {
|
|
102
|
+
// 动态导入管理后台服务
|
|
103
|
+
let createAdminServer;
|
|
104
|
+
try {
|
|
105
|
+
// 尝试导入已安装的包
|
|
106
|
+
createAdminServer = require('warehouse-mock-admin').createAdminServer;
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
// 如果找不到,尝试相对路径(开发环境)
|
|
110
|
+
const adminPath = require('path').resolve(__dirname, '../../mock-admin/dist/server/index.js');
|
|
111
|
+
createAdminServer = require(adminPath).createAdminServer;
|
|
112
|
+
}
|
|
113
|
+
if (!createAdminServer) {
|
|
114
|
+
throw new Error('无法加载管理后台模块');
|
|
115
|
+
}
|
|
116
|
+
const adminResult = createAdminServer({
|
|
117
|
+
mockPath: this.resolvedMockPath,
|
|
118
|
+
port: ((_a = this.options.admin) === null || _a === void 0 ? void 0 : _a.port) || 3100,
|
|
119
|
+
});
|
|
120
|
+
this.adminServer = adminResult;
|
|
121
|
+
console.log(chalk_1.default.green(`\n╭────────────────────────────────────────────────────╮`));
|
|
122
|
+
console.log(chalk_1.default.green(`│ 🎨 Mock 数据管理后台已启动 │`));
|
|
123
|
+
console.log(chalk_1.default.green(`│ │`));
|
|
124
|
+
console.log(chalk_1.default.green(`│ ➜ 访问地址: ${chalk_1.default.cyan(adminResult.url).padEnd(31)} │`));
|
|
125
|
+
console.log(chalk_1.default.green(`│ │`));
|
|
126
|
+
console.log(chalk_1.default.green(`│ 在浏览器中打开上面的地址来管理 Mock 数据 │`));
|
|
127
|
+
console.log(chalk_1.default.green(`╰────────────────────────────────────────────────────╯\n`));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
console.log(chalk_1.default.yellow('[WarehouseMock] 管理后台包未安装或加载失败,跳过启动'));
|
|
131
|
+
console.log(chalk_1.default.gray(' 提示:运行 npm install warehouse-mock-admin 来安装管理后台'));
|
|
132
|
+
if (err.message && !err.message.includes('Cannot find module')) {
|
|
133
|
+
console.log(chalk_1.default.gray(` 错误详情: ${err.message}`));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
86
137
|
/**
|
|
87
138
|
* 自动注入环境变量 VUE_APP_MOCK
|
|
88
139
|
*/
|
|
@@ -186,6 +237,20 @@ class WarehouseMockPlugin {
|
|
|
186
237
|
console.error(chalk_1.default.yellow(`[WarehouseMock] 创建示例文件失败: ${e}`));
|
|
187
238
|
}
|
|
188
239
|
}
|
|
240
|
+
// 读取接口配置
|
|
241
|
+
readInterfaceConfig(apiName, mockPath) {
|
|
242
|
+
const configPath = path_1.default.join(mockPath, apiName, '.config.json');
|
|
243
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
244
|
+
try {
|
|
245
|
+
const content = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
246
|
+
return JSON.parse(content);
|
|
247
|
+
}
|
|
248
|
+
catch (e) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
189
254
|
handleRequest(req, res, next, mockPath) {
|
|
190
255
|
var _a, _b, _c;
|
|
191
256
|
const url = req.path || ((_a = req.url) === null || _a === void 0 ? void 0 : _a.split('?')[0]);
|
|
@@ -218,31 +283,125 @@ class WarehouseMockPlugin {
|
|
|
218
283
|
let filePath = '';
|
|
219
284
|
let matched = false;
|
|
220
285
|
let matchedName = '';
|
|
286
|
+
let interfaceConfig = null;
|
|
221
287
|
// 1. 优先尝试 Query String 匹配 (RPC 风格接口,如 /api?user.taurus.pointInfo)
|
|
222
288
|
if (req.url && req.url.includes('?')) {
|
|
223
289
|
const queryPart = req.url.split('?')[1];
|
|
224
290
|
if (queryPart) {
|
|
225
291
|
const params = new URLSearchParams(queryPart);
|
|
226
292
|
for (const key of params.keys()) {
|
|
227
|
-
//
|
|
228
|
-
const
|
|
229
|
-
if (fs_1.default.existsSync(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
293
|
+
// 先尝试目录模式(优先,支持多场景)
|
|
294
|
+
const dirPath = path_1.default.join(mockPath, key);
|
|
295
|
+
if (fs_1.default.existsSync(dirPath) && fs_1.default.statSync(dirPath).isDirectory()) {
|
|
296
|
+
// 读取接口配置(新格式)
|
|
297
|
+
const config = this.readInterfaceConfig(key, mockPath);
|
|
298
|
+
if (config) {
|
|
299
|
+
// 新格式:检查是否启用
|
|
300
|
+
if (config.enabled === false) {
|
|
301
|
+
console.log(chalk_1.default.yellow(`[WarehouseMock] ✗ 接口已禁用: ${key}`));
|
|
302
|
+
break; // 接口被禁用,不拦截
|
|
303
|
+
}
|
|
304
|
+
// 根据 activeScene 读取场景文件
|
|
305
|
+
const activeScene = config.activeScene || 'default';
|
|
306
|
+
const sceneFilePath = path_1.default.join(dirPath, `${activeScene}.json`);
|
|
307
|
+
if (fs_1.default.existsSync(sceneFilePath)) {
|
|
308
|
+
filePath = sceneFilePath;
|
|
309
|
+
matchedName = key;
|
|
310
|
+
matched = true;
|
|
311
|
+
interfaceConfig = config;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
// 旧格式:查找 mock: true 的文件(向后兼容)
|
|
317
|
+
const files = fs_1.default.readdirSync(dirPath).filter(f => f.endsWith('.json') && f !== '.config.json');
|
|
318
|
+
for (const file of files) {
|
|
319
|
+
const fullPath = path_1.default.join(dirPath, file);
|
|
320
|
+
try {
|
|
321
|
+
const content = fs_1.default.readFileSync(fullPath, 'utf-8');
|
|
322
|
+
const jsonData = JSON.parse(content);
|
|
323
|
+
if (jsonData.mock === true) {
|
|
324
|
+
filePath = fullPath;
|
|
325
|
+
matchedName = key;
|
|
326
|
+
matched = true;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
catch (e) {
|
|
331
|
+
// 文件解析失败,跳过
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (matched)
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
234
337
|
}
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
matchedName = value;
|
|
338
|
+
// 再尝试单文件模式(向后兼容)
|
|
339
|
+
if (!matched) {
|
|
340
|
+
const queryFilePath = path_1.default.join(mockPath, `${key}.json`);
|
|
341
|
+
if (fs_1.default.existsSync(queryFilePath) && fs_1.default.statSync(queryFilePath).isFile()) {
|
|
342
|
+
filePath = queryFilePath;
|
|
343
|
+
matchedName = key;
|
|
242
344
|
matched = true;
|
|
243
345
|
break;
|
|
244
346
|
}
|
|
245
347
|
}
|
|
348
|
+
// 也尝试匹配 value (例如 method=user.taurus.pointInfo)
|
|
349
|
+
const value = params.get(key);
|
|
350
|
+
if (value && !matched) {
|
|
351
|
+
const valueDirPath = path_1.default.join(mockPath, value);
|
|
352
|
+
if (fs_1.default.existsSync(valueDirPath) && fs_1.default.statSync(valueDirPath).isDirectory()) {
|
|
353
|
+
// 读取接口配置(新格式)
|
|
354
|
+
const config = this.readInterfaceConfig(value, mockPath);
|
|
355
|
+
if (config) {
|
|
356
|
+
// 新格式:检查是否启用
|
|
357
|
+
if (config.enabled === false) {
|
|
358
|
+
console.log(chalk_1.default.yellow(`[WarehouseMock] ✗ 接口已禁用: ${value}`));
|
|
359
|
+
break;
|
|
360
|
+
}
|
|
361
|
+
// 根据 activeScene 读取场景文件
|
|
362
|
+
const activeScene = config.activeScene || 'default';
|
|
363
|
+
const sceneFilePath = path_1.default.join(valueDirPath, `${activeScene}.json`);
|
|
364
|
+
if (fs_1.default.existsSync(sceneFilePath)) {
|
|
365
|
+
filePath = sceneFilePath;
|
|
366
|
+
matchedName = value;
|
|
367
|
+
matched = true;
|
|
368
|
+
interfaceConfig = config;
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// 旧格式:查找 mock: true 的文件(向后兼容)
|
|
374
|
+
const files = fs_1.default.readdirSync(valueDirPath).filter(f => f.endsWith('.json') && f !== '.config.json');
|
|
375
|
+
for (const file of files) {
|
|
376
|
+
const fullPath = path_1.default.join(valueDirPath, file);
|
|
377
|
+
try {
|
|
378
|
+
const content = fs_1.default.readFileSync(fullPath, 'utf-8');
|
|
379
|
+
const jsonData = JSON.parse(content);
|
|
380
|
+
if (jsonData.mock === true) {
|
|
381
|
+
filePath = fullPath;
|
|
382
|
+
matchedName = value;
|
|
383
|
+
matched = true;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (e) {
|
|
388
|
+
// 跳过
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (matched)
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (!matched) {
|
|
396
|
+
const valueFilePath = path_1.default.join(mockPath, `${value}.json`);
|
|
397
|
+
if (fs_1.default.existsSync(valueFilePath) && fs_1.default.statSync(valueFilePath).isFile()) {
|
|
398
|
+
filePath = valueFilePath;
|
|
399
|
+
matchedName = value;
|
|
400
|
+
matched = true;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
246
405
|
}
|
|
247
406
|
}
|
|
248
407
|
}
|
|
@@ -275,21 +434,38 @@ class WarehouseMockPlugin {
|
|
|
275
434
|
}
|
|
276
435
|
if (matched) {
|
|
277
436
|
console.log(chalk_1.default.green(`[WarehouseMock] ✓ 拦截: ${req.url || url}`));
|
|
278
|
-
|
|
437
|
+
// 获取延时配置(优先使用接口级别的 delay)
|
|
438
|
+
const delayTime = (interfaceConfig === null || interfaceConfig === void 0 ? void 0 : interfaceConfig.delay) !== undefined
|
|
439
|
+
? interfaceConfig.delay
|
|
440
|
+
: this.options.delay || 0;
|
|
441
|
+
// 获取场景名称
|
|
442
|
+
const sceneName = (interfaceConfig === null || interfaceConfig === void 0 ? void 0 : interfaceConfig.activeScene) || path_1.default.basename(filePath, '.json');
|
|
443
|
+
console.log(chalk_1.default.gray(` → 场景: ${sceneName}`));
|
|
444
|
+
if (delayTime > 0) {
|
|
445
|
+
console.log(chalk_1.default.gray(` → 延迟: ${delayTime}ms`));
|
|
446
|
+
}
|
|
279
447
|
// 模拟网络延迟
|
|
280
448
|
const respond = () => {
|
|
281
449
|
try {
|
|
282
|
-
const
|
|
450
|
+
const fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
283
451
|
try {
|
|
284
|
-
const jsonData = JSON.parse(
|
|
452
|
+
const jsonData = JSON.parse(fileContent);
|
|
453
|
+
// 新格式:纯净的场景数据(不包含 mock、scene、delay 等元数据)
|
|
454
|
+
// 旧格式:包含 mock、scene、delay、data 字段
|
|
455
|
+
let responseData = jsonData;
|
|
456
|
+
// 兼容旧格式
|
|
457
|
+
if (jsonData.mock !== undefined && jsonData.data !== undefined) {
|
|
458
|
+
responseData = jsonData.data;
|
|
459
|
+
}
|
|
285
460
|
res.setHeader('Content-Type', 'application/json');
|
|
286
461
|
res.setHeader('X-Mock-By', 'WarehouseMock');
|
|
287
|
-
res.
|
|
462
|
+
res.setHeader('X-Mock-Scene', sceneName);
|
|
463
|
+
res.end(JSON.stringify(responseData));
|
|
288
464
|
}
|
|
289
465
|
catch (jsonErr) {
|
|
290
466
|
console.warn(chalk_1.default.yellow(`[WarehouseMock] 无效的 JSON 文件: ${filePath}`));
|
|
291
467
|
res.setHeader('Content-Type', 'text/plain');
|
|
292
|
-
res.end(
|
|
468
|
+
res.end(fileContent);
|
|
293
469
|
}
|
|
294
470
|
}
|
|
295
471
|
catch (e) {
|
|
@@ -298,8 +474,9 @@ class WarehouseMockPlugin {
|
|
|
298
474
|
res.end('Mock Read Error');
|
|
299
475
|
}
|
|
300
476
|
};
|
|
301
|
-
|
|
302
|
-
|
|
477
|
+
// 应用延迟
|
|
478
|
+
if (delayTime > 0) {
|
|
479
|
+
setTimeout(respond, delayTime);
|
|
303
480
|
}
|
|
304
481
|
else {
|
|
305
482
|
respond();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "warehouse-mock",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "一个专为 Vue 2 项目设计的 Webpack 插件,支持 RPC 风格接口 mock,零业务代码侵入,实时更新",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -36,7 +36,12 @@
|
|
|
36
36
|
"homepage": "https://github.com/CodeMomentYY/warehouse-mock#readme",
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"chalk": "^4.1.2",
|
|
39
|
-
"chokidar": "^3.5.3"
|
|
39
|
+
"chokidar": "^3.5.3",
|
|
40
|
+
"i": "^0.3.7",
|
|
41
|
+
"npm": "^11.7.0"
|
|
42
|
+
},
|
|
43
|
+
"optionalDependencies": {
|
|
44
|
+
"warehouse-mock-admin": "^1.0.0"
|
|
40
45
|
},
|
|
41
46
|
"devDependencies": {
|
|
42
47
|
"@types/node": "^18.0.0",
|
|
@@ -51,6 +56,5 @@
|
|
|
51
56
|
},
|
|
52
57
|
"engines": {
|
|
53
58
|
"node": ">=12.0.0"
|
|
54
|
-
}
|
|
55
|
-
"gitHead": "dd7a56f686885eebc054fa738235ddf882ca02fa"
|
|
59
|
+
}
|
|
56
60
|
}
|