@simplysm/sd-cli 10.0.37 → 10.0.40

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