@simplysm/sd-cli 10.0.40 → 10.0.47

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