@simplysm/sd-cli 14.0.15 → 14.0.17
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 +4 -3
- package/dist/angular/client-transform-stylesheet.d.ts +2 -0
- package/dist/angular/client-transform-stylesheet.d.ts.map +1 -1
- package/dist/angular/client-transform-stylesheet.js +88 -2
- package/dist/angular/client-transform-stylesheet.js.map +1 -1
- package/dist/angular/vite-angular-plugin.d.ts +7 -0
- package/dist/angular/vite-angular-plugin.d.ts.map +1 -1
- package/dist/angular/vite-angular-plugin.js +78 -16
- package/dist/angular/vite-angular-plugin.js.map +1 -1
- package/dist/capacitor/capacitor.d.ts.map +1 -1
- package/dist/capacitor/capacitor.js +24 -13
- package/dist/capacitor/capacitor.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +8 -9
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/device.d.ts +1 -1
- package/dist/commands/device.d.ts.map +1 -1
- package/dist/commands/device.js +61 -12
- package/dist/commands/device.js.map +1 -1
- package/dist/commands/lint.d.ts +0 -1
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +2 -3
- package/dist/commands/lint.js.map +1 -1
- package/dist/commands/publish.js +3 -3
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/replace-deps.js +1 -1
- package/dist/commands/replace-deps.js.map +1 -1
- package/dist/commands/typecheck.d.ts.map +1 -1
- package/dist/commands/typecheck.js +1 -2
- package/dist/commands/typecheck.js.map +1 -1
- package/dist/electron/electron.d.ts +3 -2
- package/dist/electron/electron.d.ts.map +1 -1
- package/dist/electron/electron.js +54 -31
- package/dist/electron/electron.js.map +1 -1
- package/dist/engines/BaseEngine.js +1 -1
- package/dist/engines/BaseEngine.js.map +1 -1
- package/dist/engines/NgtscEngine.d.ts.map +1 -1
- package/dist/engines/NgtscEngine.js +0 -1
- package/dist/engines/NgtscEngine.js.map +1 -1
- package/dist/engines/ServerEsbuildEngine.d.ts.map +1 -1
- package/dist/engines/ServerEsbuildEngine.js +0 -1
- package/dist/engines/ServerEsbuildEngine.js.map +1 -1
- package/dist/engines/TscEngine.d.ts.map +1 -1
- package/dist/engines/TscEngine.js +0 -1
- package/dist/engines/TscEngine.js.map +1 -1
- package/dist/engines/ViteEngine.d.ts.map +1 -1
- package/dist/engines/ViteEngine.js +10 -1
- package/dist/engines/ViteEngine.js.map +1 -1
- package/dist/engines/index.d.ts +0 -10
- package/dist/engines/index.d.ts.map +1 -1
- package/dist/engines/index.js +0 -5
- package/dist/engines/index.js.map +1 -1
- package/dist/engines/types.d.ts +0 -1
- package/dist/engines/types.d.ts.map +1 -1
- package/dist/infra/SignalHandler.d.ts +1 -6
- package/dist/infra/SignalHandler.d.ts.map +1 -1
- package/dist/infra/SignalHandler.js +4 -13
- package/dist/infra/SignalHandler.js.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/BuildOrchestrator.js +7 -12
- package/dist/orchestrators/BuildOrchestrator.js.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.d.ts.map +1 -1
- package/dist/orchestrators/DevWatchOrchestrator.js +18 -11
- package/dist/orchestrators/DevWatchOrchestrator.js.map +1 -1
- package/dist/sd-cli-entry.d.ts +0 -1
- package/dist/sd-cli-entry.d.ts.map +1 -1
- package/dist/sd-cli-entry.js +13 -16
- package/dist/sd-cli-entry.js.map +1 -1
- package/dist/sd-cli.js +1 -1
- package/dist/sd-cli.js.map +1 -1
- package/dist/sd-config.types.d.ts +12 -2
- package/dist/sd-config.types.d.ts.map +1 -1
- package/dist/utils/angular-compiler.d.ts.map +1 -1
- package/dist/utils/angular-compiler.js +20 -13
- package/dist/utils/angular-compiler.js.map +1 -1
- package/dist/utils/esbuild-config.d.ts +1 -1
- package/dist/utils/esbuild-config.d.ts.map +1 -1
- package/dist/utils/esbuild-config.js +1 -4
- package/dist/utils/esbuild-config.js.map +1 -1
- package/dist/utils/ngtsc-build-core.d.ts.map +1 -1
- package/dist/utils/ngtsc-build-core.js +3 -0
- package/dist/utils/ngtsc-build-core.js.map +1 -1
- package/dist/utils/orchestrator-utils.js +1 -1
- package/dist/utils/orchestrator-utils.js.map +1 -1
- package/dist/utils/tsc-build.d.ts +5 -0
- package/dist/utils/tsc-build.d.ts.map +1 -1
- package/dist/utils/tsc-build.js +2 -1
- package/dist/utils/tsc-build.js.map +1 -1
- package/dist/utils/vite-config.d.ts +1 -1
- package/dist/utils/vite-config.d.ts.map +1 -1
- package/dist/utils/vite-config.js +22 -53
- package/dist/utils/vite-config.js.map +1 -1
- package/dist/utils/vite-pwa-plugin.d.ts +9 -0
- package/dist/utils/vite-pwa-plugin.d.ts.map +1 -0
- package/dist/utils/vite-pwa-plugin.js +139 -0
- package/dist/utils/vite-pwa-plugin.js.map +1 -0
- package/dist/utils/worker-utils.d.ts +2 -5
- package/dist/utils/worker-utils.d.ts.map +1 -1
- package/dist/utils/worker-utils.js +5 -11
- package/dist/utils/worker-utils.js.map +1 -1
- package/dist/workers/client.worker.d.ts.map +1 -1
- package/dist/workers/client.worker.js +9 -3
- package/dist/workers/client.worker.js.map +1 -1
- package/dist/workers/library-build.worker.d.ts.map +1 -1
- package/dist/workers/library-build.worker.js +6 -2
- package/dist/workers/library-build.worker.js.map +1 -1
- package/dist/workers/ngtsc-build.worker.js +2 -2
- package/dist/workers/ngtsc-build.worker.js.map +1 -1
- package/dist/workers/server-build.worker.d.ts.map +1 -1
- package/dist/workers/server-build.worker.js +6 -2
- package/dist/workers/server-build.worker.js.map +1 -1
- package/dist/workers/server-runtime.worker.js +4 -4
- package/dist/workers/server-runtime.worker.js.map +1 -1
- package/docs/config.md +30 -2
- package/docs/pwa-configuration-types.md +1 -1
- package/package.json +8 -10
- package/src/angular/client-transform-stylesheet.ts +104 -2
- package/src/angular/vite-angular-plugin.ts +92 -31
- package/src/capacitor/capacitor.ts +25 -26
- package/src/commands/check.ts +8 -11
- package/src/commands/device.ts +71 -17
- package/src/commands/lint.ts +2 -3
- package/src/commands/publish.ts +3 -3
- package/src/commands/replace-deps.ts +1 -1
- package/src/commands/typecheck.ts +1 -2
- package/src/electron/electron.ts +62 -43
- package/src/engines/BaseEngine.ts +1 -1
- package/src/engines/NgtscEngine.ts +0 -1
- package/src/engines/ServerEsbuildEngine.ts +0 -1
- package/src/engines/TscEngine.ts +0 -1
- package/src/engines/ViteEngine.ts +9 -1
- package/src/engines/index.ts +0 -10
- package/src/engines/types.ts +0 -1
- package/src/infra/SignalHandler.ts +4 -14
- package/src/orchestrators/BuildOrchestrator.ts +7 -9
- package/src/orchestrators/DevWatchOrchestrator.ts +22 -10
- package/src/sd-cli-entry.ts +17 -24
- package/src/sd-cli.ts +1 -1
- package/src/sd-config.types.ts +13 -2
- package/src/utils/angular-compiler.ts +21 -21
- package/src/utils/esbuild-config.ts +2 -5
- package/src/utils/ngtsc-build-core.ts +7 -0
- package/src/utils/orchestrator-utils.ts +1 -1
- package/src/utils/tsc-build.ts +7 -0
- package/src/utils/vite-config.ts +23 -55
- package/src/utils/vite-pwa-plugin.ts +168 -0
- package/src/utils/worker-utils.ts +5 -11
- package/src/workers/client.worker.ts +11 -3
- package/src/workers/library-build.worker.ts +6 -2
- package/src/workers/ngtsc-build.worker.ts +2 -2
- package/src/workers/server-build.worker.ts +7 -2
- package/src/workers/server-runtime.worker.ts +4 -4
- package/tests/angular/client-transform-stylesheet.spec.ts +43 -0
- package/tests/angular/find-affected-by-scss.spec.ts +37 -0
- package/tests/angular/fixtures/basic-app/scss/_colors.scss +1 -0
- package/tests/angular/fixtures/basic-app/scss/_variables.scss +3 -0
- package/tests/angular/fixtures/basic-app/src/styled.component.ts +14 -0
- package/tests/angular/linker-disk-cache.spec.ts +158 -0
- package/tests/angular/scss-disk-cache.spec.ts +162 -0
- package/tests/angular/vite-angular-plugin-hmr-fallback.spec.ts +15 -15
- package/tests/angular/vite-angular-plugin-hmr.spec.ts +9 -9
- package/tests/angular/vite-angular-plugin-lint.spec.ts +4 -4
- package/tests/angular/vite-angular-plugin-scss-hmr.spec.ts +87 -0
- package/tests/angular/vite-angular-plugin.spec.ts +15 -15
- package/tests/capacitor/capacitor-icon.spec.ts +2 -4
- package/tests/capacitor/capacitor-init.spec.ts +2 -4
- package/tests/capacitor/capacitor-workspace.spec.ts +2 -4
- package/tests/commands/device.spec.ts +108 -8
- package/tests/commands/publish.spec.ts +2 -2
- package/tests/commands/typecheck.spec.ts +1 -1
- package/tests/electron/electron.spec.ts +24 -17
- package/tests/engines/ngtsc-engine.spec.ts +0 -3
- package/tests/engines/server-esbuild-engine.spec.ts +0 -3
- package/tests/engines/tsc-engine.spec.ts +1 -2
- package/tests/engines/vite-engine.spec.ts +0 -2
- package/tests/infra/signal-handler.spec.ts +1 -12
- package/tests/orchestrators/build-orchestrator.spec.ts +1 -7
- package/tests/orchestrators/dev-watch-orchestrator.spec.ts +24 -66
- package/tests/utils/angular-compiler.spec.ts +1396 -32
- package/tests/utils/esbuild-config.spec.ts +4 -7
- package/tests/utils/{ngtsc-build-core-angular-compiler.spec.ts → ngtsc-build-core.spec.ts} +142 -11
- package/tests/utils/orchestrator-utils.spec.ts +2 -2
- package/tests/utils/sd-config.spec.ts +2 -2
- package/tests/utils/tsc-build.spec.ts +4 -1
- package/tests/utils/vite-config.spec.ts +130 -261
- package/tests/utils/vite-pwa-plugin.acc.spec.ts +143 -0
- package/tests/utils/vite-pwa-plugin.spec.ts +350 -0
- package/tests/utils/worker-utils.spec.ts +8 -7
- package/tests/workers/client-worker.spec.ts +50 -1
- package/tests/workers/dev-port-file.verify.md +6 -0
- package/tests/workers/library-build-lint.spec.ts +1 -1
- package/tests/workers/library-build-worker.spec.ts +1 -1
- package/tests/workers/ngtsc-build-lint.spec.ts +1 -1
- package/tests/workers/server-build-lint.spec.ts +1 -1
- package/tests/workers/server-build-worker.spec.ts +1 -1
- package/tests/workers/server-runtime-worker.spec.ts +8 -1
- package/dist/infra/WorkerManager.d.ts +0 -40
- package/dist/infra/WorkerManager.d.ts.map +0 -1
- package/dist/infra/WorkerManager.js +0 -59
- package/dist/infra/WorkerManager.js.map +0 -1
- package/dist/utils/SdCliReporter.d.ts +0 -18
- package/dist/utils/SdCliReporter.d.ts.map +0 -1
- package/dist/utils/SdCliReporter.js +0 -144
- package/dist/utils/SdCliReporter.js.map +0 -1
- package/src/infra/WorkerManager.ts +0 -65
- package/src/utils/SdCliReporter.ts +0 -177
- package/tests/angular/scss-compiler-async.spec.ts +0 -54
- package/tests/commands/dev.spec.ts +0 -53
- package/tests/commands/watch.spec.ts +0 -53
- package/tests/infra/worker-manager.spec.ts +0 -63
- package/tests/utils/angular-compiler-emit.spec.ts +0 -570
- package/tests/utils/angular-compiler-init.spec.ts +0 -705
- package/tests/utils/angular-compiler-update.spec.ts +0 -293
- package/tests/utils/build-env.spec.ts +0 -33
- package/tests/utils/ngtsc-build-core-transform-stylesheet.spec.ts +0 -124
- package/tests/utils/ngtsc-scss-refactor.spec.ts +0 -47
package/src/commands/device.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import path from "path";
|
|
1
4
|
import { consola } from "consola";
|
|
2
5
|
import { pathx } from "@simplysm/core-node";
|
|
3
6
|
import { SdError } from "@simplysm/core-common";
|
|
@@ -8,7 +11,7 @@ import { Electron } from "../electron/electron";
|
|
|
8
11
|
const logger = consola.withTag("sd:cli:device");
|
|
9
12
|
|
|
10
13
|
export interface DeviceOptions {
|
|
11
|
-
|
|
14
|
+
target?: string;
|
|
12
15
|
url?: string;
|
|
13
16
|
options: string[];
|
|
14
17
|
}
|
|
@@ -21,45 +24,96 @@ export interface DeviceOptions {
|
|
|
21
24
|
*/
|
|
22
25
|
export async function runDevice(options: DeviceOptions): Promise<void> {
|
|
23
26
|
const cwd = process.cwd();
|
|
24
|
-
const sdConfig = await loadSdConfig({ cwd, dev: true,
|
|
27
|
+
const sdConfig = await loadSdConfig({ cwd, dev: true, opt: options.options });
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
// target 결정: 미지정 시 유일한 client 패키지 자동 선택
|
|
30
|
+
let targetName: string;
|
|
31
|
+
if (options.target != null) {
|
|
32
|
+
targetName = options.target;
|
|
33
|
+
} else {
|
|
34
|
+
const clientNames = Object.entries(sdConfig.packages)
|
|
35
|
+
.filter(([, cfg]) => cfg != null && cfg.target === "client")
|
|
36
|
+
.map(([name]) => name);
|
|
37
|
+
if (clientNames.length === 0) {
|
|
38
|
+
throw new SdError("device 실행 가능한 client 패키지가 없습니다.");
|
|
39
|
+
}
|
|
40
|
+
if (clientNames.length > 1) {
|
|
41
|
+
throw new SdError(
|
|
42
|
+
`client 패키지가 여러 개입니다. target을 지정해주세요: ${clientNames.join(", ")}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
targetName = clientNames[0];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const pkgConfig = sdConfig.packages[targetName];
|
|
27
49
|
if (pkgConfig == null) {
|
|
28
|
-
throw new SdError(`패키지를 찾을 수 없습니다: ${
|
|
50
|
+
throw new SdError(`패키지를 찾을 수 없습니다: ${targetName}`);
|
|
29
51
|
}
|
|
30
52
|
if (pkgConfig.target !== "client") {
|
|
31
|
-
throw new SdError(
|
|
53
|
+
throw new SdError(
|
|
54
|
+
`client 패키지만 device 실행이 가능합니다: ${targetName} (target: ${pkgConfig.target})`,
|
|
55
|
+
);
|
|
32
56
|
}
|
|
33
57
|
|
|
34
58
|
const clientConfig = pkgConfig;
|
|
35
|
-
const pkgDir = pathx.posixResolve(cwd, "packages",
|
|
59
|
+
const pkgDir = pathx.posixResolve(cwd, "packages", targetName);
|
|
36
60
|
|
|
37
61
|
// 서버 URL 결정
|
|
38
62
|
let serverUrl = options.url;
|
|
39
63
|
if (serverUrl == null) {
|
|
40
64
|
if (typeof clientConfig.server === "number") {
|
|
41
|
-
serverUrl = `http://localhost:${clientConfig.server}
|
|
65
|
+
serverUrl = `http://localhost:${clientConfig.server}/${targetName}/`;
|
|
42
66
|
} else {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
67
|
+
// server가 패키지명(string)인 경우: .dev-port 파일에서 포트 자동 탐지
|
|
68
|
+
const portFile = path.join(pkgDir, "dist", ".dev-port");
|
|
69
|
+
let portStr: string;
|
|
70
|
+
try {
|
|
71
|
+
portStr = fs.readFileSync(portFile, "utf-8").trim();
|
|
72
|
+
} catch {
|
|
73
|
+
throw new SdError(
|
|
74
|
+
"dev 서버가 실행 중이 아닙니다. 먼저 pnpm dev를 실행해주세요.",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
const port = Number(portStr);
|
|
78
|
+
serverUrl = `http://localhost:${port}/${targetName}/`;
|
|
79
|
+
|
|
80
|
+
// HTTP 헬스체크
|
|
81
|
+
const alive = await checkDevServer(serverUrl);
|
|
82
|
+
if (!alive) {
|
|
83
|
+
throw new SdError(
|
|
84
|
+
"dev 서버가 응답하지 않습니다. pnpm dev를 다시 실행해주세요.",
|
|
85
|
+
);
|
|
86
|
+
}
|
|
46
87
|
}
|
|
47
88
|
}
|
|
48
89
|
|
|
49
90
|
// Electron이 Capacitor보다 우선
|
|
50
91
|
if (clientConfig.electron != null) {
|
|
51
|
-
logger.start(`${
|
|
92
|
+
logger.start(`${targetName} (electron) 실행 중...`);
|
|
52
93
|
const electron = await Electron.create(pkgDir, clientConfig.electron, clientConfig.exclude);
|
|
53
94
|
await electron.run(serverUrl);
|
|
54
|
-
logger.success(`${
|
|
95
|
+
logger.success(`${targetName} (electron) 실행 완료`);
|
|
55
96
|
} else if (clientConfig.capacitor != null) {
|
|
56
|
-
logger.start(`${
|
|
97
|
+
logger.start(`${targetName} (capacitor) 실행 중...`);
|
|
57
98
|
const cap = await Capacitor.create(pkgDir, clientConfig.capacitor, clientConfig.exclude);
|
|
58
99
|
await cap.run(serverUrl);
|
|
59
|
-
logger.success(`${
|
|
100
|
+
logger.success(`${targetName} (capacitor) 실행 완료`);
|
|
60
101
|
} else {
|
|
61
|
-
throw new SdError(
|
|
62
|
-
`${options.package}에 capacitor 또는 electron 설정이 없습니다.`,
|
|
63
|
-
);
|
|
102
|
+
throw new SdError(`${targetName}에 capacitor 또는 electron 설정이 없습니다.`);
|
|
64
103
|
}
|
|
65
104
|
}
|
|
105
|
+
|
|
106
|
+
/** dev 서버가 응답하는지 HTTP GET으로 확인한다. */
|
|
107
|
+
function checkDevServer(url: string): Promise<boolean> {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
const req = http.get(url, (res) => {
|
|
110
|
+
res.resume();
|
|
111
|
+
resolve(true);
|
|
112
|
+
});
|
|
113
|
+
req.on("error", () => resolve(false));
|
|
114
|
+
req.setTimeout(3000, () => {
|
|
115
|
+
req.destroy();
|
|
116
|
+
resolve(false);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
}
|
package/src/commands/lint.ts
CHANGED
|
@@ -2,8 +2,7 @@ import { ESLint } from "eslint";
|
|
|
2
2
|
import { createJiti } from "jiti";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { fsx, pathx } from "@simplysm/core-node";
|
|
5
|
-
import "@simplysm/core-common";
|
|
6
|
-
import { SdError } from "@simplysm/core-common";
|
|
5
|
+
import { env, SdError } from "@simplysm/core-common";
|
|
7
6
|
import { consola } from "consola";
|
|
8
7
|
|
|
9
8
|
//#region Types
|
|
@@ -128,7 +127,7 @@ export async function executeLint(options: LintOptions): Promise<LintResult> {
|
|
|
128
127
|
|
|
129
128
|
// TIMING 환경변수 설정
|
|
130
129
|
if (timing) {
|
|
131
|
-
|
|
130
|
+
env("TIMING", "1");
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
// ESLint 설정 로드
|
package/src/commands/publish.ts
CHANGED
|
@@ -61,7 +61,7 @@ function replaceEnvVariables(str: string, version: string, projectPath: string):
|
|
|
61
61
|
if (envName === "PROJECT") {
|
|
62
62
|
return projectPath;
|
|
63
63
|
}
|
|
64
|
-
return (
|
|
64
|
+
return env(envName) ?? match;
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// 치환되지 않은 환경변수가 남아있으면 에러 발생
|
|
@@ -147,7 +147,7 @@ async function ensureSshAuth(
|
|
|
147
147
|
// 개인키 파싱 시도 (암호화 또는 형식 오류 시 Error 반환)
|
|
148
148
|
const parsed = utils.parseKey(privateKeyData);
|
|
149
149
|
const isKeyEncrypted = parsed instanceof Error;
|
|
150
|
-
const sshAgent =
|
|
150
|
+
const sshAgent = env("SSH_AUTH_SOCK");
|
|
151
151
|
|
|
152
152
|
// 각 서버에 대해 키 인증 검증
|
|
153
153
|
for (const [label, target] of sshTargets) {
|
|
@@ -483,7 +483,7 @@ export async function runPublish(options: PublishOptions): Promise<void> {
|
|
|
483
483
|
// sd.config.ts 로드
|
|
484
484
|
let sdConfig: SdConfig;
|
|
485
485
|
try {
|
|
486
|
-
sdConfig = await loadSdConfig({ cwd, dev: false,
|
|
486
|
+
sdConfig = await loadSdConfig({ cwd, dev: false, opt: options.options });
|
|
487
487
|
logger.debug("sd.config.ts 로드 완료");
|
|
488
488
|
} catch (err) {
|
|
489
489
|
logger.error(`sd.config.ts 로드 실패: ${err instanceof Error ? err.message : err}`);
|
|
@@ -16,7 +16,7 @@ export interface ReplaceDepsOptions {
|
|
|
16
16
|
export async function runReplaceDeps(opts: ReplaceDepsOptions): Promise<void> {
|
|
17
17
|
const cwd = process.cwd();
|
|
18
18
|
|
|
19
|
-
const sdConfig = await loadSdConfig({ cwd, dev: false,
|
|
19
|
+
const sdConfig = await loadSdConfig({ cwd, dev: false, opt: opts.options });
|
|
20
20
|
|
|
21
21
|
if (sdConfig.replaceDeps == null) {
|
|
22
22
|
consola.warn("sd.config.ts에 replaceDeps 설정이 없습니다.");
|
|
@@ -97,7 +97,7 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
// sd.config.ts 로드
|
|
100
|
-
const sdConfig = await loadSdConfig({ cwd, dev: false,
|
|
100
|
+
const sdConfig = await loadSdConfig({ cwd, dev: false, opt: options.options });
|
|
101
101
|
logger.debug("sd.config.ts 로드 완료");
|
|
102
102
|
|
|
103
103
|
// 워크스페이스 패키지 탐색 및 tests/를 설정에 병합
|
|
@@ -189,7 +189,6 @@ export async function executeTypecheck(options: TypecheckOptions): Promise<Typec
|
|
|
189
189
|
logger.debug(`[${label}] 스택 트레이스:\n${stack}`);
|
|
190
190
|
}
|
|
191
191
|
return {
|
|
192
|
-
success: false,
|
|
193
192
|
build: {
|
|
194
193
|
success: false,
|
|
195
194
|
errors: [`[${label}] ${message}`],
|
package/src/electron/electron.ts
CHANGED
|
@@ -3,20 +3,14 @@ import fs from "fs";
|
|
|
3
3
|
import module from "module";
|
|
4
4
|
import { cpx, fsx, pathx } from "@simplysm/core-node";
|
|
5
5
|
import { consola, LogLevels } from "consola";
|
|
6
|
-
import type { SdElectronConfig } from "../sd-config.types.js";
|
|
6
|
+
import type { NpmConfig, SdElectronConfig } from "../sd-config.types.js";
|
|
7
7
|
import { createEnvBanner } from "../utils/esbuild-config.js";
|
|
8
8
|
|
|
9
|
-
interface NpmConfig {
|
|
10
|
-
name: string;
|
|
11
|
-
version: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
dependencies?: Record<string, string>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
9
|
export class Electron {
|
|
17
10
|
private static readonly _logger = consola.withTag("sd:cli:electron");
|
|
18
11
|
|
|
19
12
|
private readonly _electronPath: string;
|
|
13
|
+
private readonly _srcPath: string;
|
|
20
14
|
|
|
21
15
|
private constructor(
|
|
22
16
|
private readonly _pkgPath: string,
|
|
@@ -25,6 +19,7 @@ export class Electron {
|
|
|
25
19
|
private readonly _exclude: string[],
|
|
26
20
|
) {
|
|
27
21
|
this._electronPath = pathx.posixResolve(this._pkgPath, ".electron");
|
|
22
|
+
this._srcPath = pathx.posixResolve(this._electronPath, "src");
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
static async create(
|
|
@@ -44,10 +39,6 @@ export class Electron {
|
|
|
44
39
|
}
|
|
45
40
|
}
|
|
46
41
|
|
|
47
|
-
private _localBin(name: string): string {
|
|
48
|
-
return pathx.posixResolve(this._pkgPath, "node_modules/.bin", name);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
42
|
private async _exec(
|
|
52
43
|
cmd: string,
|
|
53
44
|
args: string[],
|
|
@@ -70,20 +61,26 @@ export class Electron {
|
|
|
70
61
|
|
|
71
62
|
async initialize(): Promise<void> {
|
|
72
63
|
Electron._logger.debug("initialize 시작");
|
|
73
|
-
const srcPath = pathx.posixResolve(this._electronPath, "src");
|
|
74
64
|
|
|
75
65
|
Electron._logger.debug("package.json 설정 시작");
|
|
76
|
-
await this.
|
|
66
|
+
await this._setupNpmConf();
|
|
77
67
|
Electron._logger.debug("package.json 설정 완료");
|
|
78
68
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
// pnpm-workspace.yaml 생성 (상위 workspace 탐색 차단)
|
|
70
|
+
const workspaceYamlPath = pathx.posixResolve(this._srcPath, "pnpm-workspace.yaml");
|
|
71
|
+
if (!(await fsx.exists(workspaceYamlPath))) {
|
|
72
|
+
await fsx.write(workspaceYamlPath, "");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
Electron._logger.debug("pnpm install 시작");
|
|
76
|
+
await this._exec("pnpm", ["install"], this._srcPath);
|
|
77
|
+
await this._exec("pnpm", ["approve-builds", "--all"], this._srcPath);
|
|
78
|
+
Electron._logger.debug("pnpm install 완료");
|
|
82
79
|
|
|
83
80
|
const reinstallDeps = this._config.reinstallDependencies ?? [];
|
|
84
81
|
if (reinstallDeps.length > 0) {
|
|
85
82
|
Electron._logger.debug(`electron-rebuild 시작 (${reinstallDeps.join(", ")})`);
|
|
86
|
-
await this._exec(
|
|
83
|
+
await this._exec("pnpm", ["exec", "electron-rebuild"], this._srcPath);
|
|
87
84
|
Electron._logger.debug("electron-rebuild 완료");
|
|
88
85
|
}
|
|
89
86
|
Electron._logger.debug("initialize 완료");
|
|
@@ -91,9 +88,9 @@ export class Electron {
|
|
|
91
88
|
|
|
92
89
|
async run(url: string): Promise<void> {
|
|
93
90
|
Electron._logger.debug(`run 시작 (url: ${url})`);
|
|
94
|
-
const srcPath = pathx.posixResolve(this._electronPath, "src");
|
|
95
91
|
|
|
96
92
|
await this.initialize();
|
|
93
|
+
await this._copyPublicAssets();
|
|
97
94
|
|
|
98
95
|
const esbuild = await import("esbuild");
|
|
99
96
|
const entryPoint = pathx.posixResolve(this._pkgPath, "src/electron-main.ts");
|
|
@@ -104,7 +101,6 @@ export class Electron {
|
|
|
104
101
|
|
|
105
102
|
const builtinModules = module.builtinModules.flatMap((m) => [m, `node:${m}`]);
|
|
106
103
|
const reinstallDeps = this._config.reinstallDependencies ?? [];
|
|
107
|
-
await fsx.mkdir(srcPath);
|
|
108
104
|
|
|
109
105
|
let currentElectron: cpx.SpawnProcess | null = null;
|
|
110
106
|
let isRestarting = false;
|
|
@@ -112,9 +108,10 @@ export class Electron {
|
|
|
112
108
|
|
|
113
109
|
const spawnElectron = () => {
|
|
114
110
|
Electron._logger.debug("Electron 프로세스 시작");
|
|
115
|
-
currentElectron = cpx.spawn(
|
|
116
|
-
cwd:
|
|
111
|
+
currentElectron = cpx.spawn("pnpm", ["exec", "electron", "."], {
|
|
112
|
+
cwd: this._srcPath,
|
|
117
113
|
stdio: "inherit",
|
|
114
|
+
shell: true,
|
|
118
115
|
reject: false,
|
|
119
116
|
});
|
|
120
117
|
|
|
@@ -132,7 +129,7 @@ export class Electron {
|
|
|
132
129
|
Electron._logger.debug("esbuild context 생성 시작");
|
|
133
130
|
const ctx = await esbuild.context({
|
|
134
131
|
entryPoints: [entryPoint],
|
|
135
|
-
outfile: pathx.posixResolve(
|
|
132
|
+
outfile: pathx.posixResolve(this._srcPath, "electron-main.js"),
|
|
136
133
|
platform: "node",
|
|
137
134
|
target: "node20",
|
|
138
135
|
format: "cjs",
|
|
@@ -205,18 +202,19 @@ export class Electron {
|
|
|
205
202
|
|
|
206
203
|
async build(outPath: string): Promise<void> {
|
|
207
204
|
Electron._logger.debug("build 시작");
|
|
208
|
-
|
|
205
|
+
|
|
206
|
+
await this.initialize();
|
|
209
207
|
|
|
210
208
|
Electron._logger.debug("메인 프로세스 번들링 시작");
|
|
211
|
-
await this._bundleMainProcess(
|
|
209
|
+
await this._bundleMainProcess();
|
|
212
210
|
Electron._logger.debug("메인 프로세스 번들링 완료");
|
|
213
211
|
|
|
214
212
|
Electron._logger.debug("웹 에셋 복사 시작");
|
|
215
|
-
await this._copyWebAssets(outPath
|
|
213
|
+
await this._copyWebAssets(outPath);
|
|
216
214
|
Electron._logger.debug("웹 에셋 복사 완료");
|
|
217
215
|
|
|
218
216
|
Electron._logger.debug("electron-builder 실행 시작");
|
|
219
|
-
await this._runElectronBuilder(
|
|
217
|
+
await this._runElectronBuilder();
|
|
220
218
|
Electron._logger.debug("electron-builder 실행 완료");
|
|
221
219
|
|
|
222
220
|
Electron._logger.debug("빌드 산출물 복사 시작");
|
|
@@ -230,14 +228,19 @@ export class Electron {
|
|
|
230
228
|
|
|
231
229
|
//#region Private - Initialization
|
|
232
230
|
|
|
233
|
-
private async
|
|
234
|
-
await fsx.mkdir(
|
|
231
|
+
private async _setupNpmConf(): Promise<void> {
|
|
232
|
+
await fsx.mkdir(this._srcPath);
|
|
233
|
+
|
|
234
|
+
const mainDeps: Record<string, string | undefined> = {
|
|
235
|
+
...this._npmConfig.dependencies,
|
|
236
|
+
...this._npmConfig.devDependencies,
|
|
237
|
+
};
|
|
235
238
|
|
|
236
239
|
const reinstallDeps = this._config.reinstallDependencies ?? [];
|
|
237
240
|
|
|
238
241
|
const dependencies: Record<string, string> = {};
|
|
239
242
|
for (const dep of reinstallDeps) {
|
|
240
|
-
const version =
|
|
243
|
+
const version = mainDeps[dep];
|
|
241
244
|
if (version != null) {
|
|
242
245
|
dependencies[dep] = version;
|
|
243
246
|
}
|
|
@@ -245,33 +248,39 @@ export class Electron {
|
|
|
245
248
|
|
|
246
249
|
for (const excludePkg of this._exclude) {
|
|
247
250
|
if (!(excludePkg in dependencies)) {
|
|
248
|
-
const version =
|
|
251
|
+
const version = mainDeps[excludePkg];
|
|
249
252
|
if (version != null) {
|
|
250
253
|
dependencies[excludePkg] = version;
|
|
251
254
|
}
|
|
252
255
|
}
|
|
253
256
|
}
|
|
254
257
|
|
|
258
|
+
const devDependencies: Record<string, string> = {};
|
|
259
|
+
devDependencies["electron"] = "^41";
|
|
260
|
+
devDependencies["@electron/rebuild"] = "^4";
|
|
261
|
+
devDependencies["electron-builder"] = "^26";
|
|
262
|
+
|
|
255
263
|
const packageJson: Record<string, unknown> = {
|
|
256
264
|
name: this._npmConfig.name.replace(/^@/, "").replace(/\//, "-"),
|
|
257
265
|
version: this._npmConfig.version,
|
|
258
266
|
description: this._npmConfig.description,
|
|
259
267
|
main: "electron-main.js",
|
|
260
268
|
dependencies,
|
|
269
|
+
devDependencies,
|
|
261
270
|
};
|
|
262
271
|
|
|
263
272
|
if (this._config.postInstallScript != null) {
|
|
264
273
|
packageJson["scripts"] = { postinstall: this._config.postInstallScript };
|
|
265
274
|
}
|
|
266
275
|
|
|
267
|
-
await fsx.writeJson(pathx.posixResolve(
|
|
276
|
+
await fsx.writeJson(pathx.posixResolve(this._srcPath, "package.json"), packageJson, { space: 2 });
|
|
268
277
|
}
|
|
269
278
|
|
|
270
279
|
//#endregion
|
|
271
280
|
|
|
272
281
|
//#region Private - Bundling
|
|
273
282
|
|
|
274
|
-
private async _bundleMainProcess(
|
|
283
|
+
private async _bundleMainProcess(): Promise<void> {
|
|
275
284
|
const esbuild = await import("esbuild");
|
|
276
285
|
const entryPoint = pathx.posixResolve(this._pkgPath, "src/electron-main.ts");
|
|
277
286
|
|
|
@@ -282,14 +291,12 @@ export class Electron {
|
|
|
282
291
|
const builtinModules = module.builtinModules.flatMap((m) => [m, `node:${m}`]);
|
|
283
292
|
const reinstallDeps = this._config.reinstallDependencies ?? [];
|
|
284
293
|
|
|
285
|
-
await fsx.mkdir(outDir);
|
|
286
|
-
|
|
287
294
|
const envBanner = createEnvBanner(this._config.env);
|
|
288
295
|
|
|
289
296
|
Electron._logger.debug(`esbuild 번들링: ${entryPoint}`);
|
|
290
297
|
await esbuild.build({
|
|
291
298
|
entryPoints: [entryPoint],
|
|
292
|
-
outfile: pathx.posixResolve(
|
|
299
|
+
outfile: pathx.posixResolve(this._srcPath, "electron-main.js"),
|
|
293
300
|
platform: "node",
|
|
294
301
|
target: "node20",
|
|
295
302
|
format: "cjs",
|
|
@@ -301,15 +308,27 @@ export class Electron {
|
|
|
301
308
|
|
|
302
309
|
//#endregion
|
|
303
310
|
|
|
311
|
+
private async _copyPublicAssets(): Promise<void> {
|
|
312
|
+
const publicPath = pathx.posixResolve(this._pkgPath, "public");
|
|
313
|
+
if (!(await fsx.exists(publicPath))) return;
|
|
314
|
+
|
|
315
|
+
const items = await fsx.readdir(publicPath);
|
|
316
|
+
for (const item of items) {
|
|
317
|
+
const source = pathx.posixResolve(publicPath, item);
|
|
318
|
+
const dest = pathx.posixResolve(this._srcPath, item);
|
|
319
|
+
await fsx.copy(source, dest);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
304
323
|
//#region Private - Build
|
|
305
324
|
|
|
306
|
-
private async _copyWebAssets(outPath: string
|
|
325
|
+
private async _copyWebAssets(outPath: string): Promise<void> {
|
|
307
326
|
const items = await fsx.readdir(outPath);
|
|
308
327
|
for (const item of items) {
|
|
309
328
|
if (item === "electron") continue;
|
|
310
329
|
|
|
311
330
|
const source = pathx.posixResolve(outPath, item);
|
|
312
|
-
const dest = pathx.posixResolve(
|
|
331
|
+
const dest = pathx.posixResolve(this._srcPath, item);
|
|
313
332
|
await fsx.copy(source, dest);
|
|
314
333
|
}
|
|
315
334
|
}
|
|
@@ -331,7 +350,7 @@ export class Electron {
|
|
|
331
350
|
}
|
|
332
351
|
}
|
|
333
352
|
|
|
334
|
-
private async _runElectronBuilder(
|
|
353
|
+
private async _runElectronBuilder(): Promise<void> {
|
|
335
354
|
if (!Electron._canCreateSymlink()) {
|
|
336
355
|
throw new Error(
|
|
337
356
|
"Symlink 생성 권한이 필요합니다. Windows 개발자 모드를 활성화하세요.",
|
|
@@ -349,7 +368,7 @@ export class Electron {
|
|
|
349
368
|
},
|
|
350
369
|
nsis: this._config.nsisOptions ?? {},
|
|
351
370
|
directories: {
|
|
352
|
-
app:
|
|
371
|
+
app: this._srcPath,
|
|
353
372
|
output: distPath,
|
|
354
373
|
},
|
|
355
374
|
removePackageScripts: false,
|
|
@@ -366,9 +385,9 @@ export class Electron {
|
|
|
366
385
|
|
|
367
386
|
Electron._logger.debug(`electron-builder 설정: ${configFilePath}`);
|
|
368
387
|
await this._exec(
|
|
369
|
-
|
|
370
|
-
["--win", "--config", configFilePath],
|
|
371
|
-
this.
|
|
388
|
+
"pnpm",
|
|
389
|
+
["exec", "electron-builder", "--win", "--config", configFilePath],
|
|
390
|
+
this._srcPath,
|
|
372
391
|
);
|
|
373
392
|
}
|
|
374
393
|
|
|
@@ -112,7 +112,7 @@ export abstract class BaseEngine<
|
|
|
112
112
|
logger.debug(`[${this._pkg.name}] run 시작 (js: ${output.js}, dts: ${output.dts}, env: ${output.env ?? "none"})`);
|
|
113
113
|
this._createWorker();
|
|
114
114
|
const result = await this._callBuild(output);
|
|
115
|
-
logger.debug(`[${this._pkg.name}] run 완료 (success: ${result.success})`);
|
|
115
|
+
logger.debug(`[${this._pkg.name}] run 완료 (success: ${result.build.success})`);
|
|
116
116
|
return result;
|
|
117
117
|
}
|
|
118
118
|
|
package/src/engines/TscEngine.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "path";
|
|
1
3
|
import { Worker, type WorkerProxy } from "@simplysm/core-node";
|
|
2
4
|
import { consola } from "consola";
|
|
3
5
|
import type * as ClientWorkerModule from "../workers/client.worker";
|
|
@@ -73,6 +75,7 @@ export class ViteEngine implements BuildEngine {
|
|
|
73
75
|
configs: this._pkg.config.configs,
|
|
74
76
|
browserSupport: this._pkg.config.browserSupport,
|
|
75
77
|
enableLint: output.lint,
|
|
78
|
+
pwa: this._pkg.config.pwa,
|
|
76
79
|
exclude: this._pkg.config.exclude,
|
|
77
80
|
outDir: this._outDir,
|
|
78
81
|
base: this._base,
|
|
@@ -80,7 +83,6 @@ export class ViteEngine implements BuildEngine {
|
|
|
80
83
|
|
|
81
84
|
logger.debug(`[${this._pkg.name}] ViteEngine.run 완료 (success: ${result.success})`);
|
|
82
85
|
return {
|
|
83
|
-
success: result.success,
|
|
84
86
|
build: {
|
|
85
87
|
success: result.success,
|
|
86
88
|
errors: result.errors ?? [],
|
|
@@ -185,6 +187,7 @@ export class ViteEngine implements BuildEngine {
|
|
|
185
187
|
replaceDeps: this._replaceDeps,
|
|
186
188
|
browserSupport: this._pkg.config.browserSupport,
|
|
187
189
|
enableLint: output.lint,
|
|
190
|
+
pwa: this._pkg.config.pwa,
|
|
188
191
|
exclude: this._pkg.config.exclude,
|
|
189
192
|
});
|
|
190
193
|
}
|
|
@@ -194,6 +197,11 @@ export class ViteEngine implements BuildEngine {
|
|
|
194
197
|
*/
|
|
195
198
|
async stop(): Promise<void> {
|
|
196
199
|
logger.debug(`[${this._pkg.name}] ViteEngine stop 시작`);
|
|
200
|
+
|
|
201
|
+
// .dev-port 파일 삭제
|
|
202
|
+
const portFile = path.join(this._pkg.dir, "dist", ".dev-port");
|
|
203
|
+
try { fs.unlinkSync(portFile); } catch { /* 파일 없으면 무시 */ }
|
|
204
|
+
|
|
197
205
|
await stopEngineWorker(this._worker, this._isWatchMode);
|
|
198
206
|
this._worker = undefined;
|
|
199
207
|
logger.debug(`[${this._pkg.name}] ViteEngine stop 완료`);
|
package/src/engines/index.ts
CHANGED
|
@@ -10,16 +10,6 @@ import type { BuildEngine, BuildPackageInfo, ClientPackageInfo, ServerPackageInf
|
|
|
10
10
|
|
|
11
11
|
const logger = consola.withTag("sd:cli:engine");
|
|
12
12
|
|
|
13
|
-
export { BaseEngine } from "./BaseEngine";
|
|
14
|
-
export type { BaseEngineOptions, CommonBuildWorkerEvents, CommonBuildWorkerModule } from "./BaseEngine";
|
|
15
|
-
export { NgtscEngine } from "./NgtscEngine";
|
|
16
|
-
export type { NgtscEngineOptions } from "./NgtscEngine";
|
|
17
|
-
export { ServerEsbuildEngine } from "./ServerEsbuildEngine";
|
|
18
|
-
export type { ServerEsbuildEngineOptions } from "./ServerEsbuildEngine";
|
|
19
|
-
export { TscEngine } from "./TscEngine";
|
|
20
|
-
export type { TscEngineOptions } from "./TscEngine";
|
|
21
|
-
export { ViteEngine } from "./ViteEngine";
|
|
22
|
-
export type { ViteEngineOptions } from "./ViteEngine";
|
|
23
13
|
export type { BuildEngine, BuildOutput, BuildPackageInfo, ClientPackageInfo, EngineResult, PackageInfo, ServerPackageInfo } from "./types";
|
|
24
14
|
|
|
25
15
|
/**
|
package/src/engines/types.ts
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
export class SignalHandler {
|
|
8
8
|
private _terminateResolver: (() => void) | null = null;
|
|
9
9
|
private readonly _terminatePromise: Promise<void>;
|
|
10
|
-
private _terminated = false;
|
|
11
10
|
|
|
12
11
|
constructor() {
|
|
13
12
|
this._terminatePromise = new Promise((resolve) => {
|
|
@@ -17,8 +16,8 @@ export class SignalHandler {
|
|
|
17
16
|
const handler = () => {
|
|
18
17
|
process.off("SIGINT", handler);
|
|
19
18
|
process.off("SIGTERM", handler);
|
|
20
|
-
this._terminated = true;
|
|
21
19
|
this._terminateResolver?.();
|
|
20
|
+
this._terminateResolver = null;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
process.on("SIGINT", handler);
|
|
@@ -32,21 +31,12 @@ export class SignalHandler {
|
|
|
32
31
|
return this._terminatePromise;
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
/**
|
|
36
|
-
* 종료 여부를 확인한다
|
|
37
|
-
*/
|
|
38
|
-
isTerminated(): boolean {
|
|
39
|
-
return this._terminated;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
34
|
/**
|
|
43
35
|
* 프로그래밍 방식으로 종료를 요청한다
|
|
44
|
-
* (
|
|
36
|
+
* (테스트에서 종료를 트리거할 때 사용)
|
|
45
37
|
*/
|
|
46
38
|
requestTermination(): void {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this._terminateResolver?.();
|
|
50
|
-
}
|
|
39
|
+
this._terminateResolver?.();
|
|
40
|
+
this._terminateResolver = null;
|
|
51
41
|
}
|
|
52
42
|
}
|