@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,7 +1,6 @@
1
1
  import type * as LibraryWorkerModule from "../workers/library.worker";
2
2
  import type { BuildResult } from "../infra/ResultCollector";
3
3
  import type { SdBuildPackageConfig } from "../sd-config.types";
4
- import type { BuildEventData, ErrorEventData } from "../utils/worker-events";
5
4
  import { BaseBuilder } from "./BaseBuilder";
6
5
  import type { PackageInfo } from "./types";
7
6
 
@@ -31,57 +30,9 @@ export class LibraryBuilder extends BaseBuilder {
31
30
 
32
31
  protected registerEventHandlers(): void {
33
32
  for (const pkg of this.packages) {
34
- const worker = this.workerManager.get<typeof LibraryWorkerModule>(`${pkg.name}:build`)!;
35
- const resultKey = `${pkg.name}:build`;
33
+ const workerKey = `${pkg.name}:build`;
36
34
  const listrTitle = `${pkg.name} (${pkg.config.target})`;
37
-
38
- // 초기 빌드 여부 추적
39
- let isInitialBuild = true;
40
-
41
- // 빌드 시작 (리빌드 시)
42
- worker.on("buildStart", () => {
43
- if (!isInitialBuild && this.rebuildManager != null) {
44
- // 리빌드 시 RebuildListrManager에 등록
45
- const resolver = this.rebuildManager.registerBuild(resultKey, listrTitle);
46
- this.buildResolvers.set(resultKey, resolver);
47
- }
48
- });
49
-
50
- // 빌드 완료
51
- worker.on("build", (data) => {
52
- const event = data as BuildEventData;
53
- const result: BuildResult = {
54
- name: pkg.name,
55
- target: pkg.config.target,
56
- type: "build",
57
- status: event.success ? "success" : "error",
58
- message: event.errors?.join("\n"),
59
- };
60
- this.resultCollector.add(result);
61
-
62
- if (isInitialBuild) {
63
- isInitialBuild = false;
64
- }
65
- this.completeBuild(pkg);
66
- });
67
-
68
- // 에러
69
- worker.on("error", (data) => {
70
- const event = data as ErrorEventData;
71
- const result: BuildResult = {
72
- name: pkg.name,
73
- target: pkg.config.target,
74
- type: "build",
75
- status: "error",
76
- message: event.message,
77
- };
78
- this.resultCollector.add(result);
79
-
80
- if (isInitialBuild) {
81
- isInitialBuild = false;
82
- }
83
- this.completeBuild(pkg);
84
- });
35
+ this.registerEventHandlersForWorker(pkg, workerKey, "build", listrTitle);
85
36
  }
86
37
  }
87
38
 
@@ -1,6 +1,6 @@
1
1
  import type { SdPackageConfig } from "../sd-config.types";
2
2
  import type { ResultCollector } from "../infra/ResultCollector";
3
- import type { RebuildListrManager } from "../utils/listr-manager";
3
+ import type { RebuildManager } from "../utils/rebuild-manager";
4
4
 
5
5
  /**
6
6
  * 패키지 정보
@@ -18,7 +18,7 @@ export interface BuilderOptions {
18
18
  cwd: string;
19
19
  packages: PackageInfo[];
20
20
  resultCollector: ResultCollector;
21
- rebuildManager?: RebuildListrManager;
21
+ rebuildManager?: RebuildManager;
22
22
  }
23
23
 
24
24
  /**
@@ -668,7 +668,8 @@ export default config;
668
668
 
669
669
  // versionName, versionCode 설정
670
670
  const version = this._npmConfig.version;
671
- const versionParts = version.split(".");
671
+ const cleanVersion = version.replace(/-.*$/, "");
672
+ const versionParts = cleanVersion.split(".");
672
673
  const versionCode =
673
674
  parseInt(versionParts[0] ?? "0") * 10000 +
674
675
  parseInt(versionParts[1] ?? "0") * 100 +
@@ -5,6 +5,7 @@ import { consola } from "consola";
5
5
  import { renderTemplateDir } from "../utils/template";
6
6
  import { addPackageToSdConfig, addTailwindToEslintConfig } from "../utils/config-editor";
7
7
  import { spawn } from "../utils/spawn";
8
+ import { findPackageRoot } from "../utils/package-utils";
8
9
 
9
10
  //#region Types
10
11
 
@@ -16,20 +17,6 @@ export interface AddClientOptions {}
16
17
  //#endregion
17
18
 
18
19
  //#region Utilities
19
-
20
- /**
21
- * import.meta.dirname에서 상위로 올라가며 package.json을 찾아 패키지 루트를 반환한다.
22
- */
23
- function findPackageRoot(startDir: string): string {
24
- let dir = startDir;
25
- while (!fs.existsSync(path.join(dir, "package.json"))) {
26
- const parent = path.dirname(dir);
27
- if (parent === dir) throw new Error("package.json을 찾을 수 없습니다.");
28
- dir = parent;
29
- }
30
- return dir;
31
- }
32
-
33
20
  //#endregion
34
21
 
35
22
  //#region Main
@@ -5,6 +5,7 @@ import { consola } from "consola";
5
5
  import { renderTemplateDir } from "../utils/template";
6
6
  import { addPackageToSdConfig, setClientServerInSdConfig } from "../utils/config-editor";
7
7
  import { spawn } from "../utils/spawn";
8
+ import { findPackageRoot } from "../utils/package-utils";
8
9
 
9
10
  //#region Types
10
11
 
@@ -17,19 +18,6 @@ export interface AddServerOptions {}
17
18
 
18
19
  //#region Utilities
19
20
 
20
- /**
21
- * import.meta.dirname에서 상위로 올라가며 package.json을 찾아 패키지 루트를 반환한다.
22
- */
23
- function findPackageRoot(startDir: string): string {
24
- let dir = startDir;
25
- while (!fs.existsSync(path.join(dir, "package.json"))) {
26
- const parent = path.dirname(dir);
27
- if (parent === dir) throw new Error("package.json을 찾을 수 없습니다.");
28
- dir = parent;
29
- }
30
- return dir;
31
- }
32
-
33
21
  /**
34
22
  * sd.config.ts를 읽어서 target이 "client"인 패키지명 목록을 반환한다.
35
23
  */
@@ -1,28 +1,7 @@
1
- import path from "path";
2
- import ts from "typescript";
3
- import { Listr, type ListrTask } from "listr2";
4
- import { Worker, type WorkerProxy, fsRm } from "@simplysm/core-node";
5
- import "@simplysm/core-common";
6
- import { consola, LogLevels } from "consola";
7
- import type { SdConfig, SdBuildPackageConfig, SdClientPackageConfig, SdServerPackageConfig } from "../sd-config.types";
8
- import { loadSdConfig } from "../utils/sd-config";
9
- import { getVersion } from "../utils/build-env";
10
- import { setupReplaceDeps } from "../utils/replace-deps";
11
- import type { TypecheckEnv } from "../utils/tsconfig";
12
- import { deserializeDiagnostic } from "../utils/typecheck-serialization";
13
- import { runLint, type LintOptions } from "./lint";
14
- import type * as LibraryWorkerModule from "../workers/library.worker";
15
- import type * as ServerWorkerModule from "../workers/server.worker";
16
- import type * as ClientWorkerModule from "../workers/client.worker";
17
- import type * as DtsWorkerModule from "../workers/dts.worker";
18
- import { Capacitor } from "../capacitor/capacitor";
19
- import { Electron } from "../electron/electron";
20
- import { copySrcFiles } from "../utils/copy-src";
21
-
22
- //#region Types
1
+ import { BuildOrchestrator, type BuildOrchestratorOptions } from "../orchestrators/BuildOrchestrator";
23
2
 
24
3
  /**
25
- * Build 명령 옵션
4
+ * Build 명령 옵션 (하위 호환성)
26
5
  */
27
6
  export interface BuildOptions {
28
7
  /** 빌드할 패키지 필터 (빈 배열이면 모든 패키지) */
@@ -31,82 +10,6 @@ export interface BuildOptions {
31
10
  options: string[];
32
11
  }
33
12
 
34
- /**
35
- * 빌드 결과
36
- */
37
- interface BuildResult {
38
- name: string;
39
- target: string;
40
- type: "js" | "dts" | "vite" | "capacitor" | "electron";
41
- success: boolean;
42
- errors?: string[];
43
- diagnostics?: ts.Diagnostic[];
44
- }
45
-
46
- /**
47
- * 패키지 분류 결과
48
- */
49
- interface ClassifiedPackages {
50
- /** node/browser/neutral 타겟 (JS + dts) */
51
- buildPackages: Array<{ name: string; config: SdBuildPackageConfig }>;
52
- /** client 타겟 (Vite build + typecheck) */
53
- clientPackages: Array<{ name: string; config: SdClientPackageConfig }>;
54
- /** server 타겟 (JS 빌드, dts 제외) */
55
- serverPackages: Array<{ name: string; config: SdServerPackageConfig }>;
56
- }
57
-
58
- //#endregion
59
-
60
- //#region Utilities
61
-
62
- /**
63
- * 패키지를 타겟별로 분류
64
- * - node/browser/neutral: buildPackages (JS + dts)
65
- * - client: clientPackages (Vite build + typecheck)
66
- * - server: serverPackages (JS 빌드, dts 제외)
67
- * - scripts: 제외
68
- */
69
- function classifyPackages(
70
- packages: Record<
71
- string,
72
- SdBuildPackageConfig | SdClientPackageConfig | SdServerPackageConfig | { target: "scripts" } | undefined
73
- >,
74
- targets: string[],
75
- ): ClassifiedPackages {
76
- const buildPackages: ClassifiedPackages["buildPackages"] = [];
77
- const clientPackages: ClassifiedPackages["clientPackages"] = [];
78
- const serverPackages: ClassifiedPackages["serverPackages"] = [];
79
-
80
- for (const [name, config] of Object.entries(packages)) {
81
- if (config == null) continue;
82
- if (config.target === "scripts") continue;
83
-
84
- // targets가 지정되면 해당 패키지만 포함
85
- if (targets.length > 0 && !targets.includes(name)) continue;
86
-
87
- if (config.target === "client") {
88
- clientPackages.push({ name, config });
89
- } else if (config.target === "server") {
90
- serverPackages.push({ name, config });
91
- } else {
92
- buildPackages.push({ name, config });
93
- }
94
- }
95
-
96
- return { buildPackages, clientPackages, serverPackages };
97
- }
98
-
99
- /**
100
- * dist 폴더 삭제
101
- */
102
- async function cleanDistFolders(cwd: string, packageNames: string[]): Promise<void> {
103
- await Promise.all(packageNames.map((name) => fsRm(path.join(cwd, "packages", name, "dist"))));
104
- }
105
-
106
- //#endregion
107
-
108
- //#region Main
109
-
110
13
  /**
111
14
  * 프로덕션 빌드를 실행한다.
112
15
  *
@@ -121,355 +24,22 @@ async function cleanDistFolders(cwd: string, packageNames: string[]): Promise<vo
121
24
  * @returns 완료 시 resolve
122
25
  */
123
26
  export async function runBuild(options: BuildOptions): Promise<void> {
124
- const { targets } = options;
125
- const cwd = process.cwd();
126
- const logger = consola.withTag("sd:cli:build");
127
-
128
- logger.debug("빌드 시작", { targets });
129
-
130
- // sd.config.ts 로드
131
- let sdConfig: SdConfig;
132
- try {
133
- sdConfig = await loadSdConfig({ cwd, dev: false, opt: options.options });
134
- logger.debug("sd.config.ts 로드 완료");
135
- } catch (err) {
136
- consola.error(`sd.config.ts 로드 실패: ${err instanceof Error ? err.message : err}`);
137
- process.exitCode = 1;
138
- return;
139
- }
140
-
141
- // replaceDeps 설정이 있으면 symlink 교체
142
- if (sdConfig.replaceDeps != null) {
143
- await setupReplaceDeps(cwd, sdConfig.replaceDeps);
144
- }
145
-
146
- // VER, DEV 환경변수 준비
147
- const version = await getVersion(cwd);
148
- const baseEnv = { VER: version, DEV: "false" };
149
-
150
- // 패키지 분류
151
- const { buildPackages, clientPackages, serverPackages } = classifyPackages(sdConfig.packages, targets);
152
- const allPackageNames = [
153
- ...buildPackages.map((p) => p.name),
154
- ...clientPackages.map((p) => p.name),
155
- ...serverPackages.map((p) => p.name),
156
- ];
157
-
158
- if (allPackageNames.length === 0) {
159
- process.stdout.write("✔ 빌드할 패키지가 없습니다.\n");
160
- return;
161
- }
162
-
163
- logger.debug("패키지 분류 완료", {
164
- buildPackages: buildPackages.map((p) => p.name),
165
- clientPackages: clientPackages.map((p) => p.name),
166
- serverPackages: serverPackages.map((p) => p.name),
167
- });
168
-
169
- // 결과 수집
170
- const results: BuildResult[] = [];
171
- // 에러 추적 (객체로 래핑하여 콜백 내 수정 추적 가능하게 함)
172
- const state = { hasError: false };
173
-
174
- // Worker 경로
175
- const libraryWorkerPath = import.meta.resolve("../workers/library.worker");
176
- const serverWorkerPath = import.meta.resolve("../workers/server.worker");
177
- const clientWorkerPath = import.meta.resolve("../workers/client.worker");
178
- const dtsWorkerPath = import.meta.resolve("../workers/dts.worker");
179
-
180
- // 파일 캐시 (diagnostics 출력용)
181
- const fileCache = new Map<string, string>();
182
-
183
- // formatHost (diagnostics 출력용)
184
- const formatHost: ts.FormatDiagnosticsHost = {
185
- getCanonicalFileName: (f) => f,
186
- getCurrentDirectory: () => cwd,
187
- getNewLine: () => ts.sys.newLine,
188
- };
189
-
190
- // Lint 옵션 (전체 패키지 대상)
191
- const lintOptions: LintOptions = {
192
- targets: allPackageNames.map((name) => `packages/${name}`),
193
- fix: false,
194
- timing: false,
27
+ const orchestratorOptions: BuildOrchestratorOptions = {
28
+ targets: options.targets,
29
+ options: options.options,
195
30
  };
196
31
 
197
- // Listr 구조: Lint → Clean → Build (순차)
198
- const mainListr = new Listr(
199
- [
200
- {
201
- title: "Lint",
202
- task: async () => {
203
- await runLint(lintOptions);
204
- // lint 에러가 있으면 process.exitCode가 1로 설정됨
205
- if (process.exitCode === 1) {
206
- state.hasError = true;
207
- }
208
- },
209
- },
210
- {
211
- title: "Clean",
212
- task: async () => {
213
- await cleanDistFolders(cwd, allPackageNames);
214
- },
215
- },
216
- {
217
- title: "Build",
218
- task: (_, task) => {
219
- const buildTasks: ListrTask[] = [];
220
-
221
- // buildPackages: JS 빌드 + dts 생성
222
- for (const { name, config } of buildPackages) {
223
- const pkgDir = path.join(cwd, "packages", name);
224
- const env: TypecheckEnv = config.target === "node" ? "node" : "browser";
225
-
226
- buildTasks.push({
227
- title: `${name} (${config.target})`,
228
- task: async () => {
229
- // JS 빌드와 DTS 생성을 병렬 실행
230
- const libraryWorker: WorkerProxy<typeof LibraryWorkerModule> =
231
- Worker.create<typeof LibraryWorkerModule>(libraryWorkerPath);
232
- const dtsWorker: WorkerProxy<typeof DtsWorkerModule> =
233
- Worker.create<typeof DtsWorkerModule>(dtsWorkerPath);
234
-
235
- try {
236
- const [buildResult, dtsResult] = await Promise.all([
237
- // JS 빌드
238
- libraryWorker.build({ name, config, cwd, pkgDir }),
239
- // DTS 생성
240
- dtsWorker.buildDts({ name, cwd, pkgDir, env, emit: true }),
241
- ]);
242
-
243
- // JS 빌드 결과 처리
244
- results.push({
245
- name,
246
- target: config.target,
247
- type: "js",
248
- success: buildResult.success,
249
- errors: buildResult.errors,
250
- });
251
- if (!buildResult.success) state.hasError = true;
252
-
253
- // DTS 결과 처리
254
- const diagnostics = dtsResult.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
255
- results.push({
256
- name,
257
- target: config.target,
258
- type: "dts",
259
- success: dtsResult.success,
260
- errors: dtsResult.errors,
261
- diagnostics,
262
- });
263
- if (!dtsResult.success) state.hasError = true;
264
- } finally {
265
- await Promise.all([libraryWorker.terminate(), dtsWorker.terminate()]);
266
- }
267
-
268
- // copySrc 파일 복사
269
- if (config.copySrc != null && config.copySrc.length > 0) {
270
- await copySrcFiles(pkgDir, config.copySrc);
271
- }
272
- },
273
- });
274
- }
275
-
276
- // clientPackages: Vite 빌드 + typecheck + Capacitor 빌드
277
- for (const { name, config } of clientPackages) {
278
- const pkgDir = path.join(cwd, "packages", name);
279
-
280
- buildTasks.push({
281
- title: `${name} (client)`,
282
- task: async () => {
283
- // Vite 빌드와 타입체크를 병렬 실행
284
- const clientWorker: WorkerProxy<typeof ClientWorkerModule> =
285
- Worker.create<typeof ClientWorkerModule>(clientWorkerPath);
286
- const dtsWorker: WorkerProxy<typeof DtsWorkerModule> =
287
- Worker.create<typeof DtsWorkerModule>(dtsWorkerPath);
288
-
289
- try {
290
- const clientConfig: SdClientPackageConfig = {
291
- ...config,
292
- env: { ...baseEnv, ...config.env },
293
- };
294
- const [clientResult, dtsResult] = await Promise.all([
295
- // Vite production 빌드
296
- clientWorker.build({ name, config: clientConfig, cwd, pkgDir }),
297
- // typecheck (dts 없이)
298
- dtsWorker.buildDts({
299
- name,
300
- cwd,
301
- pkgDir,
302
- env: "browser",
303
- emit: false,
304
- }),
305
- ]);
306
-
307
- // Vite 빌드 결과 처리
308
- results.push({
309
- name,
310
- target: "client",
311
- type: "vite",
312
- success: clientResult.success,
313
- errors: clientResult.errors,
314
- });
315
- if (!clientResult.success) state.hasError = true;
316
-
317
- // 타입체크 결과 처리
318
- const diagnostics = dtsResult.diagnostics.map((d) => deserializeDiagnostic(d, fileCache));
319
- results.push({
320
- name,
321
- target: "client",
322
- type: "dts",
323
- success: dtsResult.success,
324
- errors: dtsResult.errors,
325
- diagnostics,
326
- });
327
- if (!dtsResult.success) state.hasError = true;
328
- } finally {
329
- await Promise.all([clientWorker.terminate(), dtsWorker.terminate()]);
330
- }
331
-
332
- // Capacitor 빌드 (설정이 있는 경우만)
333
- if (config.capacitor != null) {
334
- const outPath = path.join(pkgDir, "dist");
335
- try {
336
- const cap = await Capacitor.create(pkgDir, config.capacitor);
337
- await cap.initialize();
338
- await cap.build(outPath);
339
- results.push({
340
- name,
341
- target: "client",
342
- type: "capacitor",
343
- success: true,
344
- });
345
- } catch (err) {
346
- results.push({
347
- name,
348
- target: "client",
349
- type: "capacitor",
350
- success: false,
351
- errors: [err instanceof Error ? err.message : String(err)],
352
- });
353
- state.hasError = true;
354
- }
355
- }
356
-
357
- // Electron 빌드 (설정이 있는 경우만)
358
- if (config.electron != null) {
359
- const outPath = path.join(pkgDir, "dist");
360
- try {
361
- const electron = await Electron.create(pkgDir, config.electron);
362
- await electron.initialize();
363
- await electron.build(outPath);
364
- results.push({
365
- name,
366
- target: "client",
367
- type: "electron",
368
- success: true,
369
- });
370
- } catch (err) {
371
- results.push({
372
- name,
373
- target: "client",
374
- type: "electron",
375
- success: false,
376
- errors: [err instanceof Error ? err.message : String(err)],
377
- });
378
- state.hasError = true;
379
- }
380
- }
381
- },
382
- });
383
- }
384
-
385
- // serverPackages: JS 빌드만 (dts 생성 제외)
386
- for (const { name, config } of serverPackages) {
387
- const pkgDir = path.join(cwd, "packages", name);
388
-
389
- buildTasks.push({
390
- title: `${name} (server)`,
391
- task: async () => {
392
- const serverWorker: WorkerProxy<typeof ServerWorkerModule> =
393
- Worker.create<typeof ServerWorkerModule>(serverWorkerPath);
394
-
395
- try {
396
- const buildResult = await serverWorker.build({
397
- name,
398
- cwd,
399
- pkgDir,
400
- env: { ...baseEnv, ...config.env },
401
- configs: config.configs,
402
- externals: config.externals,
403
- pm2: config.pm2,
404
- packageManager: config.packageManager,
405
- });
406
-
407
- results.push({
408
- name,
409
- target: "server",
410
- type: "js",
411
- success: buildResult.success,
412
- errors: buildResult.errors,
413
- });
414
- if (!buildResult.success) state.hasError = true;
415
- } finally {
416
- await serverWorker.terminate();
417
- }
418
- },
419
- });
420
- }
421
-
422
- return task.newListr(buildTasks, { concurrent: true, exitOnError: false });
423
- },
424
- },
425
- ],
426
- {
427
- concurrent: false,
428
- exitOnError: false,
429
- renderer: consola.level >= LogLevels.debug ? "verbose" : "default",
430
- },
431
- );
32
+ const orchestrator = new BuildOrchestrator(orchestratorOptions);
432
33
 
433
34
  try {
434
- await mainListr.run();
435
- } catch {
436
- // Listr 내부 에러는 results에 이미 수집됨
437
- }
438
-
439
- // 결과 출력
440
- const allDiagnostics: ts.Diagnostic[] = [];
441
- for (const result of results) {
442
- if (!result.success) {
443
- const typeLabel = result.type === "dts" ? "dts" : result.target;
444
- const errorLines: string[] = [`${result.name} (${typeLabel})`];
445
- if (result.errors != null) {
446
- for (const error of result.errors) {
447
- for (const line of error.split("\n")) {
448
- errorLines.push(` → ${line}`);
449
- }
450
- }
451
- }
452
- consola.error(errorLines.join("\n"));
453
- }
454
- if (result.diagnostics != null) {
455
- allDiagnostics.push(...result.diagnostics);
35
+ await orchestrator.initialize();
36
+ const hasError = await orchestrator.start();
37
+ if (hasError) {
38
+ process.exitCode = 1;
456
39
  }
457
- }
458
-
459
- // diagnostics 출력 (중복 제거)
460
- if (allDiagnostics.length > 0) {
461
- const uniqueDiagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics);
462
- const message = ts.formatDiagnosticsWithColorAndContext(uniqueDiagnostics, formatHost);
463
- process.stdout.write(message);
464
- }
465
-
466
- // 결과 로그 출력
467
- if (state.hasError) {
468
- logger.error("빌드 실패");
40
+ } catch {
469
41
  process.exitCode = 1;
470
- } else {
471
- logger.info("빌드 완료");
42
+ } finally {
43
+ await orchestrator.shutdown();
472
44
  }
473
45
  }
474
-
475
- //#endregion