wyt-cli 1.0.21 → 1.0.22

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.
@@ -3,6 +3,7 @@ import { execa } from 'execa';
3
3
  import { Command } from 'commander';
4
4
  import fs from 'fs-extra';
5
5
  import inquirer from 'inquirer';
6
+ import readline from 'readline';
6
7
 
7
8
  import { log_info, log_error, getInquirerOperationText } from '../lib/logger.js';
8
9
  import { checkTargetDir, getProjects } from '../lib/dir.js';
@@ -96,18 +97,19 @@ async function runProject(projects = [], appsDir) {
96
97
  });
97
98
 
98
99
  // 运行项目文档
99
- log_info(`🚀 启动项目文档...`);
100
- const docsPath = path.join(process.cwd(), 'docs');
101
- const docsProcess = execa(command, {
102
- cwd: docsPath,
103
- stdio: 'inherit',
104
- env: commandEnv,
105
- });
106
- docsProcess.on('exit', (code) => {
107
- if (code !== 0) log_error(`项目文档异常退出 (CODE: ${code})`);
108
- });
100
+ runDocsProjects(commandEnv);
101
+ // log_info(`🚀 启动项目文档...`);
102
+ // const docsPath = path.join(process.cwd(), 'docs');
103
+ // const docsProcess = execa(command, {
104
+ // cwd: docsPath,
105
+ // stdio: 'inherit',
106
+ // env: commandEnv,
107
+ // });
108
+ // docsProcess.on('exit', (code) => {
109
+ // if (code !== 0) log_error(`项目文档异常退出 (CODE: ${code})`);
110
+ // });
109
111
 
110
- // 运行项目
112
+ // 更新项目启动状态
111
113
  const configPath = path.join(process.cwd(), 'project.json');
112
114
  let config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
113
115
  if (config.apps) {
@@ -119,41 +121,192 @@ async function runProject(projects = [], appsDir) {
119
121
  };
120
122
  });
121
123
  }
122
- projects.forEach(async (project) => {
123
- const projectName = project.name;
124
- if (projectName) {
125
- const projectPath = path.join(appsDir, projectName);
126
- if (!fs.existsSync(projectPath)) {
127
- throw new Error(`项目 ${projectName} 不存在`);
128
- }
124
+ // 运行项目
125
+ // projects.forEach(async (project) => {
126
+ // const projectName = project.name;
127
+ // if (projectName) {
128
+ // const projectPath = path.join(appsDir, projectName);
129
+ // if (!fs.existsSync(projectPath)) {
130
+ // throw new Error(`项目 ${projectName} 不存在`);
131
+ // }
129
132
 
130
- // 执行命令
131
- log_info(`🚀 启动项目 ${projectName}...`);
132
- // 更新项目启动状态
133
- const targetIndex = config.apps.findIndex((app) => app.name === projectName);
134
- if (targetIndex !== -1) {
135
- config.apps[targetIndex].lastRun = true;
136
- }
133
+ // // 执行命令
134
+ // log_info(`🚀 启动项目 ${projectName}...`);
135
+ // // 更新项目启动状态
136
+ // const targetIndex = config.apps.findIndex((app) => app.name === projectName);
137
+ // if (targetIndex !== -1) {
138
+ // config.apps[targetIndex].lastRun = true;
139
+ // }
137
140
 
138
- const subprocess = execa(command, {
139
- cwd: projectPath,
140
- stdio: 'inherit',
141
- env: commandEnv,
142
- });
143
-
144
- // 新增信号处理逻辑
145
- process.on('SIGINT', () => {
146
- log_info('正在优雅关闭进程...');
147
- subprocess.kill('SIGINT'); // 杀死子进程
148
- process.exit(0); // 退出父进程
149
- });
150
- subprocess.on('exit', (code) => {
151
- if (code !== 0) log_error(`项目 ${projectName} 异常退出 (CODE: ${code})`);
152
- });
153
- }
154
- });
141
+ // execa(command, {
142
+ // cwd: projectPath,
143
+ // stdio: 'inherit',
144
+ // env: commandEnv,
145
+ // });
146
+ // }
147
+ // });
148
+ runAppsProjects(command, commandEnv, projects, appsDir, config);
155
149
 
156
150
  // 运行时配置更新
157
151
  const runtimeConfigPath = path.join(process.cwd(), 'runtime.config.json');
158
152
  fs.writeFileSync(runtimeConfigPath, JSON.stringify({ runtime_apps: config.apps }, null, 2));
159
153
  }
154
+
155
+ // 运行 apps 里面的项目
156
+
157
+ async function runAppsProjects(command, commandEnv, projects, appsDir, config) {
158
+ // 1. 创建一个数组来保存所有子进程的引用
159
+ const childProcesses = [];
160
+
161
+ // 2. 监听 Ctrl + C 信号
162
+ const handleSigint = () => {
163
+ console.log('\n🛑 检测到 Ctrl + C,正在关闭所有测试服务...');
164
+
165
+ // 遍历并杀死所有子进程
166
+ childProcesses.forEach((cp) => {
167
+ if (!cp.killed) {
168
+ cp.kill('SIGTERM');
169
+ }
170
+ });
171
+
172
+ // 退出主进程
173
+ process.exit(0);
174
+ };
175
+
176
+ // 常规监听(Linux/macOS 有效)
177
+ process.on('SIGINT', handleSigint);
178
+
179
+ // 强制监听终端输入(Windows 环境下必须加这一段)
180
+ if (process.platform === 'win32') {
181
+ const rl = readline.createInterface({
182
+ input: process.stdin,
183
+ output: process.stdout,
184
+ });
185
+
186
+ rl.on('SIGINT', function () {
187
+ // 当 readline 捕获到 Ctrl+C 时,手动触发 process 的 SIGINT 事件
188
+ process.emit('SIGINT');
189
+ });
190
+ }
191
+
192
+ // 运行所有项目
193
+ try {
194
+ for (const project of projects) {
195
+ const projectName = project.name;
196
+ if (projectName) {
197
+ const projectPath = path.join(appsDir, projectName);
198
+ if (!fs.existsSync(projectPath)) {
199
+ throw new Error(`项目 ${projectName} 不存在`);
200
+ }
201
+
202
+ log_info(`🚀 启动项目 ${projectName}...`);
203
+
204
+ const targetIndex = config.apps.findIndex((app) => app.name === projectName);
205
+ if (targetIndex !== -1) {
206
+ config.apps[targetIndex].lastRun = true;
207
+ }
208
+
209
+ // 3. 执行命令,并将返回的子进程实例存入数组
210
+ const cp = execa(command, {
211
+ cwd: projectPath,
212
+ stdio: 'inherit',
213
+ env: commandEnv,
214
+ cleanup: true, // 当父进程退出时,自动杀死子进程
215
+ });
216
+
217
+ childProcesses.push(cp);
218
+
219
+ // 可选:监听单个进程的意外退出
220
+ cp.on('exit', (code) => {
221
+ if (code !== 0 && code !== null) {
222
+ log_info(`⚠️ 项目 ${projectName} 已退出,退出码: ${code}`);
223
+ }
224
+ });
225
+ }
226
+ }
227
+
228
+ // 4. 保持主进程存活,直到所有子进程都结束
229
+ // 因为 dev 服务通常不会主动结束,所以这里会一直挂起,直到按下 Ctrl+C
230
+ await Promise.all(childProcesses.map((cp) => cp.catch(() => {})));
231
+
232
+ console.log('✅ 所有服务已正常退出');
233
+ } catch (error) {
234
+ console.error('❌ 启动过程中发生错误:', error.message);
235
+
236
+ // 如果启动阶段就报错,也要清理可能已经启动的子进程
237
+ childProcesses.forEach((cp) => cp.kill());
238
+ process.exit(1);
239
+ } finally {
240
+ // 移除监听,防止内存泄漏
241
+ process.removeListener('SIGINT', handleSigint);
242
+ }
243
+ }
244
+
245
+ // 运行文档项目
246
+ function runDocsProjects(commandEnv) {
247
+ const docsPath = path.join(process.cwd(), 'docs');
248
+
249
+ // 根据操作系统构建不同的启动命令
250
+ let terminalCommand;
251
+ let terminalArgs;
252
+
253
+ if (process.platform === 'win32') {
254
+ // Windows: 使用 cmd 的 start 命令开启新窗口
255
+ // /c: 执行完毕后关闭窗口(这里不用,我们要保持窗口)
256
+ // /k: 执行完毕后保留窗口(非常适合运行 dev server)
257
+ terminalCommand = 'cmd';
258
+ terminalArgs = [
259
+ '/c',
260
+ 'start',
261
+ 'VitePress Docs', // 新终端窗口的标题
262
+ 'cmd',
263
+ '/k',
264
+ `cd ${docsPath} && vitepress dev --port 7000`, // 在新窗口中执行的命令
265
+ ];
266
+ } else {
267
+ // macOS / Linux:
268
+ // macOS 默认使用 open -a Terminal
269
+ // Linux 桌面环境通常支持 xdg-open 或直接运行终端程序
270
+ // 这里以 macOS 为例,如果是 Linux,可能需要替换为 'gnome-terminal' 或 'xterm'
271
+
272
+ if (process.platform === 'darwin') {
273
+ // macOS: 使用 AppleScript 打开 Terminal.app 并执行命令
274
+ terminalCommand = 'osascript';
275
+ terminalArgs = [
276
+ '-e',
277
+ `tell application "Terminal"
278
+ do script "cd ${docsPath} && vitepress dev --port 7000"
279
+ activate
280
+ end tell`,
281
+ ];
282
+ } else {
283
+ // Linux (以 gnome-terminal 为例,根据你的桌面环境可能需要调整)
284
+ terminalCommand = 'gnome-terminal';
285
+ terminalArgs = [
286
+ '--',
287
+ 'bash',
288
+ '-c',
289
+ `cd ${docsPath} && vitepress dev --port 7000; exec bash`, // exec bash 保证进程结束后终端不关闭
290
+ ];
291
+ }
292
+ }
293
+
294
+ log_info(`🚀 在新终端窗口中启动项目文档...`);
295
+
296
+ try {
297
+ // 注意:这里不需要再指定 cwd 为 docsPath 了,因为我们在命令里已经处理了目录切换
298
+ // 也不需要 stdio: 'inherit',因为它的输出会去新窗口
299
+ const docsProcess = execa(terminalCommand, terminalArgs, {
300
+ stdio: 'ignore', // 忽略输入输出,因为它在新窗口里
301
+ env: commandEnv,
302
+ detached: true, // 关键:让该进程独立于父进程运行
303
+ });
304
+
305
+ // 关键:取消父进程对子进程的引用,让操作系统接管
306
+ docsProcess.unref();
307
+
308
+ // 注意:此时不需要也不应该将 docsProcess push 到 childProcesses 数组里了!
309
+ } catch (error) {
310
+ log_error(`❌ 启动文档终端失败: ${error.message}`);
311
+ }
312
+ }
@@ -2,11 +2,11 @@ import { createRouter, createWebHashHistory } from 'vue-router';
2
2
  import { defaultRoutes } from './router-list.json';
3
3
  const basename = process.env.NODE_ENV === 'production' ? '/<%= projectName %>/' : '';
4
4
 
5
- // let autoRoutes = `<%- JSON.stringify(routeConfig) %>`;
5
+ const modules = import.meta.glob('/src/views/**/index.vue');
6
6
  const autoRoutes = defaultRoutes.map((item) => {
7
7
  return {
8
8
  ...item,
9
- component: () => import(/* @vite-ignore */ item.component),
9
+ component: modules[item.component],
10
10
  };
11
11
  });
12
12
  const routes = [
@@ -19,6 +19,7 @@ export default defineConfig({
19
19
  '/finweb': {
20
20
  target: ProxyURL,
21
21
  changeOrigin: true,
22
+ secure: false,
22
23
  rewrite: (path) => path.replace(/^\/finweb/, '/finweb'),
23
24
  // 添加 CORS 头
24
25
  configure: (proxy) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wyt-cli",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "description": "HRP3.0 项目命令行工具",
5
5
  "main": "index.js",
6
6
  "bin": {