@infly/libs 2.0.52 → 2.0.54
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/cli.js +0 -0
- package/cli/project-command.js +96 -12
- package/package.json +17 -18
package/bin/cli.js
CHANGED
|
File without changes
|
package/cli/project-command.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// 配置驱动的公共项目命令编排。
|
|
2
|
-
const {
|
|
2
|
+
const { spawn, spawnSync } = require("node:child_process");
|
|
3
3
|
const fs = require("node:fs");
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
|
|
@@ -77,17 +77,101 @@ function commandParts(command) {
|
|
|
77
77
|
return { command: parts[0], args: parts.slice(1) };
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
function attachChildLifecycle(child, command, resolve, reject) {
|
|
81
|
+
// 把子进程的生命周期(信号转发/退出语义)挂接到一个已启动的 child 上。
|
|
82
|
+
const forwardSignal = (signal) => {
|
|
83
|
+
try {
|
|
84
|
+
child.kill(signal);
|
|
85
|
+
} catch {
|
|
86
|
+
// 子进程已退出时忽略转发失败
|
|
87
|
+
}
|
|
88
|
+
// Windows 下 cmd 批处理在 Ctrl+C 时会弹"终止批处理操作吗(Y/N)?"等待输入,主进程等
|
|
89
|
+
// 子进程 exit 会永久阻塞;补杀整棵进程树(taskkill /T)并立即退出主进程,保证终端干净。
|
|
90
|
+
if (process.platform === "win32" && child.pid) {
|
|
91
|
+
try {
|
|
92
|
+
spawnSync("taskkill", ["/T", "/F", "/PID", String(child.pid)], {
|
|
93
|
+
stdio: "ignore",
|
|
94
|
+
windowsHide: true,
|
|
95
|
+
});
|
|
96
|
+
} catch {
|
|
97
|
+
// taskkill 失败不影响退出:子进程可能已结束
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
process.exit(0);
|
|
101
|
+
};
|
|
102
|
+
process.once("SIGINT", forwardSignal);
|
|
103
|
+
process.once("SIGTERM", forwardSignal);
|
|
104
|
+
|
|
105
|
+
const cleanup = () => {
|
|
106
|
+
process.removeListener("SIGINT", forwardSignal);
|
|
107
|
+
process.removeListener("SIGTERM", forwardSignal);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
child.on("error", (error) => {
|
|
111
|
+
cleanup();
|
|
112
|
+
reject(error);
|
|
113
|
+
});
|
|
114
|
+
child.on("exit", (code, signal) => {
|
|
115
|
+
cleanup();
|
|
116
|
+
// 被信号终止(如用户 Ctrl+C)视为正常结束:dev server 由中断信号退出,
|
|
117
|
+
// 主进程随后返回,CLI 自然退出,不将 Ctrl+C 视为命令失败。
|
|
118
|
+
if (code === 0 || signal) {
|
|
119
|
+
resolve({ signal: signal || null });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const error = new Error(`Command failed with exit code ${code ?? "unknown"}: ${command}`);
|
|
123
|
+
error.code = code;
|
|
124
|
+
reject(error);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function spawnCommand(command, args, options, useShell) {
|
|
84
129
|
// shell=true 时按 build-utils/command.js 约定传单字符串,规避 DEP0190
|
|
85
130
|
const [cmd, cmdArgs] = useShell ? [[command, ...args].join(" "), []] : [command, args];
|
|
86
|
-
execFileSync
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
131
|
+
// 用 spawn(异步、非阻塞)替代 execFileSync:dev 场景(长驻进程)下,
|
|
132
|
+
// execFileSync 同步阻塞 + 多层 cmd/pnpm 嵌套在 Windows 上 Ctrl+C 后易留孤儿进程占用终端与端口。
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
const child = spawn(cmd, cmdArgs, {
|
|
135
|
+
cwd: options.cwd,
|
|
136
|
+
env: options.env,
|
|
137
|
+
stdio: "inherit",
|
|
138
|
+
shell: useShell,
|
|
139
|
+
});
|
|
140
|
+
attachChildLifecycle(child, command, resolve, reject);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function defaultRunCommand(command, args, options) {
|
|
145
|
+
// 非 Windows 统一走无 shell 形态。
|
|
146
|
+
if (process.platform !== "win32") {
|
|
147
|
+
return spawnCommand(command, args, options, false);
|
|
148
|
+
}
|
|
149
|
+
// Windows: 先尝试无 shell 直跑(.exe,如 node)——避免 cmd 批处理层在 Ctrl+C 时弹
|
|
150
|
+
// "终止批处理操作吗(Y/N)?" 等待输入;.CMD 垫片(如 pnpm/npm)无 shell 会 ENOENT,回退 cmd shell。
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const child = spawn(command, args, {
|
|
153
|
+
cwd: options.cwd,
|
|
154
|
+
env: options.env,
|
|
155
|
+
stdio: "inherit",
|
|
156
|
+
shell: false,
|
|
157
|
+
});
|
|
158
|
+
let settled = false;
|
|
159
|
+
child.once("error", (error) => {
|
|
160
|
+
if (settled) return;
|
|
161
|
+
settled = true;
|
|
162
|
+
if (error.code === "ENOENT") {
|
|
163
|
+
// .cmd/.bat 垫片:回退 cmd shell(保留原有行为)
|
|
164
|
+
spawnCommand(command, args, options, true).then(resolve, reject);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
reject(error);
|
|
168
|
+
});
|
|
169
|
+
child.once("spawn", () => {
|
|
170
|
+
if (settled) return;
|
|
171
|
+
settled = true;
|
|
172
|
+
// 无 shell 直跑成功:挂接生命周期到当前 child(不再二次启动)
|
|
173
|
+
attachChildLifecycle(child, command, resolve, reject);
|
|
174
|
+
});
|
|
91
175
|
});
|
|
92
176
|
}
|
|
93
177
|
|
|
@@ -146,7 +230,7 @@ async function runProjectCommand(options = {}, dependencies = {}) {
|
|
|
146
230
|
const parts = commandParts(devConfig.command);
|
|
147
231
|
const env = { ...process.env, VUE_APP_PLATFORM: targetName };
|
|
148
232
|
if (options.dryRun) printDryRun(parts.command, parts.args, env);
|
|
149
|
-
else runCommand(parts.command, parts.args, { cwd: configDir, env });
|
|
233
|
+
else await runCommand(parts.command, parts.args, { cwd: configDir, env });
|
|
150
234
|
return { action, target: targetName };
|
|
151
235
|
}
|
|
152
236
|
|
|
@@ -191,7 +275,7 @@ async function runProjectCommand(options = {}, dependencies = {}) {
|
|
|
191
275
|
const parts = commandParts(step.command);
|
|
192
276
|
const args = [...parts.args, ...step.extraArgs];
|
|
193
277
|
if (options.dryRun) printDryRun(parts.command, args, env);
|
|
194
|
-
else runCommand(parts.command, args, { cwd: configDir, env });
|
|
278
|
+
else await runCommand(parts.command, args, { cwd: configDir, env });
|
|
195
279
|
}
|
|
196
280
|
}
|
|
197
281
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infly/libs",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.54",
|
|
4
4
|
"description": "不受前端框架限制的独立工具库",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -23,21 +23,6 @@
|
|
|
23
23
|
"!**/*.test.js",
|
|
24
24
|
"!**/*.test.mjs"
|
|
25
25
|
],
|
|
26
|
-
"scripts": {
|
|
27
|
-
"test": "vitest run",
|
|
28
|
-
"test:coverage": "vitest run --coverage",
|
|
29
|
-
"test:watch": "vitest",
|
|
30
|
-
"check": "vitest run core-entry.test.js",
|
|
31
|
-
"prepublishOnly": "pnpm test",
|
|
32
|
-
"lint": "eslint .",
|
|
33
|
-
"lint:strict": "eslint . --max-warnings 0",
|
|
34
|
-
"postinstall": "node adapters/vue2/postinstall.js",
|
|
35
|
-
"publishPkg": "npm publish --access=public --registry=https://registry.npmjs.org/",
|
|
36
|
-
"preview": "infly-libs --preview",
|
|
37
|
-
"preview:no-build": "infly-libs --preview --no-build",
|
|
38
|
-
"origin:preview": "infly-libs --preview",
|
|
39
|
-
"origin:preview:no-build": "infly-libs --preview --no-build"
|
|
40
|
-
},
|
|
41
26
|
"bin": {
|
|
42
27
|
"infly-libs": "bin/cli.js"
|
|
43
28
|
},
|
|
@@ -74,7 +59,7 @@
|
|
|
74
59
|
"author": "Kahal",
|
|
75
60
|
"license": "ISC",
|
|
76
61
|
"dependencies": {
|
|
77
|
-
"@infly/ts-libs": "^0.1.
|
|
62
|
+
"@infly/ts-libs": "^0.1.15",
|
|
78
63
|
"connect": "^3.7.0",
|
|
79
64
|
"dotenv": "16.6.1",
|
|
80
65
|
"enquirer": "^2.4.1",
|
|
@@ -135,5 +120,19 @@
|
|
|
135
120
|
"staging [禁用更新版本号的环境, 比如测试环境构建不需要更新version, 不配置默认禁用stage测试环境]"
|
|
136
121
|
]
|
|
137
122
|
}
|
|
123
|
+
},
|
|
124
|
+
"scripts": {
|
|
125
|
+
"test": "vitest run",
|
|
126
|
+
"test:coverage": "vitest run --coverage",
|
|
127
|
+
"test:watch": "vitest",
|
|
128
|
+
"check": "vitest run core-entry.test.js",
|
|
129
|
+
"lint": "eslint .",
|
|
130
|
+
"lint:strict": "eslint . --max-warnings 0",
|
|
131
|
+
"postinstall": "node adapters/vue2/postinstall.js",
|
|
132
|
+
"publishPkg": "pnpm publish --access=public --registry=https://registry.npmjs.org/ --no-git-checks",
|
|
133
|
+
"preview": "infly-libs --preview",
|
|
134
|
+
"preview:no-build": "infly-libs --preview --no-build",
|
|
135
|
+
"origin:preview": "infly-libs --preview",
|
|
136
|
+
"origin:preview:no-build": "infly-libs --preview --no-build"
|
|
138
137
|
}
|
|
139
|
-
}
|
|
138
|
+
}
|