@simplysm/sd-cli 10.0.40 → 10.0.45

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 (63) hide show
  1. package/dist/build-tools/SdCliIndexFileGenerator.d.ts +5 -0
  2. package/dist/build-tools/SdCliIndexFileGenerator.js +51 -0
  3. package/dist/build-tools/SdCliIndexFileGenerator.js.map +1 -0
  4. package/dist/{SdLinter.d.ts → build-tools/SdLinter.d.ts} +1 -1
  5. package/dist/{SdLinter.js → build-tools/SdLinter.js} +2 -1
  6. package/dist/build-tools/SdLinter.js.map +1 -0
  7. package/dist/{SdTsIncrementalBuilder.d.ts → build-tools/SdTsIncrementalBuilder.d.ts} +1 -1
  8. package/dist/{SdTsIncrementalBuilder.js → build-tools/SdTsIncrementalBuilder.js} +1 -1
  9. package/dist/build-tools/SdTsIncrementalBuilder.js.map +1 -0
  10. package/dist/builders/SdCliClientBuilder.js +84 -8
  11. package/dist/builders/SdCliClientBuilder.js.map +1 -1
  12. package/dist/builders/SdCliJsLibLinter.js +1 -1
  13. package/dist/builders/SdCliJsLibLinter.js.map +1 -1
  14. package/dist/builders/SdCliServerBuilder.js +22 -5
  15. package/dist/builders/SdCliServerBuilder.js.map +1 -1
  16. package/dist/builders/SdCliTsLibBuilder.js +6 -5
  17. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  18. package/dist/commons.d.ts +18 -7
  19. package/dist/entry/SdCliElectron.d.ts +5 -0
  20. package/dist/entry/SdCliElectron.js +59 -1
  21. package/dist/entry/SdCliElectron.js.map +1 -1
  22. package/dist/entry/SdCliProject.js +75 -19
  23. package/dist/entry/SdCliProject.js.map +1 -1
  24. package/dist/index.d.ts +19 -1
  25. package/dist/index.js +19 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/sd-cli.js +26 -21
  28. package/dist/sd-cli.js.map +1 -1
  29. package/dist/utils/SdCliBuildResultUtil.js +3 -2
  30. package/dist/utils/SdCliBuildResultUtil.js.map +1 -1
  31. package/dist/utils/SdCliViteElectronMainPlugin.js +24 -7
  32. package/dist/utils/SdCliViteElectronMainPlugin.js.map +1 -1
  33. package/dist/utils/SdCliViteExternalPlugin.d.ts +1 -0
  34. package/dist/utils/SdCliViteExternalPlugin.js +9 -6
  35. package/dist/utils/SdCliViteExternalPlugin.js.map +1 -1
  36. package/dist/utils/SdCliViteReactSwcPlugin.js +2 -4
  37. package/dist/utils/SdCliViteReactSwcPlugin.js.map +1 -1
  38. package/dist/utils/sdCliTsDefineTransformer.js.map +1 -1
  39. package/package.json +12 -11
  40. package/src/build-tools/SdCliIndexFileGenerator.ts +62 -0
  41. package/src/{SdLinter.ts → build-tools/SdLinter.ts} +3 -2
  42. package/src/{SdTsIncrementalBuilder.ts → build-tools/SdTsIncrementalBuilder.ts} +2 -2
  43. package/src/builders/SdCliClientBuilder.ts +298 -203
  44. package/src/builders/SdCliJsLibLinter.ts +1 -1
  45. package/src/builders/SdCliServerBuilder.ts +325 -307
  46. package/src/builders/SdCliTsLibBuilder.ts +135 -133
  47. package/src/commons.ts +73 -61
  48. package/src/entry/SdCliElectron.ts +124 -48
  49. package/src/entry/SdCliProject.ts +524 -455
  50. package/src/index.ts +19 -1
  51. package/src/sd-cli.ts +190 -179
  52. package/src/utils/SdCliBuildResultUtil.ts +4 -3
  53. package/src/utils/SdCliViteElectronMainPlugin.ts +25 -7
  54. package/src/utils/SdCliViteExternalPlugin.ts +12 -7
  55. package/src/utils/SdCliViteReactSwcPlugin.ts +6 -8
  56. package/src/utils/sdCliTsDefineTransformer.ts +23 -23
  57. package/tsconfig.json +7 -1
  58. package/dist/SdLinter.js.map +0 -1
  59. package/dist/SdTsIncrementalBuilder.js.map +0 -1
  60. package/dist/entry/SdCliLocalUpdate.d.ts +0 -12
  61. package/dist/entry/SdCliLocalUpdate.js +0 -94
  62. package/dist/entry/SdCliLocalUpdate.js.map +0 -1
  63. package/src/entry/SdCliLocalUpdate.ts +0 -125
@@ -1,530 +1,599 @@
1
1
  import path from "path";
2
- import {FsUtil, Logger, SdProcess} from "@simplysm/sd-core-node";
2
+ import {FsUtil, Logger, PathUtil, SdProcess} from "@simplysm/sd-core-node";
3
3
  import {
4
- INpmConfig,
5
- ISdCliBuildClusterReqMessage,
6
- ISdCliBuildClusterResMessage,
7
- ISdCliConfig,
8
- ISdCliPackageBuildResult,
9
- TSdCliPackageConfig
4
+ INpmConfig,
5
+ ISdCliBuildClusterReqMessage,
6
+ ISdCliBuildClusterResMessage,
7
+ ISdCliPackageBuildResult,
8
+ TSdCliConfig,
9
+ TSdCliPackageConfig
10
10
  } from "../commons";
11
11
  import cp from "child_process";
12
12
  import {fileURLToPath, pathToFileURL} from "url";
13
13
  import {SdCliBuildResultUtil} from "../utils/SdCliBuildResultUtil";
14
14
  import semver from "semver";
15
- import {NotImplementError, Wait} from "@simplysm/sd-core-common";
16
- import {SdCliLocalUpdate} from "./SdCliLocalUpdate";
15
+ import {NotImplementError, StringUtil, Wait} from "@simplysm/sd-core-common";
16
+ import {SdCliIndexFileGenerator} from "../build-tools/SdCliIndexFileGenerator";
17
+ import {SdStorage} from "@simplysm/sd-storage";
17
18
 
18
19
  export class SdCliProject {
19
- public static async watchAsync(opt: {
20
- confFileRelPath: string;
21
- optNames: string[];
22
- pkgNames: string[];
23
- withLint: boolean;
24
- }): Promise<void> {
25
- const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "watchAsync"]);
26
-
27
- logger.debug("프로젝트 설정 가져오기...");
28
- const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(true, opt.optNames) as ISdCliConfig;
29
-
30
- if (projConf.localUpdates) {
31
- logger.debug("로컬 라이브러리 업데이트 변경감지 시작...");
32
- await SdCliLocalUpdate.watchAsync({confFileRelPath: opt.confFileRelPath, optNames: []});
33
- }
20
+ public static async watchAsync(opt: {
21
+ confFileRelPath: string;
22
+ optNames: string[];
23
+ pkgNames: string[];
24
+ withLint: boolean;
25
+ }): Promise<void> {
26
+ const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "watchAsync"]);
27
+
28
+ logger.debug("프로젝트 설정 가져오기...");
29
+ const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(true, opt.optNames) as TSdCliConfig;
30
+
31
+ logger.debug("프로젝트 package.json 가져오기...");
32
+ const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
33
+
34
+ logger.debug("패키지 목록 구성...");
35
+ if (!projNpmConf.workspaces) {
36
+ throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
37
+ }
38
+ const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
39
+ let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf);
40
+ if (opt.pkgNames.length !== 0) {
41
+ pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
42
+ }
34
43
 
35
- logger.debug("프로젝트 package.json 가져오기...");
36
- const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
44
+ logger.debug("패키지 존재 확인...");
45
+ const notExistsPkgs = Object.keys(projConf).filter((pkgConfKey) => allPkgPaths.every((pkgPath) => path.basename(pkgPath) !== pkgConfKey));
46
+ if (notExistsPkgs.length > 0) {
47
+ throw new Error("패키지를 찾을 수 없습니다. (" + notExistsPkgs.join(", ") + ")");
48
+ }
37
49
 
38
- logger.debug("패키지 목록 구성...");
39
- if (!projNpmConf.workspaces) {
40
- throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
50
+ logger.debug("라이브러리 INDEX 파일 생성...");
51
+ await pkgPaths.parallelAsync(async (pkgPath) => {
52
+ const pkgConf = projConf[path.basename(pkgPath)]!;
53
+ if (pkgConf.type === "library" && FsUtil.exists(path.resolve(pkgPath, "tsconfig.json"))) {
54
+ await SdCliIndexFileGenerator.watchAsync(pkgPath, pkgConf.polyfills);
55
+ }
56
+ });
57
+
58
+ logger.debug("빌드 프로세스 준비...");
59
+ const cluster = await this._prepareClusterAsync();
60
+
61
+ logger.debug("빌드 프로세스 이벤트 준비...");
62
+ const resultCache = new Map<string, ISdCliPackageBuildResult[]>();
63
+ let busyCount = 0;
64
+ const serverInfoMap = new Map<string, {
65
+ // server
66
+ pkgPath?: string; // persist
67
+ worker?: cp.ChildProcess; // persist
68
+ port?: number;
69
+ hasChanges: boolean;
70
+
71
+ //client
72
+ pathProxy: Record<string, number | undefined>; // persist
73
+ changeFilePaths: string[];
74
+ }>();
75
+ cluster.on("message", (message: ISdCliBuildClusterResMessage) => {
76
+ if (message.type === "change") {
77
+ if (busyCount === 0) {
78
+ logger.log("빌드를 시작합니다...");
41
79
  }
42
- const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
43
- let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf.packages);
44
- if (opt.pkgNames.length !== 0) {
45
- pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
80
+ busyCount++;
81
+ }
82
+ else if (message.type === "complete") {
83
+ for (const affectedFilePath of message.result!.affectedFilePaths) {
84
+ resultCache.delete(affectedFilePath);
46
85
  }
47
86
 
48
- logger.debug("패키지 존재 확인...");
49
- const notExistsPkgs = Object.keys(projConf.packages).filter((pkgConfKey) => allPkgPaths.every((pkgPath) => path.basename(pkgPath) !== pkgConfKey));
50
- if (notExistsPkgs.length > 0) {
51
- throw new Error("패키지를 찾을 수 없습니다. (" + notExistsPkgs.join(", ") + ")");
87
+ for (const buildResult of message.result!.buildResults) {
88
+ const cacheItem = resultCache.getOrCreate(buildResult.filePath ?? "none", []);
89
+ cacheItem.push(buildResult);
52
90
  }
53
91
 
54
- logger.debug("빌드 프로세스 준비...");
55
- const cluster = await this._prepareClusterAsync();
56
-
57
- logger.debug("빌드 프로세스 이벤트 준비...");
58
- const resultCache = new Map<string, ISdCliPackageBuildResult[]>();
59
- let busyCount = 0;
60
- const serverInfoMap = new Map<string, {
61
- // server
62
- pkgPath?: string; // persist
63
- worker?: cp.ChildProcess; // persist
64
- port?: number;
65
- hasChanges: boolean;
66
-
67
- //client
68
- pathProxy: Record<string, number | undefined>; // persist
69
- changeFilePaths: string[];
70
- }>();
71
- cluster.on("message", (message: ISdCliBuildClusterResMessage) => {
72
- if (message.type === "change") {
73
- if (busyCount === 0) {
74
- logger.log("빌드를 시작합니다...");
75
- }
76
- busyCount++;
77
- } else if (message.type === "complete") {
78
- for (const affectedFilePath of message.result!.affectedFilePaths) {
79
- resultCache.delete(affectedFilePath);
80
- }
92
+ if (message.req.pkgConf.type === "server") {
93
+ const pkgName = path.basename(message.req.pkgPath);
94
+ const serverInfo = serverInfoMap.getOrCreate(pkgName, {
95
+ hasChanges: false,
96
+ pathProxy: {},
97
+ changeFilePaths: []
98
+ });
99
+ serverInfo.pkgPath = message.req.pkgPath;
100
+ serverInfo.hasChanges = true;
101
+ }
81
102
 
82
- for (const buildResult of message.result!.buildResults) {
83
- const cacheItem = resultCache.getOrCreate(buildResult.filePath ?? "none", []);
84
- cacheItem.push(buildResult);
85
- }
103
+ if (message.req.pkgConf.type === "client") {
104
+ const pkgName = path.basename(message.req.pkgPath);
86
105
 
87
- if (message.req.pkgConf.type === "server") {
88
- const pkgName = path.basename(message.req.pkgPath);
89
- const serverInfo = serverInfoMap.getOrCreate(pkgName, {
90
- hasChanges: false,
91
- pathProxy: {},
92
- changeFilePaths: []
93
- });
94
- serverInfo.pkgPath = message.req.pkgPath;
95
- serverInfo.hasChanges = true;
96
- }
106
+ if (message.req.pkgConf.server !== undefined) {
107
+ const serverInfo = serverInfoMap.getOrCreate(message.req.pkgConf.server, {
108
+ hasChanges: false,
109
+ pathProxy: {},
110
+ changeFilePaths: []
111
+ });
112
+ serverInfo.pathProxy[pkgName] = message.result!.port;
113
+ serverInfo.changeFilePaths.push(...message.result!.affectedFilePaths);
114
+ }
115
+ else {
116
+ const serverInfo = serverInfoMap.getOrCreate(pkgName, {
117
+ hasChanges: false,
118
+ pathProxy: {},
119
+ changeFilePaths: []
120
+ });
121
+ serverInfo.port = message.result!.port;
122
+ serverInfo.changeFilePaths.push(...message.result!.affectedFilePaths);
123
+ }
124
+ }
97
125
 
98
- if (message.req.pkgConf.type === "client") {
99
- const pkgName = path.basename(message.req.pkgPath);
100
-
101
- if (message.req.pkgConf.server !== undefined) {
102
- const serverInfo = serverInfoMap.getOrCreate(message.req.pkgConf.server, {
103
- hasChanges: false,
104
- pathProxy: {},
105
- changeFilePaths: []
106
- });
107
- serverInfo.pathProxy[pkgName] = message.result!.port;
108
- serverInfo.changeFilePaths.push(...message.result!.affectedFilePaths);
109
- } else {
110
- const serverInfo = serverInfoMap.getOrCreate(pkgName, {
111
- hasChanges: false,
112
- pathProxy: {},
113
- changeFilePaths: []
114
- });
115
- serverInfo.port = message.result!.port;
116
- serverInfo.changeFilePaths.push(...message.result!.affectedFilePaths);
117
- }
126
+ setTimeout(async () => {
127
+ busyCount--;
128
+ if (busyCount === 0) {
129
+ for (const serverPkgName of serverInfoMap.keys()) {
130
+ const serverInfo = serverInfoMap.get(serverPkgName)!;
131
+ if (serverInfo.pkgPath !== undefined && serverInfo.hasChanges) {
132
+ logger.debug("서버 재시작...");
133
+ try {
134
+ const restartServerResult = await this._restartServerAsync(serverInfo.pkgPath, serverInfo.worker);
135
+ serverInfo.worker = restartServerResult.worker;
136
+ serverInfo.port = restartServerResult.port;
137
+ serverInfo.hasChanges = false;
138
+ }
139
+ catch (err) {
140
+ logger.error(err);
118
141
  }
142
+ }
119
143
 
120
- setTimeout(async () => {
121
- busyCount--;
122
- if (busyCount === 0) {
123
- for (const serverPkgName of serverInfoMap.keys()) {
124
- const serverInfo = serverInfoMap.get(serverPkgName)!;
125
- if (serverInfo.pkgPath !== undefined && serverInfo.hasChanges) {
126
- logger.debug("서버 재시작...");
127
- try {
128
- const restartServerResult = await this._restartServerAsync(serverInfo.pkgPath, serverInfo.worker);
129
- serverInfo.worker = restartServerResult.worker;
130
- serverInfo.port = restartServerResult.port;
131
- serverInfo.hasChanges = false;
132
- } catch (err) {
133
- logger.error(err);
134
- }
135
- }
136
-
137
- if (serverInfo.worker) {
138
- logger.debug("클라이언트 설정...");
139
- serverInfo.worker.send({
140
- type: "setPathProxy",
141
- pathProxy: serverInfo.pathProxy
142
- });
143
- }
144
- }
145
-
146
- const clientPaths: string[] = [];
147
- for (const serverInfo of serverInfoMap.values()) {
148
- if (Object.keys(serverInfo.pathProxy).length > 0) {
149
- for (const proxyPath of Object.keys(serverInfo.pathProxy)) {
150
- clientPaths.push(`http://localhost:${serverInfo.port}/${proxyPath}/`);
151
- }
152
- } else {
153
- clientPaths.push(`http://localhost:${serverInfo.port}/`);
154
- }
155
- }
156
- if (clientPaths.length > 0) {
157
- logger.info("클라이언트 개발 서버 접속 주소\n" + clientPaths.join("\n"));
158
- }
159
-
160
- const buildResults = Array.from(resultCache.values()).mapMany();
161
- this._logging(buildResults, logger);
162
- }
163
- }, 300);
144
+ if (serverInfo.worker) {
145
+ logger.debug("클라이언트 설정...");
146
+ serverInfo.worker.send({
147
+ type: "setPathProxy",
148
+ pathProxy: serverInfo.pathProxy
149
+ });
150
+ }
164
151
  }
165
- });
166
152
 
167
- logger.debug("빌드 프로세스 명령 전송...");
168
- busyCount++;
169
- logger.log("빌드를 시작합니다...");
170
-
171
- await pkgPaths.parallelAsync(async (pkgPath) => {
172
- const pkgConf = projConf.packages[path.basename(pkgPath)]!;
173
- if (pkgConf.type === "client") {
174
- const builderKeys = Object.keys(pkgConf.builder ?? {web: {}});
175
- await builderKeys.parallelAsync(async (builderKey) => {
176
- await this._runCommandAsync(cluster, "watch", pkgPath, projConf.packages[path.basename(pkgPath)]!, opt.withLint, builderKey);
177
- });
178
- } else {
179
- await this._runCommandAsync(cluster, "watch", pkgPath, projConf.packages[path.basename(pkgPath)]!, opt.withLint);
153
+ const clientPaths: string[] = [];
154
+ for (const serverInfo of serverInfoMap.values()) {
155
+ if (Object.keys(serverInfo.pathProxy).length > 0) {
156
+ for (const proxyPath of Object.keys(serverInfo.pathProxy)) {
157
+ clientPaths.push(`http://localhost:${serverInfo.port}/${proxyPath}/`);
158
+ }
159
+ }
160
+ else {
161
+ clientPaths.push(`http://localhost:${serverInfo.port}/`);
162
+ }
163
+ }
164
+ if (clientPaths.length > 0) {
165
+ logger.info("클라이언트 개발 서버 접속 주소\n" + clientPaths.join("\n"));
180
166
  }
181
- });
182
167
 
183
- busyCount--;
184
- if (busyCount === 0) {
185
168
  const buildResults = Array.from(resultCache.values()).mapMany();
186
169
  this._logging(buildResults, logger);
187
- }
170
+ }
171
+ }, 300);
172
+ }
173
+ });
174
+
175
+ logger.debug("빌드 프로세스 명령 전송...");
176
+ busyCount++;
177
+ logger.log("빌드를 시작합니다...");
178
+
179
+ await pkgPaths.parallelAsync(async (pkgPath) => {
180
+ const pkgConf = projConf[path.basename(pkgPath)]!;
181
+ if (pkgConf.type === "client") {
182
+ const builderKeys = Object.keys(pkgConf.builder ?? {web: {}});
183
+ await builderKeys.parallelAsync(async (builderKey) => {
184
+ await this._runCommandAsync(cluster, "watch", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint, builderKey);
185
+ });
186
+ }
187
+ else {
188
+ await this._runCommandAsync(cluster, "watch", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint);
189
+ }
190
+ });
191
+
192
+ busyCount--;
193
+ if (busyCount === 0) {
194
+ const buildResults = Array.from(resultCache.values()).mapMany();
195
+ this._logging(buildResults, logger);
188
196
  }
197
+ }
198
+
199
+ public static async buildAsync(opt: {
200
+ confFileRelPath: string;
201
+ optNames: string[];
202
+ pkgNames: string[];
203
+ withLint: boolean;
204
+ }): Promise<void> {
205
+ const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "buildAsync"]);
189
206
 
190
- public static async buildAsync(opt: {
191
- confFileRelPath: string;
192
- optNames: string[];
193
- pkgNames: string[];
194
- withLint: boolean;
195
- }): Promise<void> {
196
- const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "buildAsync"]);
207
+ logger.debug("프로젝트 설정 가져오기...");
208
+ const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(false, opt.optNames) as TSdCliConfig;
197
209
 
198
- logger.debug("프로젝트 설정 가져오기...");
199
- const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(false, opt.optNames) as ISdCliConfig;
210
+ logger.debug("프로젝트 package.json 가져오기...");
211
+ const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
200
212
 
201
- logger.debug("프로젝트 package.json 가져오기...");
202
- const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
213
+ logger.debug("패키지 목록 구성...");
214
+ if (!projNpmConf.workspaces) {
215
+ throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
216
+ }
217
+ const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
218
+ let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf);
219
+ if (opt.pkgNames.length !== 0) {
220
+ pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
221
+ }
203
222
 
204
- logger.debug("패키지 목록 구성...");
205
- if (!projNpmConf.workspaces) {
206
- throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
223
+ logger.debug("프로젝트 및 패키지 버전 설정...");
224
+ await this._upgradeVersionAsync(projNpmConf, allPkgPaths);
225
+
226
+ logger.debug("라이브러리 INDEX 파일 생성...");
227
+ await pkgPaths.parallelAsync(async (pkgPath) => {
228
+ const pkgConf = projConf[path.basename(pkgPath)]!;
229
+ if (pkgConf.type === "library" && FsUtil.exists(path.resolve(pkgPath, "tsconfig.json"))) {
230
+ await SdCliIndexFileGenerator.runAsync(pkgPath, pkgConf.polyfills);
231
+ }
232
+ });
233
+
234
+ logger.debug("빌드 프로세스 준비...");
235
+ const cluster = await this._prepareClusterAsync();
236
+
237
+ logger.debug("빌드 프로세스 명령 전달...");
238
+ const results = (
239
+ await pkgPaths.parallelAsync(async (pkgPath) => {
240
+ const pkgConf = projConf[path.basename(pkgPath)]!;
241
+ if (pkgConf.type === "client") {
242
+ const builderKeys = Object.keys(pkgConf.builder ?? {web: {}});
243
+ return (await builderKeys.parallelAsync(async (builderKey) => {
244
+ return await this._runCommandAsync(cluster, "build", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint, builderKey);
245
+ })).mapMany();
207
246
  }
208
- const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
209
- let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf.packages);
210
- if (opt.pkgNames.length !== 0) {
211
- pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
247
+ else {
248
+ return await this._runCommandAsync(cluster, "build", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint);
212
249
  }
250
+ })
251
+ ).mapMany();
213
252
 
214
- logger.debug("프로젝트 패키지 버전 설정...");
215
- await this._upgradeVersionAsync(projNpmConf, allPkgPaths);
216
-
217
- logger.debug("빌드 프로세스 준비...");
218
- const cluster = await this._prepareClusterAsync();
219
-
220
- logger.debug("빌드 프로세스 명령 전달...");
221
- const results = (
222
- await pkgPaths.parallelAsync(async (pkgPath) => {
223
- const pkgConf = projConf.packages[path.basename(pkgPath)]!;
224
- if (pkgConf.type === "client") {
225
- const builderKeys = Object.keys(pkgConf.builder ?? {web: {}});
226
- return (await builderKeys.parallelAsync(async (builderKey) => {
227
- return await this._runCommandAsync(cluster, "build", pkgPath, projConf.packages[path.basename(pkgPath)]!, opt.withLint, builderKey);
228
- })).mapMany();
229
- } else {
230
- return await this._runCommandAsync(cluster, "build", pkgPath, projConf.packages[path.basename(pkgPath)]!, opt.withLint);
231
- }
232
- })
233
- ).mapMany();
234
-
235
- logger.debug("빌드 프로세스 닫기...");
236
- this._closeCluster(cluster);
253
+ logger.debug("빌드 프로세스 닫기...");
254
+ this._closeCluster(cluster);
237
255
 
238
- this._logging(results, logger);
239
- }
256
+ this._logging(results, logger);
257
+ }
240
258
 
241
- public static async publishAsync(opt: {
242
- noBuild: boolean;
243
- confFileRelPath: string;
244
- optNames: string[];
245
- pkgNames: string[];
246
- withLint: boolean;
247
- }): Promise<void> {
248
- const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "publishAsync"]);
259
+ public static async publishAsync(opt: {
260
+ noBuild: boolean;
261
+ confFileRelPath: string;
262
+ optNames: string[];
263
+ pkgNames: string[];
264
+ withLint: boolean;
265
+ }): Promise<void> {
266
+ const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "publishAsync"]);
249
267
 
250
- logger.debug("프로젝트 설정 가져오기...");
251
- const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(false, opt.optNames) as ISdCliConfig;
268
+ logger.debug("프로젝트 설정 가져오기...");
269
+ const projConf = (await import(pathToFileURL(path.resolve(process.cwd(), opt.confFileRelPath)).href)).default(false, opt.optNames) as TSdCliConfig;
252
270
 
253
- logger.debug("프로젝트 package.json 가져오기...");
254
- const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
271
+ logger.debug("프로젝트 package.json 가져오기...");
272
+ const projNpmConf = (await FsUtil.readJsonAsync(path.resolve(process.cwd(), "package.json"))) as INpmConfig;
255
273
 
256
- if (opt.noBuild) {
257
- logger.warn("빌드하지 않고, 배포하는것은 상당히 위험합니다.");
258
- await this._waitSecMessageAsync("프로세스를 중지하려면, 'CTRL+C'를 누르세요.", 5);
259
- }
274
+ if (opt.noBuild) {
275
+ logger.warn("빌드하지 않고, 배포하는것은 상당히 위험합니다.");
276
+ await this._waitSecMessageAsync("프로세스를 중지하려면, 'CTRL+C'를 누르세요.", 5);
277
+ }
260
278
 
261
- // GIT 사용중일 경우, 커밋되지 않은 수정사항이 있는지 확인
262
- if (FsUtil.exists(path.resolve(process.cwd(), ".git"))) {
263
- logger.debug("GIT 커밋여부 확인...");
264
- const gitStatusResult = await SdProcess.spawnAsync("git status");
265
- if (gitStatusResult.includes("Changes") || gitStatusResult.includes("Untracked")) {
266
- throw new Error("커밋되지 않은 정보가 있습니다.\n" + gitStatusResult);
267
- }
268
- }
279
+ // GIT 사용중일 경우, 커밋되지 않은 수정사항이 있는지 확인
280
+ if (FsUtil.exists(path.resolve(process.cwd(), ".git"))) {
281
+ logger.debug("GIT 커밋여부 확인...");
282
+ const gitStatusResult = await SdProcess.spawnAsync("git status");
283
+ if (gitStatusResult.includes("Changes") || gitStatusResult.includes("Untracked")) {
284
+ throw new Error("커밋되지 않은 정보가 있습니다.\n" + gitStatusResult);
285
+ }
286
+ }
269
287
 
270
- logger.debug("패키지 목록 구성...");
271
- if (!projNpmConf.workspaces) {
272
- throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
273
- }
274
- const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
275
- let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf.packages);
276
- if (opt.pkgNames.length !== 0) {
277
- pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
278
- }
288
+ logger.debug("패키지 목록 구성...");
289
+ if (!projNpmConf.workspaces) {
290
+ throw new Error("프로젝트 package.json에 workspaces가 설정되어있지 않습니다.");
291
+ }
292
+ const allPkgPaths = await projNpmConf.workspaces.mapManyAsync(async (item) => await FsUtil.globAsync(item));
293
+ let pkgPaths = allPkgPaths.filter((pkgPath) => path.basename(pkgPath) in projConf);
294
+ if (opt.pkgNames.length !== 0) {
295
+ pkgPaths = pkgPaths.filter((pkgPath) => opt.pkgNames.includes(path.basename(pkgPath)));
296
+ }
279
297
 
280
- logger.debug("프로젝트 및 패키지 버전 설정...");
281
- await this._upgradeVersionAsync(projNpmConf, allPkgPaths);
298
+ logger.debug("프로젝트 및 패키지 버전 설정...");
299
+ await this._upgradeVersionAsync(projNpmConf, allPkgPaths);
282
300
 
283
- // 빌드
284
- if (!opt.noBuild) {
285
- logger.debug("빌드 프로세스 준비...");
286
- const cluster = await this._prepareClusterAsync();
301
+ // 빌드
302
+ if (!opt.noBuild) {
303
+ logger.debug("라이브러리 INDEX 파일 생성...");
304
+ await pkgPaths.parallelAsync(async (pkgPath) => {
305
+ const pkgConf = projConf[path.basename(pkgPath)]!;
306
+ if (pkgConf.type === "library" && FsUtil.exists(path.resolve(pkgPath, "tsconfig.json"))) {
307
+ await SdCliIndexFileGenerator.runAsync(pkgPath, pkgConf.polyfills);
308
+ }
309
+ });
287
310
 
288
- logger.debug("빌드 프로세스 명령 전달...");
289
- const results = (
290
- await pkgPaths.parallelAsync(async (pkgPath) => {
291
- return await this._runCommandAsync(cluster, "build", pkgPath, projConf.packages[path.basename(pkgPath)]!, opt.withLint);
292
- })
293
- ).mapMany();
311
+ logger.debug("빌드 프로세스 준비...");
312
+ const cluster = await this._prepareClusterAsync();
294
313
 
295
- logger.debug("빌드 프로세스 닫기...");
296
- this._closeCluster(cluster);
314
+ logger.debug("빌드 프로세스 명령 전달...");
315
+ const results = (
316
+ await pkgPaths.parallelAsync(async (pkgPath) => {
317
+ const pkgConf = projConf[path.basename(pkgPath)]!;
318
+ if (pkgConf.type === "client") {
319
+ const builderKeys = Object.keys(pkgConf.builder ?? {web: {}});
320
+ return (await builderKeys.parallelAsync(async (builderKey) => {
321
+ return await this._runCommandAsync(cluster, "build", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint, builderKey);
322
+ })).mapMany();
323
+ }
324
+ else {
325
+ return await this._runCommandAsync(cluster, "build", pkgPath, projConf[path.basename(pkgPath)]!, opt.withLint);
326
+ }
327
+ })
328
+ ).mapMany();
329
+
330
+ logger.debug("빌드 프로세스 닫기...");
331
+ this._closeCluster(cluster);
332
+
333
+ this._logging(results, logger);
334
+ }
297
335
 
298
- this._logging(results, logger);
299
- }
336
+ // GIT 사용중일경우, 새 버전 커밋 및 TAG 생성
337
+ if (FsUtil.exists(path.resolve(process.cwd(), ".git"))) {
338
+ logger.debug("새 버전 커밋 및 TAG 생성...");
339
+ await SdProcess.spawnAsync("git add .");
340
+ await SdProcess.spawnAsync(`git commit -m "v${projNpmConf.version}"`);
341
+ await SdProcess.spawnAsync(`git tag -a "v${projNpmConf.version}" -m "v${projNpmConf.version}"`);
300
342
 
301
- // GIT 사용중일경우, 새 버전 커밋 및 TAG 생성
302
- if (FsUtil.exists(path.resolve(process.cwd(), ".git"))) {
303
- logger.debug(" 버전 커밋 및 TAG 생성...");
304
- await SdProcess.spawnAsync("git add .");
305
- await SdProcess.spawnAsync(`git commit -m "v${projNpmConf.version}"`);
306
- await SdProcess.spawnAsync(`git tag -a "v${projNpmConf.version}" -m "v${projNpmConf.version}"`);
343
+ logger.debug("새 버전 푸쉬...");
344
+ await SdProcess.spawnAsync("git push");
345
+ await SdProcess.spawnAsync("git push --tags");
346
+ }
307
347
 
308
- logger.debug(" 버전 푸쉬...");
309
- await SdProcess.spawnAsync("git push");
310
- await SdProcess.spawnAsync("git push --tags");
311
- }
348
+ logger.debug("배포 시작...");
349
+ await pkgPaths.parallelAsync(async (pkgPath) => {
350
+ const pkgName = path.basename(pkgPath);
351
+ const pkgConf = projConf[pkgName];
352
+ if (pkgConf?.publish == null) return;
312
353
 
313
- logger.debug("배포 시작...");
314
- await pkgPaths.parallelAsync(async (pkgPath) => {
315
- const pkgName = path.basename(pkgPath);
316
- const pkgConf = projConf.packages[pkgName];
317
- if (pkgConf?.publish == null) return;
354
+ logger.debug(`[${pkgName}] 배포 시작...`);
355
+ await this._publishPkgAsync(pkgPath, pkgConf.publish);
356
+ logger.debug(`[${pkgName}] 배포 완료`);
357
+ });
318
358
 
319
- logger.debug(`[${pkgName}] 배포 시작...`);
320
- await this._publishPkgAsync(pkgPath, pkgConf.publish);
321
- logger.debug(`[${pkgName}] 배포 완료`);
322
- });
359
+ logger.info(`모든 배포가 완료되었습니다. (v${projNpmConf.version})`);
360
+ }
323
361
 
324
- logger.info(`모든 배포가 완료되었습니다. (v${projNpmConf.version})`);
362
+ private static async _publishPkgAsync(pkgPath: string, pkgPubConf: TSdCliPackageConfig["publish"]): Promise<void> {
363
+ if (pkgPubConf === "npm") {
364
+ await SdProcess.spawnAsync("yarn npm publish --access public", {cwd: pkgPath});
325
365
  }
366
+ else if (pkgPubConf?.type === "local-directory") {
367
+ const pkgNpmConf = (await FsUtil.readJsonAsync(path.resolve(pkgPath, "package.json"))) as INpmConfig;
326
368
 
327
- private static async _publishPkgAsync(pkgPath: string, pkgPubConf: TSdCliPackageConfig["publish"]): Promise<void> {
328
- if (pkgPubConf === "npm") {
329
- await SdProcess.spawnAsync("yarn npm publish --access public", {cwd: pkgPath});
330
- } else {
331
- throw new NotImplementError();
369
+ const targetRootPath = pkgPubConf.path.replace(/%([^%]*)%/g, (item) => {
370
+ const envName = item.replace(/%/g, "");
371
+ if (!StringUtil.isNullOrEmpty(pkgNpmConf.version) && envName === "SD_VERSION") {
372
+ return pkgNpmConf.version;
332
373
  }
374
+ return process.env[envName] ?? item;
375
+ });
376
+
377
+ const filePaths = await FsUtil.globAsync(path.resolve(pkgPath, "dist", "**", "*"), {
378
+ dot: true,
379
+ nodir: true
380
+ });
381
+
382
+ await filePaths.parallelAsync(async (filePath) => {
383
+ const relativeFilePath = path.relative(path.resolve(pkgPath, "dist"), filePath);
384
+ const targetPath = PathUtil.posix(targetRootPath, relativeFilePath);
385
+ await FsUtil.copyAsync(filePath, targetPath);
386
+ });
333
387
  }
334
-
335
- private static async _waitSecMessageAsync(msg: string, sec: number): Promise<void> {
336
- for (let i = sec; i > 0; i--) {
337
- if (i !== sec) {
338
- process.stdout.cursorTo(0);
339
- }
340
- process.stdout.write(`${msg} ${i}`);
341
- await Wait.time(1000);
342
- }
343
-
344
- process.stdout.cursorTo(0);
345
- process.stdout.clearLine(0);
388
+ else if (pkgPubConf?.type === "ftp" || pkgPubConf?.type === "ftps" || pkgPubConf?.type === "sftp") {
389
+ const ftp = await SdStorage.connectAsync(pkgPubConf.type, {
390
+ host: pkgPubConf.host,
391
+ port: pkgPubConf.port,
392
+ user: pkgPubConf.user,
393
+ pass: pkgPubConf.pass
394
+ });
395
+ await ftp.uploadDirAsync(path.resolve(pkgPath, "dist"), pkgPubConf.path ?? "/");
396
+ await ftp.closeAsync();
346
397
  }
347
-
348
- private static async _upgradeVersionAsync(projNpmConf: INpmConfig, allPkgPaths: string[]): Promise<void> {
349
- // 작업공간 package.json 버전 설정
350
- const newVersion = semver.inc(projNpmConf.version, "patch")!;
351
- projNpmConf.version = newVersion;
352
-
353
- const pkgNames = await allPkgPaths.mapAsync(async (pkgPath) => {
354
- const pkgNpmConf = await FsUtil.readJsonAsync(path.resolve(pkgPath, "package.json"));
355
- return pkgNpmConf.name;
356
- });
357
-
358
- const updateDepVersion = (deps: Record<string, string> | undefined): void => {
359
- if (!deps) return;
360
- for (const depName of Object.keys(deps)) {
361
- if (pkgNames.includes(depName)) {
362
- deps[depName] = newVersion;
363
- }
364
- }
365
- };
366
- updateDepVersion(projNpmConf.dependencies);
367
- updateDepVersion(projNpmConf.optionalDependencies);
368
- updateDepVersion(projNpmConf.devDependencies);
369
- updateDepVersion(projNpmConf.peerDependencies);
370
-
371
- const projNpmConfFilePath = path.resolve(process.cwd(), "package.json");
372
- await FsUtil.writeJsonAsync(projNpmConfFilePath, projNpmConf, {space: 2});
373
-
374
- // 각 패키지 package.json 버전 설정
375
- await allPkgPaths.parallelAsync(async (pkgPath) => {
376
- const pkgNpmConfFilePath = path.resolve(pkgPath, "package.json");
377
- const pkgNpmConf = await FsUtil.readJsonAsync(pkgNpmConfFilePath);
378
- pkgNpmConf.version = newVersion;
379
-
380
- updateDepVersion(pkgNpmConf.dependencies);
381
- updateDepVersion(pkgNpmConf.optionalDependencies);
382
- updateDepVersion(pkgNpmConf.devDependencies);
383
- updateDepVersion(pkgNpmConf.peerDependencies);
384
-
385
- await FsUtil.writeJsonAsync(pkgNpmConfFilePath, pkgNpmConf, {space: 2});
386
- });
398
+ else {
399
+ throw new NotImplementError();
387
400
  }
401
+ }
388
402
 
389
- private static _logging(buildResults: ISdCliPackageBuildResult[], logger: Logger): void {
390
- const messages = buildResults.filter((item) => item.severity === "message");
391
- const suggestions = buildResults.filter((item) => item.severity === "suggestion");
392
- const warnings = buildResults.filter((item) => item.severity === "warning");
393
- const errors = buildResults.filter((item) => item.severity === "error");
403
+ private static async _waitSecMessageAsync(msg: string, sec: number): Promise<void> {
404
+ for (let i = sec; i > 0; i--) {
405
+ if (i !== sec) {
406
+ process.stdout.cursorTo(0);
407
+ }
408
+ process.stdout.write(`${msg} ${i}`);
409
+ await Wait.time(1000);
410
+ }
394
411
 
395
- if (messages.length > 0) {
396
- logger.log("\n" + messages.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
412
+ process.stdout.cursorTo(0);
413
+ process.stdout.clearLine(0);
414
+ }
415
+
416
+ private static async _upgradeVersionAsync(projNpmConf: INpmConfig, allPkgPaths: string[]): Promise<void> {
417
+ // 작업공간 package.json 버전 설정
418
+ const newVersion = semver.inc(projNpmConf.version, "patch")!;
419
+ projNpmConf.version = newVersion;
420
+
421
+ const pkgNames = await allPkgPaths.mapAsync(async (pkgPath) => {
422
+ const pkgNpmConf = await FsUtil.readJsonAsync(path.resolve(pkgPath, "package.json"));
423
+ return pkgNpmConf.name;
424
+ });
425
+
426
+ const updateDepVersion = (deps: Record<string, string> | undefined): void => {
427
+ if (!deps) return;
428
+ for (const depName of Object.keys(deps)) {
429
+ if (pkgNames.includes(depName)) {
430
+ deps[depName] = newVersion;
397
431
  }
398
- if (suggestions.length > 0) {
399
- logger.info("\n" + suggestions.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
400
- }
401
- if (warnings.length > 0) {
402
- logger.warn("\n" + warnings.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
403
- }
404
- if (errors.length > 0) {
405
- logger.error("\n" + errors.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
406
- }
407
-
408
- logger.info("모든 빌드가 완료되었습니다.");
432
+ }
433
+ };
434
+ updateDepVersion(projNpmConf.dependencies);
435
+ updateDepVersion(projNpmConf.optionalDependencies);
436
+ updateDepVersion(projNpmConf.devDependencies);
437
+ updateDepVersion(projNpmConf.peerDependencies);
438
+
439
+ const projNpmConfFilePath = path.resolve(process.cwd(), "package.json");
440
+ await FsUtil.writeJsonAsync(projNpmConfFilePath, projNpmConf, {space: 2});
441
+
442
+ // 각 패키지 package.json 버전 설정
443
+ await allPkgPaths.parallelAsync(async (pkgPath) => {
444
+ const pkgNpmConfFilePath = path.resolve(pkgPath, "package.json");
445
+ const pkgNpmConf = await FsUtil.readJsonAsync(pkgNpmConfFilePath);
446
+ pkgNpmConf.version = newVersion;
447
+
448
+ updateDepVersion(pkgNpmConf.dependencies);
449
+ updateDepVersion(pkgNpmConf.optionalDependencies);
450
+ updateDepVersion(pkgNpmConf.devDependencies);
451
+ updateDepVersion(pkgNpmConf.peerDependencies);
452
+
453
+ await FsUtil.writeJsonAsync(pkgNpmConfFilePath, pkgNpmConf, {space: 2});
454
+ });
455
+ }
456
+
457
+ private static _logging(buildResults: ISdCliPackageBuildResult[], logger: Logger): void {
458
+ const messages = buildResults.filter((item) => item.severity === "message");
459
+ const suggestions = buildResults.filter((item) => item.severity === "suggestion");
460
+ const warnings = buildResults.filter((item) => item.severity === "warning");
461
+ const errors = buildResults.filter((item) => item.severity === "error");
462
+
463
+ if (messages.length > 0) {
464
+ logger.log("\n" + messages.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
465
+ }
466
+ if (suggestions.length > 0) {
467
+ logger.info("\n" + suggestions.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
468
+ }
469
+ if (warnings.length > 0) {
470
+ logger.warn("\n" + warnings.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
471
+ }
472
+ if (errors.length > 0) {
473
+ logger.error("\n" + errors.map((item) => SdCliBuildResultUtil.getMessage(item)).join("\n"));
409
474
  }
410
475
 
411
- private static async _prepareClusterAsync(): Promise<cp.ChildProcess> {
412
- const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "_runBuildClusterAsync"]);
413
-
414
- return await new Promise<cp.ChildProcess>(async (resolve, reject) => {
415
- const cluster = cp.fork(
416
- fileURLToPath(await import.meta.resolve!("../build-cluster")),
417
- [],
418
- {
419
- stdio: ["pipe", "pipe", "pipe", "ipc"],
420
- env: process.env
421
- }
422
- );
476
+ logger.info("모든 빌드가 완료되었습니다.");
477
+ }
423
478
 
424
- cluster.stdout!.pipe(process.stdout);
425
- cluster.stderr!.pipe(process.stderr);
479
+ private static async _prepareClusterAsync(): Promise<cp.ChildProcess> {
480
+ const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "_runBuildClusterAsync"]);
426
481
 
427
- cluster.on("exit", (code) => {
428
- if (code != null && code !== 0) {
429
- const err = new Error(`오류와 함께 닫힘 (${code})`);
430
- logger.error(err);
431
- reject(err);
432
- return;
433
- }
434
- });
482
+ return await new Promise<cp.ChildProcess>(async (resolve, reject) => {
483
+ const cluster = cp.fork(
484
+ fileURLToPath(await import.meta.resolve!("../build-cluster")),
485
+ [],
486
+ {
487
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
488
+ env: process.env
489
+ }
490
+ );
435
491
 
436
- cluster.on("error", (err) => {
437
- logger.error(err);
438
- reject(err);
439
- });
492
+ cluster.stdout!.pipe(process.stdout);
493
+ cluster.stderr!.pipe(process.stderr);
440
494
 
441
- cluster.on("message", (message) => {
442
- if (message === "ready") {
443
- logger.debug("빌드 클러스터 프로세스가 준비되었습니다.");
444
- resolve(cluster);
445
- }
446
- });
447
- });
448
- }
495
+ cluster.on("exit", (code) => {
496
+ if (code != null && code !== 0) {
497
+ const err = new Error(`오류와 함께 닫힘 (${code})`);
498
+ logger.error(err);
499
+ reject(err);
500
+ return;
501
+ }
502
+ });
449
503
 
450
- private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "watch", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<void>;
451
- private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "build", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<ISdCliPackageBuildResult[]>;
452
- private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "watch" | "build", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<ISdCliPackageBuildResult[] | void> {
453
- return await new Promise<ISdCliPackageBuildResult[] | void>((resolve) => {
454
- const cb = (message: ISdCliBuildClusterResMessage): void => {
455
- if (cmd === "watch" && message.type === "ready" && message.req.cmd === cmd && message.req.pkgPath === pkgPath) {
456
- cluster.off("message", cb);
457
- resolve();
458
- } else if (cmd === "build" && message.type === "complete" && message.req.cmd === cmd && message.req.pkgPath === pkgPath) {
459
- cluster.off("message", cb);
460
- resolve(message.result?.buildResults);
461
- }
462
- };
463
- cluster.on("message", cb);
464
-
465
- cluster.send({
466
- cmd,
467
- pkgPath,
468
- pkgConf,
469
- builderKey,
470
- withLint
471
- } as ISdCliBuildClusterReqMessage);
472
- });
473
- }
504
+ cluster.on("error", (err) => {
505
+ logger.error(err);
506
+ reject(err);
507
+ });
474
508
 
475
- private static _closeCluster(cluster: cp.ChildProcess): void {
476
- cluster.kill("SIGKILL");
509
+ cluster.on("message", (message) => {
510
+ if (message === "ready") {
511
+ logger.debug("빌드 클러스터 프로세스가 준비되었습니다.");
512
+ resolve(cluster);
513
+ }
514
+ });
515
+ });
516
+ }
517
+
518
+ private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "watch", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<void>;
519
+ private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "build", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<ISdCliPackageBuildResult[]>;
520
+ private static async _runCommandAsync(cluster: cp.ChildProcess, cmd: "watch" | "build", pkgPath: string, pkgConf: TSdCliPackageConfig, withLint: boolean, builderKey?: string): Promise<ISdCliPackageBuildResult[] | void> {
521
+ return await new Promise<ISdCliPackageBuildResult[] | void>((resolve) => {
522
+ const cb = (message: ISdCliBuildClusterResMessage): void => {
523
+ if (cmd === "watch" && message.type === "ready" && message.req.cmd === cmd && message.req.pkgPath === pkgPath) {
524
+ cluster.off("message", cb);
525
+ resolve();
526
+ }
527
+ else if (cmd === "build" && message.type === "complete" && message.req.cmd === cmd && message.req.pkgPath === pkgPath) {
528
+ cluster.off("message", cb);
529
+ resolve(message.result?.buildResults);
530
+ }
531
+ };
532
+ cluster.on("message", cb);
533
+
534
+ cluster.send({
535
+ cmd,
536
+ pkgPath,
537
+ pkgConf,
538
+ builderKey,
539
+ withLint
540
+ } as ISdCliBuildClusterReqMessage);
541
+ });
542
+ }
543
+
544
+ private static _closeCluster(cluster: cp.ChildProcess): void {
545
+ cluster.kill("SIGKILL");
546
+ }
547
+
548
+ private static async _restartServerAsync(pkgPath: string, prevServerProcess?: cp.ChildProcess): Promise<{
549
+ worker: cp.ChildProcess,
550
+ port: number
551
+ }> {
552
+ const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "_restartServerAsync"]);
553
+
554
+ if (prevServerProcess) {
555
+ prevServerProcess.kill("SIGKILL");
477
556
  }
478
557
 
479
- private static async _restartServerAsync(pkgPath: string, prevServerProcess?: cp.ChildProcess): Promise<{
480
- worker: cp.ChildProcess,
481
- port: number
482
- }> {
483
- const logger = Logger.get(["simplysm", "sd-cli", "SdCliProject", "_restartServerAsync"]);
484
-
485
- if (prevServerProcess) {
486
- prevServerProcess.kill("SIGKILL");
558
+ return await new Promise<{
559
+ worker: cp.ChildProcess,
560
+ port: number
561
+ }>(async (resolve, reject) => {
562
+ const worker = cp.fork(
563
+ fileURLToPath(await import.meta.resolve!("../server-worker")),
564
+ [pkgPath],
565
+ {
566
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
567
+ env: process.env
487
568
  }
569
+ );
488
570
 
489
- return await new Promise<{
490
- worker: cp.ChildProcess,
491
- port: number
492
- }>(async (resolve, reject) => {
493
- const worker = cp.fork(
494
- fileURLToPath(await import.meta.resolve!("../server-worker")),
495
- [pkgPath],
496
- {
497
- stdio: ["pipe", "pipe", "pipe", "ipc"],
498
- env: process.env
499
- }
500
- );
571
+ worker.stdout!.pipe(process.stdout);
572
+ worker.stderr!.pipe(process.stderr);
501
573
 
502
- worker.stdout!.pipe(process.stdout);
503
- worker.stderr!.pipe(process.stderr);
504
-
505
- worker.on("exit", (code) => {
506
- if (code != null && code !== 0) {
507
- const err = new Error(`오류와 함께 닫힘 (${code})`);
508
- logger.error(err);
509
- reject(err);
510
- return;
511
- }
512
- });
513
-
514
- worker.on("error", (err) => {
515
- logger.error(err);
516
- reject(err);
517
- });
518
-
519
- worker.on("message", (message: any) => {
520
- if ("port" in message) {
521
- logger.debug("서버가 시작되었습니다.");
522
- resolve({
523
- worker,
524
- port: message.port
525
- });
526
- }
527
- });
528
- });
529
- }
574
+ worker.on("exit", (code) => {
575
+ if (code != null && code !== 0) {
576
+ const err = new Error(`오류와 함께 닫힘 (${code})`);
577
+ logger.error(err);
578
+ reject(err);
579
+ return;
580
+ }
581
+ });
582
+
583
+ worker.on("error", (err) => {
584
+ logger.error(err);
585
+ reject(err);
586
+ });
587
+
588
+ worker.on("message", (message: any) => {
589
+ if ("port" in message) {
590
+ logger.debug("서버가 시작되었습니다.");
591
+ resolve({
592
+ worker,
593
+ port: message.port
594
+ });
595
+ }
596
+ });
597
+ });
598
+ }
530
599
  }