@simplysm/sd-cli 7.0.20 → 7.0.24

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 (36) hide show
  1. package/dist/bin/sd-cli.d.ts +1 -1
  2. package/dist/bin/sd-cli.mjs +54 -15
  3. package/dist/builder/SdCliServerBuilder.d.ts +21 -0
  4. package/dist/builder/SdCliServerBuilder.mjs +260 -0
  5. package/dist/builder/SdCliTsLibBuilder.mjs +2 -2
  6. package/dist/commons.d.ts +2 -4
  7. package/dist/entry-points/SdCliLocalUpdate.d.ts +7 -4
  8. package/dist/entry-points/SdCliLocalUpdate.mjs +6 -7
  9. package/dist/entry-points/SdCliNpm.d.ts +6 -0
  10. package/dist/entry-points/SdCliNpm.mjs +18 -0
  11. package/dist/entry-points/SdCliPrepare.d.ts +5 -0
  12. package/dist/entry-points/SdCliPrepare.mjs +54 -0
  13. package/dist/entry-points/SdCliWorkspace.d.ts +13 -5
  14. package/dist/entry-points/SdCliWorkspace.mjs +50 -13
  15. package/dist/packages/SdCliPackage.d.ts +5 -2
  16. package/dist/packages/SdCliPackage.mjs +31 -19
  17. package/dist/utils/SdCliBuildResultUtil.d.ts +4 -1
  18. package/dist/utils/SdCliBuildResultUtil.mjs +25 -2
  19. package/dist/utils/SdCliConfigUtil.d.ts +1 -1
  20. package/dist/utils/SdCliConfigUtil.mjs +5 -5
  21. package/dist/utils/SdCliNpmConfigUtil.d.ts +4 -0
  22. package/dist/utils/SdCliNpmConfigUtil.mjs +11 -0
  23. package/package.json +20 -11
  24. package/src/bin/sd-cli.ts +62 -14
  25. package/src/builder/SdCliServerBuilder.ts +287 -0
  26. package/src/builder/SdCliTsLibBuilder.ts +1 -1
  27. package/src/commons.ts +2 -5
  28. package/src/entry-points/SdCliLocalUpdate.ts +5 -6
  29. package/src/entry-points/SdCliNpm.ts +22 -0
  30. package/src/entry-points/SdCliPrepare.ts +54 -0
  31. package/src/entry-points/SdCliWorkspace.ts +65 -15
  32. package/src/packages/SdCliPackage.ts +33 -17
  33. package/src/utils/SdCliBuildResultUtil.ts +31 -1
  34. package/src/utils/SdCliConfigUtil.ts +4 -4
  35. package/src/utils/SdCliNpmConfigUtil.ts +12 -0
  36. package/tsconfig.json +4 -1
@@ -2,28 +2,31 @@ import { FsUtil, Logger, SdProcess } from "@simplysm/sd-core-node";
2
2
  import path from "path";
3
3
  import { INpmConfig, ISdCliConfig, ISdCliPackageBuildResult } from "../commons";
4
4
  import { SdCliPackage } from "../packages/SdCliPackage";
5
- import { Wait } from "@simplysm/sd-core-common";
5
+ import { Uuid, Wait } from "@simplysm/sd-core-common";
6
6
  import os from "os";
7
7
  import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
8
8
  import semver from "semver/preload";
9
+ import { SdCliConfigUtil } from "../utils/SdCliConfigUtil";
10
+ import { SdServiceServer } from "@simplysm/sd-service/server";
11
+ import { SdCliNpm } from "./SdCliNpm";
9
12
 
10
13
  export class SdCliWorkspace {
11
14
  private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
12
15
 
13
16
  private readonly _npmConfig: INpmConfig;
14
- private readonly _config: ISdCliConfig;
17
+ private readonly _serverInfoMap = new Map<string, IServerInfo>();
15
18
 
16
- public constructor(private readonly _rootPath: string,
17
- private readonly _configFilePath?: string) {
19
+ public constructor(private readonly _rootPath: string) {
18
20
  const npmConfigFilePath = path.resolve(this._rootPath, "package.json");
19
21
  this._npmConfig = FsUtil.readJson(npmConfigFilePath);
20
-
21
- this._config = FsUtil.readJson(path.resolve(this._rootPath, this._configFilePath ?? "simplysm.json"));
22
22
  }
23
23
 
24
- public async watchAsync(): Promise<void> {
24
+ public async watchAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
25
+ this._logger.debug("프로젝트 설정 가져오기...");
26
+ const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), true, opt.optNames);
27
+
25
28
  this._logger.debug("패키지 목록 구성...");
26
- const pkgs = await this._getPackagesAsync();
29
+ const pkgs = await this._getPackagesAsync(config);
27
30
 
28
31
  this._logger.debug("패키지 이벤트 설정...");
29
32
  let changeCount = 0;
@@ -37,7 +40,15 @@ export class SdCliWorkspace {
37
40
  changeCount++;
38
41
  this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
39
42
  })
40
- .on("complete", (results) => {
43
+ .on("complete", async (results) => {
44
+ if (pkg.type === "server") {
45
+ if (results.some((item) => item.severity === "error")) {
46
+ return;
47
+ }
48
+
49
+ await this._restartServerAsync(pkg);
50
+ }
51
+
41
52
  this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
42
53
  totalResultMap.set(pkg.name, results);
43
54
 
@@ -61,9 +72,38 @@ export class SdCliWorkspace {
61
72
  });
62
73
  }
63
74
 
64
- public async buildAsync(): Promise<void> {
75
+ private async _restartServerAsync(pkg: SdCliPackage): Promise<void> {
76
+ const entryFileRelPath = pkg.main;
77
+ if (entryFileRelPath === undefined) {
78
+ this._logger.error(`서버패키지(${pkg.name})의 'package.json'에서 'main'필드를 찾을 수 없습니다.`);
79
+ return;
80
+ }
81
+ const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
82
+
83
+ this._logger.log(`서버(${pkg.name}) 재시작...`);
84
+ const serverInfo = this._serverInfoMap.getOrCreate(pkg.name, {});
85
+ if (serverInfo.server) {
86
+ await serverInfo.server.closeAsync();
87
+ delete serverInfo.server;
88
+ }
89
+
90
+ serverInfo.server = (await import("file:///" + entryFilePath + "?update=" + Uuid.new().toString())).default as SdServiceServer | undefined;
91
+ if (!(serverInfo.server instanceof SdServiceServer)) {
92
+ this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
93
+ return;
94
+ }
95
+
96
+ await Wait.until(() => serverInfo.server!.isOpen);
97
+
98
+ this._logger.log(`서버(${pkg.name}) 재시작 완료`);
99
+ }
100
+
101
+ public async buildAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
102
+ this._logger.debug("프로젝트 설정 가져오기...");
103
+ const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
104
+
65
105
  this._logger.debug("패키지 목록 구성...");
66
- const pkgs = await this._getPackagesAsync();
106
+ const pkgs = await this._getPackagesAsync(config);
67
107
 
68
108
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
69
109
  await this._upgradeVersionAsync(pkgs);
@@ -96,7 +136,10 @@ export class SdCliWorkspace {
96
136
  }
97
137
  }
98
138
 
99
- public async publishAsync(opt: { noBuild: boolean }): Promise<void> {
139
+ public async publishAsync(opt: { noBuild: boolean; confFileRelPath: string; optNames: string[] }): Promise<void> {
140
+ this._logger.debug("프로젝트 설정 가져오기...");
141
+ const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
142
+
100
143
  if (opt.noBuild) {
101
144
  this._logger.warn("빌드하지 않고, 배포하는것은 상당히 위험합니다.");
102
145
  await this._waitSecMessageAsync("프로세스를 중지하려면, 'CTRL+C'를 누르세요.", 5);
@@ -112,11 +155,14 @@ export class SdCliWorkspace {
112
155
  }
113
156
 
114
157
  this._logger.debug("패키지 목록 구성...");
115
- const pkgs = await this._getPackagesAsync();
158
+ const pkgs = await this._getPackagesAsync(config);
116
159
 
117
160
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
118
161
  await this._upgradeVersionAsync(pkgs);
119
162
 
163
+ this._logger.debug("노드패키지 업데이트...");
164
+ await new SdCliNpm(this._rootPath).updateAsync();
165
+
120
166
  // 빌드
121
167
  if (!opt.noBuild) {
122
168
  this._logger.debug("빌드를 시작합니다...");
@@ -182,14 +228,14 @@ export class SdCliWorkspace {
182
228
  process.stdout.clearLine(0);
183
229
  }
184
230
 
185
- private async _getPackagesAsync(): Promise<SdCliPackage[]> {
231
+ private async _getPackagesAsync(conf: ISdCliConfig): Promise<SdCliPackage[]> {
186
232
  const pkgRootPaths = await this._npmConfig.workspaces?.mapManyAsync(async (item) => await FsUtil.globAsync(item));
187
233
  if (!pkgRootPaths) {
188
234
  throw new Error("최상위 'package.json'에서 'workspaces'를 찾을 수 없습니다.");
189
235
  }
190
236
 
191
237
  return pkgRootPaths.map((pkgRootPath) => {
192
- const pkgConfig = this._config.packages[path.basename(pkgRootPath)];
238
+ const pkgConfig = conf.packages[path.basename(pkgRootPath)];
193
239
  return pkgConfig ? new SdCliPackage(this._rootPath, pkgRootPath, pkgConfig) : undefined;
194
240
  }).filterExists();
195
241
  }
@@ -227,3 +273,7 @@ export class SdCliWorkspace {
227
273
  }
228
274
  }
229
275
  }
276
+
277
+ interface IServerInfo {
278
+ server?: SdServiceServer;
279
+ }
@@ -5,29 +5,38 @@ import { EventEmitter } from "events";
5
5
  import { ObjectUtil } from "@simplysm/sd-core-common";
6
6
  import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
7
7
  import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
8
+ import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
9
+ import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
8
10
 
9
11
  export class SdCliPackage extends EventEmitter {
10
12
  private readonly _npmConfig: INpmConfig;
11
13
 
14
+ public get basename(): string {
15
+ return path.basename(this._workspaceRootPath);
16
+ }
17
+
12
18
  public get name(): string {
13
19
  return this._npmConfig.name;
14
20
  }
15
21
 
22
+ public get main(): string | undefined {
23
+ return this._npmConfig.main;
24
+ }
25
+
26
+ public get type(): TSdCliPackageConfig["type"] {
27
+ return this._config.type;
28
+ }
29
+
16
30
  public get allDependencies(): string[] {
17
- return [
18
- ...Object.keys(this._npmConfig.dependencies ?? {}),
19
- ...Object.keys(this._npmConfig.optionalDependencies ?? {}),
20
- ...Object.keys(this._npmConfig.devDependencies ?? {}),
21
- ...Object.keys(this._npmConfig.peerDependencies ?? {})
22
- ].distinct();
31
+ return SdCliNpmConfigUtil.getAllDependencies(this._npmConfig);
23
32
  }
24
33
 
25
34
  public constructor(private readonly _workspaceRootPath: string,
26
- private readonly _rootPath: string,
35
+ public readonly rootPath: string,
27
36
  private readonly _config: TSdCliPackageConfig) {
28
37
  super();
29
38
 
30
- const npmConfigFilePath = path.resolve(this._rootPath, "package.json");
39
+ const npmConfigFilePath = path.resolve(this.rootPath, "package.json");
31
40
  this._npmConfig = FsUtil.readJson(npmConfigFilePath);
32
41
  }
33
42
 
@@ -53,19 +62,26 @@ export class SdCliPackage extends EventEmitter {
53
62
  updateDepVersion(this._npmConfig.devDependencies);
54
63
  updateDepVersion(this._npmConfig.peerDependencies);
55
64
 
56
- const npmConfigFilePath = path.resolve(this._rootPath, "package.json");
65
+ const npmConfigFilePath = path.resolve(this.rootPath, "package.json");
57
66
  await FsUtil.writeJsonAsync(npmConfigFilePath, this._npmConfig, { space: 2 });
58
67
  }
59
68
 
60
69
  public async watchAsync(): Promise<void> {
61
- const isTs = FsUtil.exists(path.resolve(this._rootPath, "tsconfig.json"));
70
+ const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
62
71
 
63
72
  if (isTs) {
64
73
  await this._genBuildTsconfigAsync();
65
74
  }
66
75
 
67
- const isAngular = isTs && this.allDependencies.includes("@angular/core");
68
- const builder = !isTs ? new SdCliJsLibBuilder(this._rootPath) : new SdCliTsLibBuilder(this._rootPath, isAngular);
76
+ let builder: SdCliJsLibBuilder | SdCliTsLibBuilder | SdCliServerBuilder;
77
+
78
+ if (this._config.type === "library") {
79
+ const isAngular = isTs && this.allDependencies.includes("@angular/core");
80
+ builder = !isTs ? new SdCliJsLibBuilder(this.rootPath) : new SdCliTsLibBuilder(this.rootPath, isAngular);
81
+ }
82
+ else {
83
+ builder = new SdCliServerBuilder(this.rootPath, this._config, this._workspaceRootPath);
84
+ }
69
85
 
70
86
  await builder
71
87
  .on("change", () => {
@@ -78,26 +94,26 @@ export class SdCliPackage extends EventEmitter {
78
94
  }
79
95
 
80
96
  public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
81
- const isTs = FsUtil.exists(path.resolve(this._rootPath, "tsconfig.json"));
97
+ const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
82
98
 
83
99
  if (isTs) {
84
100
  await this._genBuildTsconfigAsync();
85
101
  }
86
102
 
87
103
  const isAngular = isTs && this.allDependencies.includes("@angular/core");
88
- const builder = isTs ? new SdCliTsLibBuilder(this._rootPath, isAngular) : new SdCliJsLibBuilder(this._rootPath);
104
+ const builder = isTs ? new SdCliTsLibBuilder(this.rootPath, isAngular) : new SdCliJsLibBuilder(this.rootPath);
89
105
 
90
106
  return await builder.buildAsync();
91
107
  }
92
108
 
93
109
  public async publishAsync(): Promise<void> {
94
110
  if (this._config.type === "library" && this._config.publish === "npm") {
95
- await SdProcess.execAsync("npm publish --quiet --access public", { cwd: this._rootPath });
111
+ await SdProcess.execAsync("npm publish --quiet --access public", { cwd: this.rootPath });
96
112
  }
97
113
  }
98
114
 
99
115
  private async _genBuildTsconfigAsync(): Promise<void> {
100
- const baseTsconfigFilePath = path.resolve(this._rootPath, "tsconfig.json");
116
+ const baseTsconfigFilePath = path.resolve(this.rootPath, "tsconfig.json");
101
117
  const baseTsconfig: ITsconfig = await FsUtil.readJsonAsync(baseTsconfigFilePath);
102
118
 
103
119
  const buildTsconfig: ITsconfig = ObjectUtil.clone(baseTsconfig);
@@ -105,7 +121,7 @@ export class SdCliPackage extends EventEmitter {
105
121
  delete buildTsconfig.compilerOptions.baseUrl;
106
122
  delete buildTsconfig.compilerOptions.paths;
107
123
 
108
- const buildTsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
124
+ const buildTsconfigFilePath = path.resolve(this.rootPath, "tsconfig-build.json");
109
125
  await FsUtil.writeJsonAsync(buildTsconfigFilePath, buildTsconfig, { space: 2 });
110
126
  }
111
127
  }
@@ -2,9 +2,10 @@ import ts from "typescript";
2
2
  import * as os from "os";
3
3
  import * as path from "path";
4
4
  import { ISdCliPackageBuildResult } from "../commons";
5
+ import webpack from "webpack";
5
6
 
6
7
  export class SdCliBuildResultUtil {
7
- public static convertDiagsToResult(diag: ts.Diagnostic): ISdCliPackageBuildResult | undefined {
8
+ public static convertFromTsDiag(diag: ts.Diagnostic): ISdCliPackageBuildResult | undefined {
8
9
  const severity = diag.category === ts.DiagnosticCategory.Error ? "error"
9
10
  : diag.category === ts.DiagnosticCategory.Warning ? "warning"
10
11
  : undefined;
@@ -29,6 +30,35 @@ export class SdCliBuildResultUtil {
29
30
  };
30
31
  }
31
32
 
33
+ public static convertFromWebpackStats(stats: webpack.Stats): ISdCliPackageBuildResult[] {
34
+ const results: ISdCliPackageBuildResult[] = [];
35
+
36
+ for (const statWarn of stats.compilation.warnings) {
37
+ if (stats.compilation.options.ignoreWarnings?.some((ignoreWarning) => ignoreWarning(statWarn, stats.compilation))) continue;
38
+
39
+ results.push(this._convertFromWebpackError("warning", statWarn));
40
+ }
41
+
42
+ for (const statErr of stats.compilation.errors) {
43
+ results.push(this._convertFromWebpackError("error", statErr));
44
+ }
45
+
46
+ return results;
47
+ }
48
+
49
+ private static _convertFromWebpackError(severity: "warning" | "error", err: webpack.WebpackError): ISdCliPackageBuildResult {
50
+ console.log(err);
51
+ return {
52
+ filePath: err.file,
53
+ line: err.loc["start"].line,
54
+ char: err.loc["start"].column,
55
+ code: err.name,
56
+ severity,
57
+ message: err.message
58
+ };
59
+ }
60
+
61
+
32
62
  public static getMessage(result: ISdCliPackageBuildResult): string {
33
63
  let str = "";
34
64
  if (result.filePath !== undefined) {
@@ -4,15 +4,15 @@ import { ObjectUtil } from "@simplysm/sd-core-common";
4
4
  import path from "path";
5
5
 
6
6
  export class SdCliConfigUtil {
7
- public static loadConfig(confFilePath: string, isDev: boolean, opts?: string[]): ISdCliConfig {
8
- const confFileCont = FsUtil.readJson(confFilePath);
7
+ public static async loadConfigAsync(confFilePath: string, isDev: boolean, opts?: string[]): Promise<ISdCliConfig> {
8
+ const confFileCont = await FsUtil.readJsonAsync(confFilePath);
9
9
  let conf = this._getConfigFromFileContent(confFileCont, isDev, opts);
10
10
 
11
11
  // extends
12
12
  if (conf.extends) {
13
13
  for (const extConfFilePath of conf.extends) {
14
- const extConf = this.loadConfig(path.resolve(path.dirname(confFilePath), extConfFilePath), isDev, opts);
15
- conf = this._mergeObj(conf, extConf);
14
+ const extConf = await this.loadConfigAsync(path.resolve(path.dirname(confFilePath), extConfFilePath), isDev, opts);
15
+ conf = this._mergeObj(extConf, conf);
16
16
  }
17
17
  }
18
18
  delete conf["extends"];
@@ -0,0 +1,12 @@
1
+ import { INpmConfig } from "../commons";
2
+
3
+ export class SdCliNpmConfigUtil {
4
+ public static getAllDependencies(npmConfig: INpmConfig): string[] {
5
+ return [
6
+ ...Object.keys(npmConfig.dependencies ?? {}),
7
+ ...Object.keys(npmConfig.optionalDependencies ?? {}),
8
+ ...Object.keys(npmConfig.devDependencies ?? {}),
9
+ ...Object.keys(npmConfig.peerDependencies ?? {})
10
+ ].distinct();
11
+ }
12
+ }
package/tsconfig.json CHANGED
@@ -12,7 +12,10 @@
12
12
  ],
13
13
  "@simplysm/sd-core-common": [
14
14
  "../sd-core-common/src/index.ts"
15
+ ],
16
+ "@simplysm/sd-service/server": [
17
+ "../sd-service/src/server.ts"
15
18
  ]
16
19
  }
17
20
  }
18
- }
21
+ }