jacky-proxy 1.0.0
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 +410 -0
- package/bin/jacky-proxy.js +137 -0
- package/package.json +64 -0
- package/scripts/generate-config.js +337 -0
- package/server.js +1022 -0
- package/src/commands/config-generate.js +26 -0
- package/src/commands/config-merge.js +29 -0
- package/src/commands/config-validate.js +30 -0
- package/src/commands/migrate.js +813 -0
- package/src/commands/rules-add.js +82 -0
- package/src/commands/rules-list.js +67 -0
- package/src/commands/rules-remove.js +43 -0
- package/src/commands/rules-test.js +72 -0
- package/src/commands/start.js +203 -0
- package/templates/mock-admin.html +736 -0
- package/tsconfig.json +18 -0
- package/utils/common/match-response.ts +491 -0
- package/utils/interface-identifier.ts +130 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rules add 命令实现
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
async function rulesAddCommand(options) {
|
|
9
|
+
const configPath = path.join(process.cwd(), options.config || 'config/match-rules.json');
|
|
10
|
+
|
|
11
|
+
// 加载现有配置
|
|
12
|
+
let config = {
|
|
13
|
+
global: { ignoreProps: [] },
|
|
14
|
+
interfaces: []
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (fs.existsSync(configPath)) {
|
|
18
|
+
try {
|
|
19
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(`❌ 读取配置文件失败: ${error.message}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 确保 interfaces 数组存在
|
|
27
|
+
if (!config.interfaces) {
|
|
28
|
+
config.interfaces = [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 检查接口是否已存在
|
|
32
|
+
const existingIndex = config.interfaces.findIndex(
|
|
33
|
+
r => r.interfaceName === options.interface
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const newRule = {
|
|
37
|
+
interfaceName: options.interface
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (options.ignore) {
|
|
41
|
+
newRule.ignoreProps = options.ignore.split(',').map(s => s.trim());
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (options.essential) {
|
|
45
|
+
newRule.essentialProps = options.essential.split(',').map(s => s.trim());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (options.deepIgnore !== undefined) {
|
|
49
|
+
newRule.deepIgnore = options.deepIgnore;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (existingIndex >= 0) {
|
|
53
|
+
// 更新现有规则
|
|
54
|
+
config.interfaces[existingIndex] = {
|
|
55
|
+
...config.interfaces[existingIndex],
|
|
56
|
+
...newRule
|
|
57
|
+
};
|
|
58
|
+
console.log(`✅ 更新接口规则: ${options.interface}`);
|
|
59
|
+
} else {
|
|
60
|
+
// 添加新规则
|
|
61
|
+
config.interfaces.push(newRule);
|
|
62
|
+
console.log(`✅ 添加接口规则: ${options.interface}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 保存配置
|
|
66
|
+
try {
|
|
67
|
+
// 确保目录存在
|
|
68
|
+
const configDir = path.dirname(configPath);
|
|
69
|
+
if (!fs.existsSync(configDir)) {
|
|
70
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
74
|
+
console.log(`✅ 配置已保存: ${configPath}`);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`❌ 保存配置文件失败: ${error.message}`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = rulesAddCommand;
|
|
82
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rules list 命令实现
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
async function rulesListCommand(options) {
|
|
9
|
+
const configPath = path.join(process.cwd(), options.config || 'config/match-rules.json');
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
console.error(`❌ 配置文件不存在: ${configPath}`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
18
|
+
|
|
19
|
+
console.log('\n📋 匹配规则配置:');
|
|
20
|
+
console.log('═══════════════════════════════════════════════════════\n');
|
|
21
|
+
|
|
22
|
+
// 全局规则
|
|
23
|
+
if (config.global) {
|
|
24
|
+
console.log('🌐 全局规则:');
|
|
25
|
+
if (config.global.ignoreProps && config.global.ignoreProps.length > 0) {
|
|
26
|
+
console.log(` 忽略属性: ${config.global.ignoreProps.join(', ')}`);
|
|
27
|
+
}
|
|
28
|
+
if (config.global.description) {
|
|
29
|
+
console.log(` 说明: ${config.global.description}`);
|
|
30
|
+
}
|
|
31
|
+
console.log('');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 接口规则
|
|
35
|
+
if (config.interfaces && config.interfaces.length > 0) {
|
|
36
|
+
console.log('🔧 接口规则:');
|
|
37
|
+
config.interfaces.forEach((rule, index) => {
|
|
38
|
+
console.log(`\n ${index + 1}. ${rule.interfaceName}`);
|
|
39
|
+
if (rule.ignoreProps && rule.ignoreProps.length > 0) {
|
|
40
|
+
console.log(` 忽略属性: ${rule.ignoreProps.join(', ')}`);
|
|
41
|
+
}
|
|
42
|
+
if (rule.essentialProps && rule.essentialProps.length > 0) {
|
|
43
|
+
console.log(` 必需属性: ${rule.essentialProps.join(', ')}`);
|
|
44
|
+
}
|
|
45
|
+
if (rule.deepIgnore !== undefined) {
|
|
46
|
+
console.log(` 深度忽略: ${rule.deepIgnore}`);
|
|
47
|
+
}
|
|
48
|
+
if (rule.sortProps && rule.sortProps.length > 0) {
|
|
49
|
+
console.log(` 排序配置: ${JSON.stringify(rule.sortProps)}`);
|
|
50
|
+
}
|
|
51
|
+
if (rule.description) {
|
|
52
|
+
console.log(` 说明: ${rule.description}`);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
console.log(' (无接口规则)');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('\n═══════════════════════════════════════════════════════');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error(`❌ 读取配置文件失败: ${error.message}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = rulesListCommand;
|
|
67
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rules remove 命令实现
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
async function rulesRemoveCommand(options) {
|
|
9
|
+
const configPath = path.join(process.cwd(), options.config || 'config/match-rules.json');
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(configPath)) {
|
|
12
|
+
console.error(`❌ 配置文件不存在: ${configPath}`);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
18
|
+
|
|
19
|
+
if (!config.interfaces) {
|
|
20
|
+
console.log('⚠️ 配置中没有接口规则');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const index = config.interfaces.findIndex(
|
|
25
|
+
r => r.interfaceName === options.interface
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
if (index === -1) {
|
|
29
|
+
console.log(`⚠️ 未找到接口规则: ${options.interface}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
config.interfaces.splice(index, 1);
|
|
34
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
35
|
+
console.log(`✅ 已删除接口规则: ${options.interface}`);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(`❌ 操作失败: ${error.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = rulesRemoveCommand;
|
|
43
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rules test 命令实现
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
async function rulesTestCommand(options) {
|
|
9
|
+
const configPath = path.join(process.cwd(), options.config || 'config/match-rules.json');
|
|
10
|
+
const requestPath = path.join(process.cwd(), options.request);
|
|
11
|
+
|
|
12
|
+
// 加载配置
|
|
13
|
+
if (!fs.existsSync(configPath)) {
|
|
14
|
+
console.error(`❌ 配置文件不存在: ${configPath}`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(requestPath)) {
|
|
19
|
+
console.error(`❌ 请求文件不存在: ${requestPath}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
25
|
+
const requestData = JSON.parse(fs.readFileSync(requestPath, 'utf-8'));
|
|
26
|
+
|
|
27
|
+
// 查找接口规则
|
|
28
|
+
const interfaceRule = config.interfaces?.find(
|
|
29
|
+
r => r.interfaceName === options.interface
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!interfaceRule) {
|
|
33
|
+
console.log(`⚠️ 未找到接口规则: ${options.interface}`);
|
|
34
|
+
console.log(' 使用全局规则进行测试');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log('\n🧪 测试匹配规则:');
|
|
38
|
+
console.log('═══════════════════════════════════════════════════════\n');
|
|
39
|
+
console.log(`接口名称: ${options.interface}`);
|
|
40
|
+
console.log(`请求文件: ${options.request}`);
|
|
41
|
+
console.log('\n配置的规则:');
|
|
42
|
+
|
|
43
|
+
if (interfaceRule) {
|
|
44
|
+
if (interfaceRule.ignoreProps) {
|
|
45
|
+
console.log(` 忽略属性: ${interfaceRule.ignoreProps.join(', ')}`);
|
|
46
|
+
}
|
|
47
|
+
if (interfaceRule.essentialProps) {
|
|
48
|
+
console.log(` 必需属性: ${interfaceRule.essentialProps.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (interfaceRule.deepIgnore !== undefined) {
|
|
51
|
+
console.log(` 深度忽略: ${interfaceRule.deepIgnore}`);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
console.log(' (使用全局规则)');
|
|
55
|
+
if (config.global?.ignoreProps) {
|
|
56
|
+
console.log(` 全局忽略属性: ${config.global.ignoreProps.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('\n请求数据:');
|
|
61
|
+
console.log(JSON.stringify(requestData, null, 2));
|
|
62
|
+
|
|
63
|
+
console.log('\n✅ 测试完成(此命令仅显示配置信息,实际匹配需要在服务器运行时测试)');
|
|
64
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`❌ 测试失败: ${error.message}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = rulesTestCommand;
|
|
72
|
+
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* start 命令实现
|
|
3
|
+
* 启动 Mock 服务器
|
|
4
|
+
* 支持:
|
|
5
|
+
* 1. 直接启动 Raw 文件夹(自动转换后启动)
|
|
6
|
+
* 2. 启动已有的 base-data + mocks 结构(通过 mock-id)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 查找项目根目录(包含 server.js 和 package.json 的目录)
|
|
14
|
+
*/
|
|
15
|
+
function findProjectRoot() {
|
|
16
|
+
// 从当前文件所在目录开始向上查找
|
|
17
|
+
let currentDir = __dirname;
|
|
18
|
+
|
|
19
|
+
// 当前文件在 src/commands/start.js,所以需要向上两级
|
|
20
|
+
// 但为了更通用,我们向上查找直到找到 server.js 或 package.json
|
|
21
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
22
|
+
const serverPath = path.join(currentDir, 'server.js');
|
|
23
|
+
const packagePath = path.join(currentDir, 'package.json');
|
|
24
|
+
|
|
25
|
+
if (fs.existsSync(serverPath) || fs.existsSync(packagePath)) {
|
|
26
|
+
return currentDir;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
currentDir = path.dirname(currentDir);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 如果没找到,返回默认的项目根目录(从 __dirname 向上两级)
|
|
33
|
+
return path.resolve(__dirname, '../..');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 检查路径是否是 Raw 文件夹(以 .folder 结尾的目录)
|
|
38
|
+
*/
|
|
39
|
+
function isRawFolder(pathStr) {
|
|
40
|
+
if (!pathStr) return false;
|
|
41
|
+
|
|
42
|
+
// 检查是否是绝对路径或相对路径
|
|
43
|
+
const fullPath = path.isAbsolute(pathStr)
|
|
44
|
+
? pathStr
|
|
45
|
+
: path.join(process.cwd(), pathStr);
|
|
46
|
+
|
|
47
|
+
// 检查路径是否存在且是目录
|
|
48
|
+
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isDirectory()) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 检查是否以 .folder 结尾
|
|
53
|
+
return path.basename(fullPath).endsWith('.folder');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 查找默认的 Raw 文件夹(以 .folder 结尾的文件夹)
|
|
58
|
+
*/
|
|
59
|
+
function findDefaultRawFolder() {
|
|
60
|
+
try {
|
|
61
|
+
const files = fs.readdirSync(process.cwd(), { withFileTypes: true });
|
|
62
|
+
const folderFiles = files
|
|
63
|
+
.filter(dirent => dirent.isDirectory() && dirent.name.endsWith('.folder'))
|
|
64
|
+
.map(dirent => path.join(process.cwd(), dirent.name));
|
|
65
|
+
|
|
66
|
+
if (folderFiles.length > 0) {
|
|
67
|
+
folderFiles.sort();
|
|
68
|
+
return folderFiles[0];
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// 忽略错误,返回 null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* start 命令主函数
|
|
79
|
+
*/
|
|
80
|
+
async function startCommand(mockIdOrPath, options) {
|
|
81
|
+
let finalMockId = mockIdOrPath;
|
|
82
|
+
|
|
83
|
+
// 检查是否是 Raw 文件夹路径
|
|
84
|
+
if (isRawFolder(mockIdOrPath)) {
|
|
85
|
+
console.log('🔍 检测到 Raw 文件夹,将自动转换后启动...');
|
|
86
|
+
|
|
87
|
+
const rawFolderPath = path.isAbsolute(mockIdOrPath)
|
|
88
|
+
? mockIdOrPath
|
|
89
|
+
: path.join(process.cwd(), mockIdOrPath);
|
|
90
|
+
|
|
91
|
+
// 如果设置了 --no-migrate,直接报错
|
|
92
|
+
if (options.noMigrate) {
|
|
93
|
+
console.error('错误: 指定了 --no-migrate,但提供的是 Raw 文件夹路径');
|
|
94
|
+
console.error('提示: 请先使用 jacky-proxy migrate 命令转换,或移除 --no-migrate 参数');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 执行迁移
|
|
99
|
+
const migrateCommand = require('./migrate');
|
|
100
|
+
const scenarioName = options.scenario || '场景1';
|
|
101
|
+
const targetFolder = options.target || 'mocks/test-folder';
|
|
102
|
+
const ignoreInterfaces = options.ignore
|
|
103
|
+
? options.ignore.split(',').map(s => s.trim()).filter(s => s)
|
|
104
|
+
: [];
|
|
105
|
+
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
108
|
+
console.log(' 自动迁移 Raw 文件夹');
|
|
109
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
110
|
+
console.log(`场景名称: ${scenarioName}`);
|
|
111
|
+
console.log(`目标文件夹: ${targetFolder}`);
|
|
112
|
+
console.log(`Raw 文件夹: ${rawFolderPath}`);
|
|
113
|
+
if (ignoreInterfaces.length > 0) {
|
|
114
|
+
console.log(`忽略接口: ${ignoreInterfaces.join(', ')}`);
|
|
115
|
+
}
|
|
116
|
+
console.log('');
|
|
117
|
+
|
|
118
|
+
// 调用迁移命令(非交互式)
|
|
119
|
+
const migrateOptions = {
|
|
120
|
+
scenario: scenarioName,
|
|
121
|
+
target: targetFolder,
|
|
122
|
+
raw: rawFolderPath,
|
|
123
|
+
ignore: options.ignore || '',
|
|
124
|
+
interactive: false
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
await migrateCommand(migrateOptions);
|
|
129
|
+
|
|
130
|
+
// 从配置文件中读取新创建的 mock-id(配置文件在工作目录)
|
|
131
|
+
const workDir = process.cwd();
|
|
132
|
+
const configPath = path.join(workDir, options.config || 'proxy.config.json');
|
|
133
|
+
if (fs.existsSync(configPath)) {
|
|
134
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
135
|
+
const folder = config.folders.list.find(f => f.path === targetFolder);
|
|
136
|
+
if (folder) {
|
|
137
|
+
finalMockId = String(folder.id);
|
|
138
|
+
console.log(`\n✅ 迁移完成,将使用场景 ID: ${finalMockId}`);
|
|
139
|
+
} else {
|
|
140
|
+
console.warn('警告: 无法在配置文件中找到新创建的场景,使用默认 ID: 1');
|
|
141
|
+
finalMockId = '1';
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
console.warn('警告: 配置文件不存在,使用默认 ID: 1');
|
|
145
|
+
finalMockId = '1';
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('迁移失败:', error.message);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
// 检查是否是数字(mock-id)
|
|
153
|
+
const mockIdNum = parseInt(mockIdOrPath);
|
|
154
|
+
if (isNaN(mockIdNum)) {
|
|
155
|
+
console.warn(`警告: "${mockIdOrPath}" 不是有效的 mock-id,将尝试作为 ID 使用`);
|
|
156
|
+
}
|
|
157
|
+
finalMockId = mockIdOrPath;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 设置环境变量
|
|
161
|
+
const workDir = process.cwd(); // 保存当前工作目录
|
|
162
|
+
process.env.MOCK_ID = finalMockId;
|
|
163
|
+
process.env.PORT = options.port || '5001';
|
|
164
|
+
process.env.WORK_DIR = workDir; // 设置工作目录环境变量
|
|
165
|
+
process.env.CONFIG_PATH = path.join(workDir, options.config || 'proxy.config.json');
|
|
166
|
+
process.env.DEBUG = options.debug ? 'true' : 'false'; // 设置 Debug 模式
|
|
167
|
+
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
170
|
+
console.log(' 启动 Mock 服务器');
|
|
171
|
+
console.log('═══════════════════════════════════════════════════════');
|
|
172
|
+
console.log(`场景 ID: ${finalMockId}`);
|
|
173
|
+
console.log(`端口: ${process.env.PORT}`);
|
|
174
|
+
console.log('');
|
|
175
|
+
|
|
176
|
+
// 查找项目根目录
|
|
177
|
+
const projectRoot = findProjectRoot();
|
|
178
|
+
const serverPath = path.join(projectRoot, 'server.js');
|
|
179
|
+
|
|
180
|
+
// 检查 server.js 是否存在
|
|
181
|
+
if (!fs.existsSync(serverPath)) {
|
|
182
|
+
console.error(`错误: 找不到 server.js 文件`);
|
|
183
|
+
console.error(` 期望位置: ${serverPath}`);
|
|
184
|
+
console.error(` 当前工作目录: ${process.cwd()}`);
|
|
185
|
+
console.error(` 项目根目录: ${projectRoot}`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 切换到项目根目录(这样 server.js 中的相对路径才能正确工作)
|
|
190
|
+
const originalCwd = process.cwd();
|
|
191
|
+
process.chdir(projectRoot);
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
require(serverPath);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error('启动服务器失败:', error);
|
|
197
|
+
process.chdir(originalCwd); // 恢复原始工作目录
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = startCommand;
|
|
203
|
+
|