@simplysm/sd-cli 13.0.10 → 13.0.12

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.
Files changed (154) hide show
  1. package/dist/builders/BaseBuilder.d.ts +15 -4
  2. package/dist/builders/BaseBuilder.d.ts.map +1 -1
  3. package/dist/builders/BaseBuilder.js +50 -0
  4. package/dist/builders/BaseBuilder.js.map +1 -1
  5. package/dist/builders/DtsBuilder.d.ts.map +1 -1
  6. package/dist/builders/DtsBuilder.js +2 -39
  7. package/dist/builders/DtsBuilder.js.map +1 -1
  8. package/dist/builders/LibraryBuilder.d.ts.map +1 -1
  9. package/dist/builders/LibraryBuilder.js +2 -39
  10. package/dist/builders/LibraryBuilder.js.map +1 -1
  11. package/dist/builders/types.d.ts +2 -2
  12. package/dist/builders/types.d.ts.map +1 -1
  13. package/dist/capacitor/capacitor.d.ts.map +1 -1
  14. package/dist/capacitor/capacitor.js +2 -1
  15. package/dist/capacitor/capacitor.js.map +1 -1
  16. package/dist/commands/add-client.d.ts.map +1 -1
  17. package/dist/commands/add-client.js +1 -9
  18. package/dist/commands/add-client.js.map +1 -1
  19. package/dist/commands/add-server.d.ts.map +1 -1
  20. package/dist/commands/add-server.js +1 -9
  21. package/dist/commands/add-server.js.map +1 -1
  22. package/dist/commands/build.d.ts +1 -2
  23. package/dist/commands/build.d.ts.map +1 -1
  24. package/dist/commands/build.js +12 -311
  25. package/dist/commands/build.js.map +1 -1
  26. package/dist/commands/dev.d.ts +1 -1
  27. package/dist/commands/dev.d.ts.map +1 -1
  28. package/dist/commands/dev.js +11 -432
  29. package/dist/commands/dev.js.map +1 -1
  30. package/dist/commands/device.d.ts.map +1 -1
  31. package/dist/commands/device.js +17 -32
  32. package/dist/commands/device.js.map +1 -1
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +1 -9
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/lint.d.ts +1 -1
  37. package/dist/commands/lint.d.ts.map +1 -1
  38. package/dist/commands/lint.js +71 -118
  39. package/dist/commands/lint.js.map +2 -2
  40. package/dist/commands/publish.d.ts.map +1 -1
  41. package/dist/commands/publish.js +47 -69
  42. package/dist/commands/publish.js.map +1 -1
  43. package/dist/commands/typecheck.d.ts +1 -1
  44. package/dist/commands/typecheck.d.ts.map +1 -1
  45. package/dist/commands/typecheck.js +11 -24
  46. package/dist/commands/typecheck.js.map +1 -1
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +4 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/infra/ResultCollector.d.ts +1 -1
  52. package/dist/infra/ResultCollector.d.ts.map +1 -1
  53. package/dist/infra/ResultCollector.js +1 -1
  54. package/dist/infra/ResultCollector.js.map +1 -1
  55. package/dist/orchestrators/BuildOrchestrator.d.ts +53 -0
  56. package/dist/orchestrators/BuildOrchestrator.d.ts.map +1 -0
  57. package/dist/orchestrators/BuildOrchestrator.js +338 -0
  58. package/dist/orchestrators/BuildOrchestrator.js.map +6 -0
  59. package/dist/orchestrators/DevOrchestrator.d.ts +64 -0
  60. package/dist/orchestrators/DevOrchestrator.d.ts.map +1 -0
  61. package/dist/orchestrators/DevOrchestrator.js +524 -0
  62. package/dist/orchestrators/DevOrchestrator.js.map +6 -0
  63. package/dist/orchestrators/WatchOrchestrator.d.ts +1 -1
  64. package/dist/orchestrators/WatchOrchestrator.d.ts.map +1 -1
  65. package/dist/orchestrators/WatchOrchestrator.js +30 -21
  66. package/dist/orchestrators/WatchOrchestrator.js.map +1 -1
  67. package/dist/orchestrators/index.d.ts +2 -0
  68. package/dist/orchestrators/index.d.ts.map +1 -1
  69. package/dist/orchestrators/index.js +4 -0
  70. package/dist/orchestrators/index.js.map +1 -1
  71. package/dist/sd-cli-entry.js +14 -14
  72. package/dist/sd-cli-entry.js.map +1 -1
  73. package/dist/sd-cli.js +6 -4
  74. package/dist/sd-cli.js.map +1 -1
  75. package/dist/utils/output-utils.d.ts +0 -1
  76. package/dist/utils/output-utils.d.ts.map +1 -1
  77. package/dist/utils/output-utils.js +1 -1
  78. package/dist/utils/output-utils.js.map +1 -1
  79. package/dist/utils/package-utils.d.ts +5 -1
  80. package/dist/utils/package-utils.d.ts.map +1 -1
  81. package/dist/utils/package-utils.js +12 -0
  82. package/dist/utils/package-utils.js.map +1 -1
  83. package/dist/utils/rebuild-manager.d.ts +15 -0
  84. package/dist/utils/rebuild-manager.d.ts.map +1 -0
  85. package/dist/utils/rebuild-manager.js +50 -0
  86. package/dist/utils/rebuild-manager.js.map +6 -0
  87. package/dist/utils/replace-deps.d.ts.map +1 -1
  88. package/dist/utils/replace-deps.js +7 -14
  89. package/dist/utils/replace-deps.js.map +1 -1
  90. package/dist/utils/vite-config.d.ts.map +1 -1
  91. package/dist/utils/vite-config.js +43 -5
  92. package/dist/utils/vite-config.js.map +1 -1
  93. package/dist/utils/worker-events.d.ts +5 -4
  94. package/dist/utils/worker-events.d.ts.map +1 -1
  95. package/dist/utils/worker-events.js +4 -0
  96. package/dist/utils/worker-events.js.map +1 -1
  97. package/dist/utils/worker-utils.d.ts +13 -0
  98. package/dist/utils/worker-utils.d.ts.map +1 -0
  99. package/dist/utils/worker-utils.js +15 -0
  100. package/dist/utils/worker-utils.js.map +6 -0
  101. package/dist/workers/client.worker.d.ts.map +1 -1
  102. package/dist/workers/client.worker.js +2 -14
  103. package/dist/workers/client.worker.js.map +1 -1
  104. package/dist/workers/library.worker.d.ts.map +1 -1
  105. package/dist/workers/library.worker.js +2 -14
  106. package/dist/workers/library.worker.js.map +1 -1
  107. package/dist/workers/server-runtime.worker.d.ts.map +1 -1
  108. package/dist/workers/server-runtime.worker.js +11 -11
  109. package/dist/workers/server-runtime.worker.js.map +1 -1
  110. package/dist/workers/server.worker.d.ts.map +1 -1
  111. package/dist/workers/server.worker.js +2 -14
  112. package/dist/workers/server.worker.js.map +1 -1
  113. package/package.json +4 -5
  114. package/src/builders/BaseBuilder.ts +71 -4
  115. package/src/builders/DtsBuilder.ts +2 -49
  116. package/src/builders/LibraryBuilder.ts +2 -51
  117. package/src/builders/types.ts +2 -2
  118. package/src/capacitor/capacitor.ts +2 -1
  119. package/src/commands/add-client.ts +1 -14
  120. package/src/commands/add-server.ts +1 -13
  121. package/src/commands/build.ts +13 -443
  122. package/src/commands/dev.ts +12 -582
  123. package/src/commands/device.ts +17 -34
  124. package/src/commands/init.ts +1 -13
  125. package/src/commands/lint.ts +85 -146
  126. package/src/commands/publish.ts +58 -76
  127. package/src/commands/typecheck.ts +13 -46
  128. package/src/index.ts +1 -0
  129. package/src/infra/ResultCollector.ts +2 -2
  130. package/src/orchestrators/BuildOrchestrator.ts +499 -0
  131. package/src/orchestrators/DevOrchestrator.ts +703 -0
  132. package/src/orchestrators/WatchOrchestrator.ts +42 -25
  133. package/src/orchestrators/index.ts +2 -0
  134. package/src/sd-cli-entry.ts +14 -14
  135. package/src/sd-cli.ts +6 -4
  136. package/src/utils/output-utils.ts +1 -2
  137. package/src/utils/package-utils.ts +16 -1
  138. package/src/utils/rebuild-manager.ts +65 -0
  139. package/src/utils/replace-deps.ts +26 -25
  140. package/src/utils/vite-config.ts +84 -6
  141. package/src/utils/worker-events.ts +13 -5
  142. package/src/utils/worker-utils.ts +26 -0
  143. package/src/workers/client.worker.ts +3 -19
  144. package/src/workers/library.worker.ts +2 -19
  145. package/src/workers/server-runtime.worker.ts +16 -17
  146. package/src/workers/server.worker.ts +2 -19
  147. package/templates/add-client/__CLIENT__/package.json.hbs +1 -1
  148. package/templates/add-server/__SERVER__/package.json.hbs +2 -2
  149. package/templates/init/package.json.hbs +3 -3
  150. package/dist/utils/listr-manager.d.ts +0 -37
  151. package/dist/utils/listr-manager.d.ts.map +0 -1
  152. package/dist/utils/listr-manager.js +0 -59
  153. package/dist/utils/listr-manager.js.map +0 -6
  154. package/src/utils/listr-manager.ts +0 -89
@@ -1,30 +1,7 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import { Listr } from "listr2";
4
- import { Worker, type WorkerProxy } from "@simplysm/core-node";
5
- import type { SdConfig, SdClientPackageConfig, SdServerPackageConfig } from "../sd-config.types";
6
- import { consola } from "consola";
7
- import { loadSdConfig } from "../utils/sd-config";
8
- import { getVersion } from "../utils/build-env";
9
- import { setupReplaceDeps, watchReplaceDeps, type WatchReplaceDepResult } from "../utils/replace-deps";
10
- import type * as ClientWorkerModule from "../workers/client.worker";
11
- import type * as ServerWorkerModule from "../workers/server.worker";
12
- import type * as ServerRuntimeWorkerModule from "../workers/server-runtime.worker";
13
- import { Capacitor } from "../capacitor/capacitor";
14
- import { filterPackagesByTargets, getWatchScopes, type PackageResult } from "../utils/package-utils";
15
- import { printErrors, printServers } from "../utils/output-utils";
16
- import { RebuildListrManager } from "../utils/listr-manager";
17
- import {
18
- registerWorkerEventHandlers,
19
- type ServerReadyEventData,
20
- type ServerBuildEventData,
21
- type ErrorEventData,
22
- } from "../utils/worker-events";
23
-
24
- //#region Types
1
+ import { DevOrchestrator, type DevOrchestratorOptions } from "../orchestrators/DevOrchestrator";
25
2
 
26
3
  /**
27
- * Dev 명령 옵션
4
+ * Dev 명령 옵션 (하위 호환성)
28
5
  */
29
6
  export interface DevOptions {
30
7
  /** dev할 패키지 필터 (빈 배열이면 모든 패키지) */
@@ -32,21 +9,6 @@ export interface DevOptions {
32
9
  options: string[];
33
10
  }
34
11
 
35
- /**
36
- * Client Worker 정보 (Vite dev server용)
37
- */
38
- interface ClientWorkerInfo {
39
- name: string;
40
- config: SdClientPackageConfig;
41
- worker: WorkerProxy<typeof ClientWorkerModule>;
42
- isInitialBuild: boolean;
43
- buildResolver: (() => void) | undefined;
44
- }
45
-
46
- //#endregion
47
-
48
- //#region Main
49
-
50
12
  /**
51
13
  * Client 및 Server 패키지를 개발 모드로 실행한다.
52
14
  *
@@ -61,550 +23,18 @@ interface ClientWorkerInfo {
61
23
  * @returns 종료 시그널 수신 시 resolve
62
24
  */
63
25
  export async function runDev(options: DevOptions): Promise<void> {
64
- const { targets } = options;
65
- const cwd = process.cwd();
66
- const logger = consola.withTag("sd:cli:dev");
67
-
68
- logger.debug("dev 시작", { targets });
69
-
70
- // sd.config.ts 로드 (dev는 패키지 빌드 정보가 필요하므로 필수)
71
- let sdConfig: SdConfig;
72
- try {
73
- sdConfig = await loadSdConfig({ cwd, dev: true, opt: options.options });
74
- logger.debug("sd.config.ts 로드 완료");
75
- } catch (err) {
76
- consola.error(`sd.config.ts 로드 실패: ${err instanceof Error ? err.message : err}`);
77
- process.exitCode = 1;
78
- return;
79
- }
80
-
81
- // replaceDeps 설정이 있으면 symlink 교체
82
- let replaceDepWatcher: WatchReplaceDepResult | undefined;
83
- if (sdConfig.replaceDeps != null) {
84
- await setupReplaceDeps(cwd, sdConfig.replaceDeps);
85
- replaceDepWatcher = await watchReplaceDeps(cwd, sdConfig.replaceDeps);
86
- }
87
-
88
- // VER, DEV 환경변수 준비
89
- const version = await getVersion(cwd);
90
- const baseEnv = { VER: version, DEV: "true" };
91
-
92
- // watchScopes 생성 (루트 package.json에서 scope 추출)
93
- const rootPkgJsonPath = path.join(cwd, "package.json");
94
- const rootPkgName = JSON.parse(fs.readFileSync(rootPkgJsonPath, "utf-8")).name as string;
95
- const watchScopes = getWatchScopes(rootPkgName);
96
-
97
- // targets 필터링
98
- const allPackages = filterPackagesByTargets(sdConfig.packages, targets);
99
-
100
- // client/server 패키지만 필터링
101
- const serverPackages: Array<{ name: string; config: SdServerPackageConfig }> = [];
102
- const clientPackages: Array<{ name: string; config: SdClientPackageConfig }> = [];
103
-
104
- for (const [name, config] of Object.entries(allPackages)) {
105
- if (config.target === "server") {
106
- serverPackages.push({ name, config });
107
- } else if (config.target === "client") {
108
- clientPackages.push({ name, config });
109
- }
110
- }
111
-
112
- if (serverPackages.length === 0 && clientPackages.length === 0) {
113
- process.stdout.write("⚠ dev할 client/server 패키지가 없습니다.\n");
114
- return;
115
- }
116
-
117
- // 서버와 연결된 클라이언트 찾기 (서버가 dev 대상인 경우만)
118
- const serverNames = new Set(serverPackages.map(({ name }) => name));
119
- const serverClientsMap = new Map<string, string[]>();
120
- for (const { name, config } of clientPackages) {
121
- if (typeof config.server === "string" && serverNames.has(config.server)) {
122
- const clients = serverClientsMap.get(config.server) ?? [];
123
- clients.push(name);
124
- serverClientsMap.set(config.server, clients);
125
- }
126
- }
127
-
128
- // Worker 경로
129
- const clientWorkerPath = import.meta.resolve("../workers/client.worker");
130
- const serverWorkerPath = import.meta.resolve("../workers/server.worker");
131
- const serverRuntimeWorkerPath = import.meta.resolve("../workers/server-runtime.worker");
132
-
133
- // 클라이언트가 단독 실행인 경우:
134
- // - server가 숫자인 경우
135
- // - server가 문자열이지만 해당 서버가 dev 대상이 아닌 경우
136
- const standaloneClientWorkers: ClientWorkerInfo[] = clientPackages
137
- .filter(
138
- ({ config }) =>
139
- typeof config.server === "number" || (typeof config.server === "string" && !serverNames.has(config.server)),
140
- )
141
- .map(({ name, config }) => ({
142
- name,
143
- config,
144
- worker: Worker.create<typeof ClientWorkerModule>(clientWorkerPath),
145
- isInitialBuild: true,
146
- buildResolver: undefined,
147
- }));
148
-
149
- // 서버에 연결된 클라이언트의 Vite Worker (서버가 dev 대상인 경우만)
150
- const viteClientWorkers: ClientWorkerInfo[] = clientPackages
151
- .filter(({ config }) => typeof config.server === "string" && serverNames.has(config.server))
152
- .map(({ name, config }) => ({
153
- name,
154
- config,
155
- worker: Worker.create<typeof ClientWorkerModule>(clientWorkerPath),
156
- isInitialBuild: true,
157
- buildResolver: undefined,
158
- }));
159
-
160
- // 결과 상태 관리
161
- const results = new Map<string, PackageResult>();
162
-
163
- // RebuildListrManager 생성
164
- const rebuildManager = new RebuildListrManager(logger);
165
-
166
- // 배치 완료 시 에러와 서버 URL 출력
167
- rebuildManager.on("batchComplete", () => {
168
- printErrors(results);
169
- printServers(results, serverClientsMap);
170
- });
171
-
172
- // 종료 Promise 생성
173
- let resolveTerminate!: () => void;
174
- const terminatePromise = new Promise<void>((resolve) => {
175
- resolveTerminate = resolve;
176
- });
177
-
178
- // 종료 시그널 핸들러 등록
179
- const signalHandler = () => {
180
- process.off("SIGINT", signalHandler);
181
- process.off("SIGTERM", signalHandler);
182
- resolveTerminate();
26
+ const orchestratorOptions: DevOrchestratorOptions = {
27
+ targets: options.targets,
28
+ options: options.options,
183
29
  };
184
- process.on("SIGINT", signalHandler);
185
- process.on("SIGTERM", signalHandler);
186
-
187
- // Standalone client 빌드 Promise 미리 생성
188
- const standaloneClientBuildPromises = new Map<string, Promise<void>>();
189
- for (const workerInfo of standaloneClientWorkers) {
190
- standaloneClientBuildPromises.set(
191
- workerInfo.name,
192
- new Promise<void>((resolve) => {
193
- workerInfo.buildResolver = resolve;
194
- }),
195
- );
196
- }
197
-
198
- // Vite client 빌드 Promise 미리 생성 (서버 연결 클라이언트)
199
- const viteClientBuildPromises = new Map<string, Promise<void>>();
200
- const viteClientReadyPromises = new Map<string, { promise: Promise<void>; resolver: () => void }>();
201
- for (const workerInfo of viteClientWorkers) {
202
- viteClientBuildPromises.set(
203
- workerInfo.name,
204
- new Promise<void>((resolve) => {
205
- workerInfo.buildResolver = resolve;
206
- }),
207
- );
208
- // Vite 서버 준비 완료 Promise (서버가 클라이언트 포트를 알 때까지 대기)
209
- let readyResolver!: () => void;
210
- const readyPromise = new Promise<void>((resolve) => {
211
- readyResolver = resolve;
212
- });
213
- viteClientReadyPromises.set(workerInfo.name, { promise: readyPromise, resolver: readyResolver });
214
- }
215
-
216
- // Server Build Worker 및 Promise 생성
217
- const serverBuildWorkers = new Map<
218
- string,
219
- {
220
- worker: WorkerProxy<typeof ServerWorkerModule>;
221
- buildPromise: Promise<void>;
222
- buildResolver: () => void;
223
- mainJsPath?: string;
224
- }
225
- >();
226
- for (const { name } of serverPackages) {
227
- let resolver!: () => void;
228
- const promise = new Promise<void>((resolve) => {
229
- resolver = resolve;
230
- });
231
- serverBuildWorkers.set(name, {
232
- worker: Worker.create<typeof ServerWorkerModule>(serverWorkerPath),
233
- buildPromise: promise,
234
- buildResolver: resolver,
235
- });
236
- }
237
-
238
- // clientPorts 캐시 (서버 재시작 시 재사용)
239
- const clientPorts: Record<string, number> = {};
240
-
241
- // Server Runtime Worker (서버당 하나, 재시작 시 교체)
242
- const serverRuntimeWorkers = new Map<string, WorkerProxy<typeof ServerRuntimeWorkerModule>>();
243
30
 
244
- // Server Runtime Promise (초기 서버 시작 완료 대기용)
245
- const serverRuntimePromises = new Map<string, { promise: Promise<void>; resolver: () => void }>();
246
- for (const { name } of serverPackages) {
247
- let resolver!: () => void;
248
- const promise = new Promise<void>((resolve) => {
249
- resolver = resolve;
250
- });
251
- serverRuntimePromises.set(name, { promise, resolver });
252
- }
253
-
254
- // Standalone client 이벤트 핸들러 등록 및 completeTask 함수 저장
255
- const clientCompleteTasks = new Map<string, (result: PackageResult) => void>();
256
- for (const workerInfo of standaloneClientWorkers) {
257
- const completeTask = registerWorkerEventHandlers(
258
- workerInfo,
259
- {
260
- resultKey: `${workerInfo.name}:build`,
261
- listrTitle: `${workerInfo.name} (client)`,
262
- resultType: "build",
263
- },
264
- results,
265
- rebuildManager,
266
- );
267
- clientCompleteTasks.set(workerInfo.name, completeTask);
268
-
269
- // serverReady (Vite dev server)
270
- workerInfo.worker.on("serverReady", (data) => {
271
- const event = data as ServerReadyEventData;
272
- completeTask({
273
- name: workerInfo.name,
274
- target: workerInfo.config.target,
275
- type: "server",
276
- status: "server",
277
- port: event.port,
278
- });
279
- });
280
- }
281
-
282
- // Vite client (서버 연결) 이벤트 핸들러 등록
283
- for (const workerInfo of viteClientWorkers) {
284
- const completeTask = registerWorkerEventHandlers(
285
- workerInfo,
286
- {
287
- resultKey: `${workerInfo.name}:build`,
288
- listrTitle: `${workerInfo.name} (client)`,
289
- resultType: "build",
290
- },
291
- results,
292
- rebuildManager,
293
- );
294
- clientCompleteTasks.set(workerInfo.name, completeTask);
295
-
296
- // serverReady - Vite 포트를 clientPorts에 저장 (URL은 서버를 통해 출력)
297
- workerInfo.worker.on("serverReady", (data) => {
298
- const event = data as ServerReadyEventData;
299
- clientPorts[workerInfo.name] = event.port;
300
- // Vite 서버 준비 완료 알림 (서버가 프록시 설정을 위해 대기 중)
301
- viteClientReadyPromises.get(workerInfo.name)?.resolver();
302
- // listr 완료를 위해 completeTask 호출 (Vite는 build 이벤트를 발생시키지 않음)
303
- completeTask({
304
- name: workerInfo.name,
305
- target: workerInfo.config.target,
306
- type: "build",
307
- status: "success",
308
- });
309
- });
310
- }
311
-
312
- // Server Build Worker 이벤트 핸들러 등록
313
- for (const { name } of serverPackages) {
314
- const serverBuild = serverBuildWorkers.get(name)!;
315
- let isFirstBuild = true;
316
-
317
- serverBuild.worker.on("buildStart", () => {
318
- if (!isFirstBuild) {
319
- // 리빌드 시 RebuildListrManager에 등록
320
- const resolver = rebuildManager.registerBuild(`${name}:server`, `${name} (server)`);
321
- serverBuildWorkers.set(name, {
322
- ...serverBuild,
323
- buildResolver: resolver,
324
- });
325
- }
326
- });
327
-
328
- serverBuild.worker.on("build", async (data) => {
329
- const event = data as ServerBuildEventData;
330
-
331
- if (event.success) {
332
- // mainJsPath 저장
333
- const updatedBuild = serverBuildWorkers.get(name)!;
334
- updatedBuild.mainJsPath = event.mainJsPath;
335
-
336
- // 기존 Server Runtime Worker 종료
337
- const existingRuntime = serverRuntimeWorkers.get(name);
338
- if (existingRuntime != null) {
339
- // 서버 재시작 중 메시지 출력
340
- consola.info(`[${name}] 서버 재시작 중...`);
341
- await existingRuntime.terminate();
342
- }
343
-
344
- // 새 Server Runtime Worker 생성 및 시작
345
- const runtimeWorker = Worker.create<typeof ServerRuntimeWorkerModule>(serverRuntimeWorkerPath);
346
- serverRuntimeWorkers.set(name, runtimeWorker);
347
-
348
- // 이 서버에 연결된 클라이언트들의 Vite 서버가 준비될 때까지 대기
349
- const connectedClients = serverClientsMap.get(name) ?? [];
350
- const clientReadyPromises = connectedClients
351
- .map((clientName) => viteClientReadyPromises.get(clientName)?.promise)
352
- .filter((p): p is Promise<void> => p != null);
353
- if (clientReadyPromises.length > 0) {
354
- await Promise.all(clientReadyPromises);
355
- }
356
-
357
- // 이 서버에 연결된 클라이언트 포트 수집
358
- const serverClientPorts: Record<string, number> = {};
359
- for (const clientName of connectedClients) {
360
- if (clientName in clientPorts) {
361
- serverClientPorts[clientName] = clientPorts[clientName];
362
- }
363
- }
364
-
365
- // Server Runtime 이벤트 핸들러
366
- runtimeWorker.on("serverReady", (readyData) => {
367
- const readyEvent = readyData as ServerReadyEventData;
368
- results.set(`${name}:server`, {
369
- name,
370
- target: "server",
371
- type: "server",
372
- status: "server",
373
- port: readyEvent.port,
374
- });
375
-
376
- if (isFirstBuild) {
377
- isFirstBuild = false;
378
- serverRuntimePromises.get(name)?.resolver();
379
- }
380
- updatedBuild.buildResolver();
381
- });
382
-
383
- runtimeWorker.on("error", (errorData) => {
384
- const errorEvent = errorData as ErrorEventData;
385
- results.set(`${name}:server`, {
386
- name,
387
- target: "server",
388
- type: "server",
389
- status: "error",
390
- message: errorEvent.message,
391
- });
392
-
393
- if (isFirstBuild) {
394
- isFirstBuild = false;
395
- serverRuntimePromises.get(name)?.resolver();
396
- }
397
- updatedBuild.buildResolver();
398
- });
399
-
400
- // Server Runtime 시작
401
- void runtimeWorker.start({
402
- mainJsPath: event.mainJsPath,
403
- clientPorts: serverClientPorts,
404
- });
405
- } else {
406
- results.set(`${name}:build`, {
407
- name,
408
- target: "server",
409
- type: "build",
410
- status: "error",
411
- message: event.errors?.join("\n"),
412
- });
31
+ const orchestrator = new DevOrchestrator(orchestratorOptions);
413
32
 
414
- if (isFirstBuild) {
415
- isFirstBuild = false;
416
- serverRuntimePromises.get(name)?.resolver();
417
- }
418
- serverBuild.buildResolver();
419
- }
420
- });
421
-
422
- serverBuild.worker.on("error", (data) => {
423
- const event = data as ErrorEventData;
424
- results.set(`${name}:build`, {
425
- name,
426
- target: "server",
427
- type: "build",
428
- status: "error",
429
- message: event.message,
430
- });
431
- if (isFirstBuild) {
432
- isFirstBuild = false;
433
- serverRuntimePromises.get(name)?.resolver();
434
- }
435
- serverBuild.buildResolver();
436
- });
437
- }
438
-
439
- // 초기 빌드 listr (standalone client + vite client + server 빌드)
440
- const initialListr = new Listr(
441
- [
442
- // Standalone client 태스크
443
- ...standaloneClientWorkers.map((workerInfo) => ({
444
- title: `${workerInfo.name} (client)`,
445
- task: () => standaloneClientBuildPromises.get(workerInfo.name) ?? Promise.resolve(),
446
- })),
447
- // Vite client 태스크 (서버 연결)
448
- ...viteClientWorkers.map((workerInfo) => ({
449
- title: `${workerInfo.name} (client)`,
450
- task: () => viteClientBuildPromises.get(workerInfo.name) ?? Promise.resolve(),
451
- })),
452
- // Server 빌드 태스크 (빌드 + 런타임 시작)
453
- ...serverPackages.map(({ name }) => ({
454
- title: `${name} (server)`,
455
- task: () => serverRuntimePromises.get(name)?.promise ?? Promise.resolve(),
456
- })),
457
- ],
458
- { concurrent: true },
459
- );
460
-
461
- // Standalone client 워커 시작
462
- for (const workerInfo of standaloneClientWorkers) {
463
- const pkgDir = path.join(cwd, "packages", workerInfo.name);
464
- const completeTask = clientCompleteTasks.get(workerInfo.name)!;
465
- const clientConfig: SdClientPackageConfig = {
466
- ...workerInfo.config,
467
- env: { ...baseEnv, ...workerInfo.config.env },
468
- };
469
- workerInfo.worker
470
- .startWatch({
471
- name: workerInfo.name,
472
- config: clientConfig,
473
- cwd,
474
- pkgDir,
475
- watchScopes,
476
- })
477
- .catch((err: unknown) => {
478
- completeTask({
479
- name: workerInfo.name,
480
- target: workerInfo.config.target,
481
- type: "build",
482
- status: "error",
483
- message: err instanceof Error ? err.message : String(err),
484
- });
485
- });
486
- }
487
-
488
- // Vite client 워커 시작 (서버 연결) - Vite 자동 포트 사용
489
- for (const workerInfo of viteClientWorkers) {
490
- const pkgDir = path.join(cwd, "packages", workerInfo.name);
491
- const completeTask = clientCompleteTasks.get(workerInfo.name)!;
492
- // Vite가 자동으로 포트를 할당하도록 설정
493
- const viteConfig: SdClientPackageConfig = {
494
- ...workerInfo.config,
495
- server: 0, // Vite가 자동으로 포트 할당
496
- env: { ...baseEnv, ...workerInfo.config.env },
497
- };
498
- workerInfo.worker
499
- .startWatch({
500
- name: workerInfo.name,
501
- config: viteConfig,
502
- cwd,
503
- pkgDir,
504
- watchScopes,
505
- })
506
- .catch((err: unknown) => {
507
- completeTask({
508
- name: workerInfo.name,
509
- target: workerInfo.config.target,
510
- type: "build",
511
- status: "error",
512
- message: err instanceof Error ? err.message : String(err),
513
- });
514
- });
515
- }
516
-
517
- // Server Build 워커 시작
518
- for (const { name, config } of serverPackages) {
519
- const pkgDir = path.join(cwd, "packages", name);
520
- const serverBuild = serverBuildWorkers.get(name)!;
521
- serverBuild.worker
522
- .startWatch({
523
- name,
524
- cwd,
525
- pkgDir,
526
- env: { ...baseEnv, ...config.env },
527
- configs: config.configs,
528
- externals: config.externals,
529
- })
530
- .catch((err: unknown) => {
531
- results.set(`${name}:build`, {
532
- name,
533
- target: "server",
534
- type: "build",
535
- status: "error",
536
- message: err instanceof Error ? err.message : String(err),
537
- });
538
- serverRuntimePromises.get(name)?.resolver();
539
- serverBuild.buildResolver();
540
- });
541
- }
542
-
543
- // listr 실행 (초기 빌드 완료까지 대기)
544
- await initialListr.run();
545
-
546
- // Capacitor 초기화 (client 타겟 중 capacitor 설정이 있는 패키지)
547
- const capacitorPackages: Array<[string, SdClientPackageConfig]> = [];
548
- for (const { name, config } of clientPackages) {
549
- if (config.capacitor != null) {
550
- capacitorPackages.push([name, config]);
551
- }
552
- }
553
-
554
- if (capacitorPackages.length > 0) {
555
- const capacitorListr = new Listr(
556
- capacitorPackages.map(([name, config]) => ({
557
- title: `${name} (capacitor)`,
558
- task: async () => {
559
- const pkgDir = path.join(cwd, "packages", name);
560
- try {
561
- const cap = await Capacitor.create(pkgDir, config.capacitor!);
562
- await cap.initialize();
563
- results.set(`${name}:capacitor`, {
564
- name,
565
- target: "client",
566
- type: "capacitor",
567
- status: "success",
568
- });
569
- } catch (err) {
570
- results.set(`${name}:capacitor`, {
571
- name,
572
- target: "client",
573
- type: "capacitor",
574
- status: "error",
575
- message: err instanceof Error ? err.message : String(err),
576
- });
577
- throw err;
578
- }
579
- },
580
- })),
581
- { concurrent: false, exitOnError: false },
582
- );
583
-
584
- try {
585
- await capacitorListr.run();
586
- } catch {
587
- // 에러는 results에 이미 기록됨
588
- }
33
+ try {
34
+ await orchestrator.initialize();
35
+ await orchestrator.start();
36
+ await orchestrator.awaitTermination();
37
+ } finally {
38
+ await orchestrator.shutdown();
589
39
  }
590
-
591
- // 초기 빌드 결과 출력
592
- printErrors(results);
593
- printServers(results, serverClientsMap);
594
-
595
- // 종료 시그널까지 대기
596
- await terminatePromise;
597
-
598
- // Worker 종료 (모든 워커)
599
- process.stdout.write("⏳ 종료 중...\n");
600
- await Promise.all([
601
- ...standaloneClientWorkers.map(({ worker }) => worker.terminate()),
602
- ...viteClientWorkers.map(({ worker }) => worker.terminate()),
603
- ...[...serverBuildWorkers.values()].map(({ worker }) => worker.terminate()),
604
- ...[...serverRuntimeWorkers.values()].map((worker) => worker.terminate()),
605
- ]);
606
- replaceDepWatcher?.dispose();
607
- process.stdout.write("✔ 완료\n");
608
40
  }
609
-
610
- //#endregion