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