@simplysm/sd-cli 6.0.28 → 6.0.38

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 (70) hide show
  1. package/dist-node/bin/sd-cli.js +19 -4
  2. package/dist-node/bin/sd-cli.js.map +1 -1
  3. package/dist-node/build-tools/SdCliNgModuleFilesGenerator.js +106 -57
  4. package/dist-node/build-tools/SdCliNgModuleFilesGenerator.js.map +1 -1
  5. package/dist-node/build-tools/metadata/SdAotMetadataReader.js +13 -11
  6. package/dist-node/build-tools/metadata/SdAotMetadataReader.js.map +1 -1
  7. package/dist-node/build-tools/metadata/SdIvyMetadataReader.js +23 -6
  8. package/dist-node/build-tools/metadata/SdIvyMetadataReader.js.map +1 -1
  9. package/dist-node/build-tools/metadata/SdMetadataError.js +13 -0
  10. package/dist-node/build-tools/metadata/SdMetadataError.js.map +1 -0
  11. package/dist-node/build-tools/metadata/SdMyMetadataReader.js +22 -5
  12. package/dist-node/build-tools/metadata/SdMyMetadataReader.js.map +1 -1
  13. package/dist-node/builders/SdCliNgClientBuilder.js +74 -74
  14. package/dist-node/builders/SdCliNgClientBuilder.js.map +1 -1
  15. package/dist-node/builders/SdCliNgLibraryBuilder.js +49 -45
  16. package/dist-node/builders/SdCliNgLibraryBuilder.js.map +1 -1
  17. package/dist-node/builders/SdCliServerBuilder.js +33 -23
  18. package/dist-node/builders/SdCliServerBuilder.js.map +1 -1
  19. package/dist-node/builders/SdCliTypescriptBuilder.js +75 -65
  20. package/dist-node/builders/SdCliTypescriptBuilder.js.map +1 -1
  21. package/dist-node/entry-points/SdCliProject.js +17 -17
  22. package/dist-node/entry-points/SdCliProject.js.map +1 -1
  23. package/dist-node/packages/SdCliClientPackage.js +6 -4
  24. package/dist-node/packages/SdCliClientPackage.js.map +1 -1
  25. package/dist-node/packages/SdCliLibraryPackage.js +5 -3
  26. package/dist-node/packages/SdCliLibraryPackage.js.map +1 -1
  27. package/dist-node/packages/SdCliServerPackage.js +4 -3
  28. package/dist-node/packages/SdCliServerPackage.js.map +1 -1
  29. package/dist-node/utils/SdWebpackUtil.js +33 -13
  30. package/dist-node/utils/SdWebpackUtil.js.map +1 -1
  31. package/dist-node/workers/client-ng-gen-worker.js +54 -0
  32. package/dist-node/workers/client-ng-gen-worker.js.map +1 -0
  33. package/dist-node/workers/lib-build-worker.js +7 -6
  34. package/dist-node/workers/lib-build-worker.js.map +1 -1
  35. package/dist-types/build-tools/metadata/SdIvyMetadataReader.d.ts +1 -0
  36. package/dist-types/build-tools/metadata/SdMetadataError.d.ts +6 -0
  37. package/dist-types/build-tools/metadata/SdMyMetadataReader.d.ts +1 -0
  38. package/dist-types/builders/SdCliNgClientBuilder.d.ts +6 -2
  39. package/dist-types/builders/SdCliNgLibraryBuilder.d.ts +3 -2
  40. package/dist-types/builders/SdCliServerBuilder.d.ts +2 -1
  41. package/dist-types/builders/SdCliTypescriptBuilder.d.ts +5 -5
  42. package/dist-types/commons.d.ts +4 -1
  43. package/dist-types/entry-points/SdCliProject.d.ts +5 -1
  44. package/dist-types/packages/SdCliClientPackage.d.ts +2 -1
  45. package/dist-types/packages/SdCliLibraryPackage.d.ts +2 -1
  46. package/dist-types/packages/SdCliServerPackage.d.ts +2 -1
  47. package/dist-types/utils/SdWebpackUtil.d.ts +1 -1
  48. package/dist-types/workers/client-ng-gen-worker.d.ts +1 -0
  49. package/package.json +7 -7
  50. package/schema/schema.json +72 -1
  51. package/sd-tsconfig.node.json +2 -1
  52. package/src/bin/sd-cli.ts +19 -4
  53. package/src/build-tools/SdCliNgModuleFilesGenerator.ts +122 -70
  54. package/src/build-tools/metadata/SdAotMetadataReader.ts +4 -1
  55. package/src/build-tools/metadata/SdIvyMetadataReader.ts +27 -4
  56. package/src/build-tools/metadata/SdMetadataError.ts +7 -0
  57. package/src/build-tools/metadata/SdMyMetadataReader.ts +25 -3
  58. package/src/builders/SdCliNgClientBuilder.ts +123 -66
  59. package/src/builders/SdCliNgLibraryBuilder.ts +79 -42
  60. package/src/builders/SdCliServerBuilder.ts +48 -19
  61. package/src/builders/SdCliTypescriptBuilder.ts +102 -78
  62. package/src/commons.ts +2 -1
  63. package/src/entry-points/SdCliProject.ts +22 -14
  64. package/src/packages/SdCliClientPackage.ts +5 -3
  65. package/src/packages/SdCliLibraryPackage.ts +4 -2
  66. package/src/packages/SdCliServerPackage.ts +4 -3
  67. package/src/utils/SdWebpackUtil.ts +42 -22
  68. package/src/workers/client-ng-gen-worker.ts +60 -0
  69. package/src/workers/lib-build-worker.ts +7 -6
  70. package/tsconfig.json +2 -1
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from "events";
2
2
  import { INpmConfig, ISdPackageBuildResult, ISdServerPackageConfig, ITsconfig } from "../commons";
3
3
  import * as ts from "typescript";
4
- import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
4
+ import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
5
5
  import { ObjectUtil, StringUtil, Wait } from "@simplysm/sd-core-common";
6
6
  import * as webpack from "webpack";
7
7
  import * as path from "path";
@@ -27,7 +27,8 @@ export class SdCliServerBuilder extends EventEmitter {
27
27
  public constructor(public rootPath: string,
28
28
  public tsconfigFilePath: string,
29
29
  public projectRootPath: string,
30
- public config: ISdServerPackageConfig) {
30
+ public config: ISdServerPackageConfig,
31
+ public useCache: boolean) {
31
32
  super();
32
33
 
33
34
  const tsconfig: ITsconfig = FsUtil.readJson(this.tsconfigFilePath);
@@ -93,13 +94,19 @@ export class SdCliServerBuilder extends EventEmitter {
93
94
  ...this.config.env ? this.config.env : {}
94
95
  }
95
96
  },
96
- (typeof this.config.pm2 !== "boolean") ? this.config.pm2 : {}
97
+ (typeof this.config.pm2 !== "boolean") ? this.config.pm2 : {},
98
+ {
99
+ arrayProcess: "concat"
100
+ }
97
101
  ), undefined, 2));
98
102
  }
99
103
 
100
104
  // iis 파일 쓰기
101
- if (this.config.iis) {
105
+ if (this.config.iis !== undefined && this.config.iis !== false) {
102
106
  const iisDistPath = path.resolve(this.parsedTsconfig.options.outDir!, "web.config");
107
+ const serverExeFilePath = (this.config.iis !== true && "serverExeFilePath" in this.config.iis)
108
+ ? (this.config.iis.serverExeFilePath ?? "C:\\Program Files\\nodejs\\node.exe")
109
+ : "C:\\Program Files\\nodejs\\node.exe";
103
110
  await FsUtil.writeFileAsync(iisDistPath, `
104
111
  <configuration>
105
112
  <system.webServer>
@@ -107,7 +114,10 @@ export class SdCliServerBuilder extends EventEmitter {
107
114
  <handlers>
108
115
  <add name="iisnode" path="main.js" verb="*" modules="iisnode" />
109
116
  </handlers>
110
- <iisnode nodeProcessCommandLine="C:\\Program Files\\nodejs\\node.exe" watchedFiles="web.config;*.js" loggingEnabled="true" />
117
+ <iisnode nodeProcessCommandLine="${serverExeFilePath}"
118
+ watchedFiles="web.config;*.js"
119
+ loggingEnabled="true"
120
+ devErrorsEnabled="true" />
111
121
  <rewrite>
112
122
  <rules>
113
123
  <rule name="main">
@@ -115,9 +125,10 @@ export class SdCliServerBuilder extends EventEmitter {
115
125
  </rule>
116
126
  </rules>
117
127
  </rewrite>
118
- <httpErrors errorMode="Detailed" />
128
+ <httpErrors errorMode="Detailed" />
119
129
  </system.webServer>
120
130
  </configuration>
131
+
121
132
  `.trim());
122
133
  }
123
134
 
@@ -142,7 +153,6 @@ export class SdCliServerBuilder extends EventEmitter {
142
153
  const externalModuleNames = this._findExternalModuleNames(true);
143
154
 
144
155
  // 빌드
145
-
146
156
  const webpackConfig = this._getWebpackConfig(true, externalModuleNames);
147
157
  const compiler = webpack(webpackConfig);
148
158
  await new Promise<void>((resolve, reject) => {
@@ -173,11 +183,16 @@ export class SdCliServerBuilder extends EventEmitter {
173
183
  await this._startServerAsync();
174
184
  }
175
185
  catch (error) {
176
- results.push({
177
- filePath: undefined,
178
- severity: "error",
179
- message: error.message
180
- });
186
+ if (error instanceof Error) {
187
+ results.push({
188
+ filePath: undefined,
189
+ severity: "error",
190
+ message: error.message
191
+ });
192
+ }
193
+ else {
194
+ throw error;
195
+ }
181
196
  }
182
197
 
183
198
  // 결과 리턴
@@ -203,9 +218,9 @@ export class SdCliServerBuilder extends EventEmitter {
203
218
 
204
219
  const mainFilePath = path.resolve(this.parsedTsconfig.options.outDir!, "main.js");
205
220
 
206
- const prevLoggerConfigs = ObjectUtil.clone(Logger.configs);
221
+ // const prevLoggerConfigs = ObjectUtil.clone(Logger.configs);
207
222
  this._server = require(mainFilePath) as SdServiceServer | undefined;
208
- Logger.configs = prevLoggerConfigs;
223
+ // Logger.configs = prevLoggerConfigs;
209
224
 
210
225
  if (!this._server) {
211
226
  throw new Error(`${mainFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
@@ -228,16 +243,16 @@ export class SdCliServerBuilder extends EventEmitter {
228
243
  resolve: {
229
244
  extensions: [".ts", ".tsx", ".js"],
230
245
  symlinks: true,
231
- modules: [this.projectRootPath, "node_modules"],
246
+ // modules: [this.projectRootPath, "node_modules"],
232
247
  mainFields: ["es2020", "main", "module"]
233
248
  },
234
- resolveLoader: {
249
+ /*resolveLoader: {
235
250
  symlinks: true,
236
251
  modules: [
237
252
  "node_modules",
238
253
  ...this._findAllNodeModules(__dirname, this.projectRootPath)
239
254
  ]
240
- },
255
+ },*/
241
256
  context: this.projectRootPath,
242
257
  entry: {
243
258
  main: [
@@ -252,6 +267,7 @@ export class SdCliServerBuilder extends EventEmitter {
252
267
  // chunkFilename: watch ? "[name].js" : "[name].[chunkhash:20].js",
253
268
  filename: "[name].js",
254
269
  chunkFilename: "[name].js",
270
+ assetModuleFilename: "resources/[name][ext][query]",
255
271
  libraryTarget: watch ? "umd" : "commonjs"
256
272
  },
257
273
  performance: { hints: false },
@@ -280,10 +296,14 @@ export class SdCliServerBuilder extends EventEmitter {
280
296
  return `${msg.file}(${msg.line}, ${msg.character}): ${msg.code}: ${msg.severity} ${msg.content}`;
281
297
  }
282
298
  }
299
+ },
300
+ {
301
+ test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico|otf|xlsx?|pptx?|docx?|zip|pfx|pkl)$/,
302
+ type: "asset/resource"
283
303
  }
284
304
  ]
285
305
  },
286
- cache: watch ? { type: "memory", maxGenerations: 1 } : false,
306
+ cache: (watch && this.useCache) ? { type: "memory", maxGenerations: 1 } : false,
287
307
  optimization: {
288
308
  minimizer: watch ? [] : [
289
309
  new JavaScriptOptimizerPlugin({
@@ -296,7 +316,7 @@ export class SdCliServerBuilder extends EventEmitter {
296
316
  ],
297
317
  moduleIds: "deterministic",
298
318
  chunkIds: watch ? "named" : "deterministic",
299
- emitOnErrors: false
319
+ emitOnErrors: watch
300
320
  },
301
321
  plugins: [
302
322
  new DedupeModuleResolvePlugin({ verbose: false }) as any,
@@ -358,6 +378,15 @@ export class SdCliServerBuilder extends EventEmitter {
358
378
  };
359
379
  }
360
380
 
381
+ /*private _findAllInternalModuleCachePaths(): string[] {
382
+ return this._findAllNodeModules(this.rootPath, this.projectRootPath)
383
+ .mapMany((item) => (
384
+ FsUtil.readdir(item)
385
+ .filter((item1) => !item1.startsWith("@simplysm"))
386
+ .map((item1) => path.resolve(item, item1))
387
+ ));
388
+ }*/
389
+
361
390
  private _findAllNodeModules(from: string, root: string): string[] {
362
391
  const nodeModules: string[] = [];
363
392
 
@@ -13,30 +13,29 @@ import { ParserOptions } from "@typescript-eslint/types";
13
13
  export class SdCliTypescriptBuilder extends EventEmitter {
14
14
  protected readonly _logger: Logger;
15
15
 
16
- protected _parsedTsconfig: ts.ParsedCommandLine;
16
+ protected _tsconfig: ITsconfig;
17
17
  public readonly npmConfig: INpmConfig;
18
18
 
19
19
  protected _moduleResolutionCache?: ts.ModuleResolutionCache;
20
20
  protected _cacheCompilerHost?: ts.CompilerHost;
21
21
  protected _program?: ts.Program;
22
- protected _builder?: ts.BuilderProgram | ts.EmitAndSemanticDiagnosticsBuilderProgram;
22
+ protected _builder?: ts.BuilderProgram | ts.SemanticDiagnosticsBuilderProgram;
23
23
  protected readonly _fileCache = new Map<string, ITsBuildFileCache>();
24
24
 
25
25
  private readonly _indexFileGenerator?: SdCliIndexFileGenerator;
26
26
 
27
27
  private _watcher?: SdFsWatcher;
28
28
 
29
- public ignoreProcesses: string[];
29
+ public skipProcesses: string[];
30
30
 
31
31
  public constructor(public rootPath: string,
32
32
  public tsconfigFilePath: string,
33
- ignoreProcesses: ("emit" | "check" | "lint" | "genIndex")[],
33
+ skipProcesses: ("emit" | "check" | "lint" | "genIndex")[],
34
34
  public autoIndexConfig: ISdAutoIndexConfig | undefined) {
35
35
  super();
36
- this.ignoreProcesses = ignoreProcesses;
36
+ this.skipProcesses = skipProcesses;
37
37
 
38
- const tsconfig: ITsconfig = FsUtil.readJson(this.tsconfigFilePath);
39
- this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this.rootPath);
38
+ this._tsconfig = FsUtil.readJson(this.tsconfigFilePath);
40
39
 
41
40
  this.npmConfig = FsUtil.readJson(path.resolve(this.rootPath, "package.json"));
42
41
  this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, this.npmConfig.name]);
@@ -55,10 +54,12 @@ export class SdCliTypescriptBuilder extends EventEmitter {
55
54
  public async buildAsync(watch: boolean): Promise<void> {
56
55
  this.emit("change");
57
56
 
57
+ const parsedTsconfig = ts.parseJsonConfigFileContent(this._tsconfig, ts.sys, this.rootPath);
58
+
58
59
  // DIST 비우기
59
- await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
60
- if (this._parsedTsconfig.options.declarationDir !== undefined) {
61
- await FsUtil.removeAsync(this._parsedTsconfig.options.declarationDir);
60
+ await FsUtil.removeAsync(parsedTsconfig.options.outDir!);
61
+ if (parsedTsconfig.options.declarationDir !== undefined) {
62
+ await FsUtil.removeAsync(parsedTsconfig.options.declarationDir);
62
63
  }
63
64
 
64
65
  // 프로그램 리로드
@@ -128,11 +129,16 @@ export class SdCliTypescriptBuilder extends EventEmitter {
128
129
  this.emit("complete", Array.from(resultMap.values()).mapMany());
129
130
  }
130
131
  catch (err) {
131
- this.emit("complete", [{
132
- filePath: undefined,
133
- severity: "error",
134
- message: err.stack ?? err.message
135
- }]);
132
+ if (err instanceof Error) {
133
+ this.emit("complete", [{
134
+ filePath: undefined,
135
+ severity: "error",
136
+ message: err.stack ?? err.message
137
+ }]);
138
+ }
139
+ else {
140
+ throw err;
141
+ }
136
142
  }
137
143
  })
138
144
  .watch(watchPaths);
@@ -163,7 +169,7 @@ export class SdCliTypescriptBuilder extends EventEmitter {
163
169
 
164
170
  const result: ITsGenResult = { dirtyFilePaths: [], result: [] };
165
171
 
166
- if (!this.ignoreProcesses.includes("genIndex") && this._indexFileGenerator && this.autoIndexConfig) {
172
+ if (!this.skipProcesses.includes("genIndex") && this._indexFileGenerator && this.autoIndexConfig) {
167
173
  const generateResult = await this._indexFileGenerator.generateAsync();
168
174
  result.result.push(...generateResult.result);
169
175
  if (generateResult.changed) {
@@ -192,54 +198,58 @@ export class SdCliTypescriptBuilder extends EventEmitter {
192
198
  }
193
199
 
194
200
  protected async _lintAsync(dirtyFilePaths: string[]): Promise<ISdPackageBuildResult[]> {
195
- this._logger.debug("LINT");
196
-
197
- const linter = new ESLint({
198
- overrideConfig: {
199
- overrides: [
200
- {
201
- files: ["*.ts"],
202
- parserOptions: {
203
- program: this._program
204
- } as ParserOptions,
205
- settings: {
206
- "import/resolver": {
207
- typescript: {
208
- project: this.tsconfigFilePath
201
+ if (!this.skipProcesses.includes("lint")) {
202
+ this._logger.debug("LINT");
203
+
204
+ const linter = new ESLint({
205
+ overrideConfig: {
206
+ overrides: [
207
+ {
208
+ files: ["*.ts"],
209
+ parserOptions: {
210
+ program: this._program
211
+ } as ParserOptions,
212
+ settings: {
213
+ "import/resolver": {
214
+ typescript: {
215
+ project: this.tsconfigFilePath
216
+ }
209
217
  }
210
218
  }
211
219
  }
212
- }
213
- ]
214
- }
215
- });
216
-
217
- const filePaths = await dirtyFilePaths
218
- .filterAsync(async (item) => (
219
- !item.includes("node_modules")
220
- && PathUtil.isChildPath(item, this.rootPath)
221
- && FsUtil.exists(item)
222
- && !FsUtil.isDirectory(item)
223
- && !await linter.isPathIgnored(item)
224
- ));
225
-
226
- const lintResults = await linter.lintFiles(filePaths);
220
+ ]
221
+ }
222
+ });
227
223
 
228
- const result = lintResults.mapMany((report) => (
229
- report.messages.map((msg) => {
230
- const severity: "warning" | "error" = msg.severity === 1 ? "warning" : "error";
224
+ const filePaths = await dirtyFilePaths
225
+ .filterAsync(async (item) => (
226
+ !item.includes("node_modules")
227
+ && PathUtil.isChildPath(item, this.rootPath)
228
+ && FsUtil.exists(item)
229
+ && !FsUtil.isDirectory(item)
230
+ && !await linter.isPathIgnored(item)
231
+ ));
232
+
233
+ const lintResults = await linter.lintFiles(filePaths);
234
+
235
+ const result = lintResults.mapMany((report) => (
236
+ report.messages.map((msg) => {
237
+ const severity: "warning" | "error" = msg.severity === 1 ? "warning" : "error";
238
+
239
+ return {
240
+ filePath: report.filePath,
241
+ severity,
242
+ message: `${report.filePath}(${msg.line}, ${msg.column}): ${msg.ruleId ?? ""}: ${severity} ${msg.message}`
243
+ };
244
+ })
245
+ ));
231
246
 
232
- return {
233
- filePath: report.filePath,
234
- severity,
235
- message: `${report.filePath}(${msg.line}, ${msg.column}): ${msg.ruleId ?? ""}: ${severity} ${msg.message}`
236
- };
237
- })
238
- ));
247
+ this._logger.debug("LINT 결과", result);
239
248
 
240
- this._logger.debug("LINT 결과", result);
249
+ return result;
250
+ }
241
251
 
242
- return result;
252
+ return [];
243
253
  }
244
254
 
245
255
  /*protected _getAllDependencies(filePath: string): string[] {
@@ -257,10 +267,10 @@ export class SdCliTypescriptBuilder extends EventEmitter {
257
267
  }*/
258
268
 
259
269
  public getWatchPaths(): string[] {
260
- const builder = this._builder as ts.EmitAndSemanticDiagnosticsBuilderProgram;
270
+ // const builder = this._builder as ts.SemanticDiagnosticsBuilderProgram;
261
271
 
262
272
  const result: string[] = [];
263
- for (const sourceFile of builder.getSourceFiles()) {
273
+ for (const sourceFile of this._builder!.getSourceFiles()) {
264
274
  // result.push(sourceFile.fileName, ...this._getAllDependencies(sourceFile.fileName));
265
275
  result.push(sourceFile.fileName);
266
276
  }
@@ -295,15 +305,16 @@ export class SdCliTypescriptBuilder extends EventEmitter {
295
305
 
296
306
  const diagnostics: ts.Diagnostic[] = [];
297
307
 
298
- if (!this.ignoreProcesses.includes("check")) {
308
+ if (!this.skipProcesses.includes("check")) {
299
309
  diagnostics.push(
300
310
  ...this._builder.getOptionsDiagnostics(),
301
311
  ...this._builder.getGlobalDiagnostics()
302
312
  );
303
313
 
304
- for (const dirtyFilePath of dirtyFilePaths) {
305
- const sourceFile = this._builder.getSourceFile(dirtyFilePath);
306
- if (!sourceFile) continue;
314
+ for (const sourceFile of this._builder.getSourceFiles()) {
315
+ /*for (const dirtyFilePath of dirtyFilePaths) {
316
+ const sourceFile = this._builder.getSourceFile(dirtyFilePath);
317
+ if (!sourceFile) continue;*/
307
318
 
308
319
  if (sourceFile.isDeclarationFile) continue;
309
320
 
@@ -314,7 +325,7 @@ export class SdCliTypescriptBuilder extends EventEmitter {
314
325
  }
315
326
  }
316
327
 
317
- if (!this.ignoreProcesses.includes("emit")) {
328
+ if (!this.skipProcesses.includes("emit")) {
318
329
  for (const dirtyFilePath of dirtyFilePaths) {
319
330
  const sourceFile = this._builder.getSourceFile(dirtyFilePath);
320
331
  if (!sourceFile) continue;
@@ -347,8 +358,8 @@ export class SdCliTypescriptBuilder extends EventEmitter {
347
358
  this._reloadWatchPaths();
348
359
  }
349
360
 
350
- dirtyFilePaths.push(...changedFilePaths.filter((key) => this._fileCache.has(key)));
351
- dirtyFilePaths.distinctThis();
361
+ /*dirtyFilePaths.push(...changedFilePaths.filter((key) => this._fileCache.has(key)));
362
+ dirtyFilePaths.distinctThis();*/
352
363
 
353
364
  this._logger.debug("변경 프로그램 리로드 결과", dirtyFilePaths);
354
365
  return dirtyFilePaths;
@@ -357,12 +368,14 @@ export class SdCliTypescriptBuilder extends EventEmitter {
357
368
  public async reloadProgramAsync(watch: boolean): Promise<string[]> {
358
369
  this._logger.debug("프로그램 리로드");
359
370
 
360
- this._moduleResolutionCache = ts.createModuleResolutionCache(this.rootPath, (s) => s, this._parsedTsconfig.options);
361
- this._cacheCompilerHost = await this._createCacheCompilerHostAsync(this._parsedTsconfig, this._moduleResolutionCache);
371
+ const parsedTsconfig = ts.parseJsonConfigFileContent(this._tsconfig, ts.sys, this.rootPath);
372
+
373
+ this._moduleResolutionCache = ts.createModuleResolutionCache(this.rootPath, (s) => s, parsedTsconfig.options);
374
+ this._cacheCompilerHost = await this._createCacheCompilerHostAsync(parsedTsconfig, this._moduleResolutionCache);
362
375
 
363
376
  this._program = ts.createProgram(
364
- this._parsedTsconfig.fileNames,
365
- this._parsedTsconfig.options,
377
+ parsedTsconfig.fileNames,
378
+ parsedTsconfig.options,
366
379
  this._cacheCompilerHost,
367
380
  this._program
368
381
  );
@@ -381,12 +394,21 @@ export class SdCliTypescriptBuilder extends EventEmitter {
381
394
  };
382
395
 
383
396
  if (watch) {
384
- const builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
385
- this._program,
386
- this._cacheCompilerHost,
387
- this._builder as ts.EmitAndSemanticDiagnosticsBuilderProgram
388
- );
389
- this._builder = builder;
397
+ if (this.skipProcesses.includes("emit")) {
398
+ this._builder = ts.createSemanticDiagnosticsBuilderProgram(
399
+ this._program,
400
+ this._cacheCompilerHost,
401
+ this._builder as ts.SemanticDiagnosticsBuilderProgram
402
+ );
403
+ }
404
+ else {
405
+ this._builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
406
+ this._program,
407
+ this._cacheCompilerHost,
408
+ this._builder as ts.EmitAndSemanticDiagnosticsBuilderProgram
409
+ );
410
+ }
411
+ const builder = this._builder as ts.SemanticDiagnosticsBuilderProgram;
390
412
 
391
413
  const affectedFilePaths: string[] = [];
392
414
  while (true) {
@@ -417,7 +439,7 @@ export class SdCliTypescriptBuilder extends EventEmitter {
417
439
 
418
440
  // eslint-disable-next-line @typescript-eslint/require-await
419
441
  protected async _createCacheCompilerHostAsync(parsedTsconfig: ts.ParsedCommandLine, moduleResolutionCache: ts.ModuleResolutionCache): Promise<ts.CompilerHost> {
420
- const compilerHost = ts.createCompilerHost(parsedTsconfig.options);
442
+ const compilerHost = ts.createIncrementalCompilerHost(parsedTsconfig.options);
421
443
 
422
444
  const cacheCompilerHost = { ...compilerHost };
423
445
  cacheCompilerHost.fileExists = (fileName: string) => {
@@ -448,7 +470,9 @@ export class SdCliTypescriptBuilder extends EventEmitter {
448
470
  });
449
471
  }
450
472
 
451
- compilerHost.writeFile.call(cacheCompilerHost, fileName, data, writeByteOrderMark, onError, sourceFiles);
473
+ if (!FsUtil.exists(fileName) || FsUtil.readFile(fileName) !== data) {
474
+ compilerHost.writeFile.call(cacheCompilerHost, fileName, data, writeByteOrderMark, onError, sourceFiles);
475
+ }
452
476
  };
453
477
 
454
478
  cacheCompilerHost.readFile = (fileName: string) => {
package/src/commons.ts CHANGED
@@ -32,7 +32,7 @@ export interface ISdServerPackageConfig {
32
32
  externalDependencies?: string[];
33
33
  configs?: Record<string, any>;
34
34
  pm2?: Record<string, any> | boolean;
35
- iis?: boolean;
35
+ iis?: boolean | { serverExeFilePath?: string };
36
36
  publish?: TSdPublishConfig;
37
37
  }
38
38
 
@@ -74,6 +74,7 @@ export interface ITsconfig {
74
74
  strictInputTypes?: boolean;
75
75
  strictOutputEventTypes?: boolean;
76
76
  compilationMode?: "partial" | "full";
77
+ disableTypeScriptVersionCheck?: boolean;
77
78
  };
78
79
  files?: string[];
79
80
  include?: string[];
@@ -34,7 +34,7 @@ export class SdCliProject {
34
34
  this.npmConfig = FsUtil.readJson(this.npmConfigFilePath);
35
35
  }
36
36
 
37
- public async buildAsync(opt: { watch?: boolean; packages?: string[]; options?: string[]; config?: string }): Promise<void> {
37
+ public async buildAsync(opt: { watch?: boolean; packages?: string[]; options?: string[]; config?: string; skipProcesses?: string[]; localUpdate?: boolean }): Promise<{ hasError: boolean }> {
38
38
  this._logger.debug("프로젝트 설정 가져오기...");
39
39
  const config = await SdProjectConfigUtil.loadConfigAsync(
40
40
  this._rootPath,
@@ -43,13 +43,13 @@ export class SdCliProject {
43
43
  opt.config
44
44
  );
45
45
 
46
- if (opt.watch && config.localUpdates) {
46
+ if (opt.watch && opt.localUpdate && config.localUpdates) {
47
47
  this._logger.debug("로컬 라이브러리 업데이트 변경감지 시작...");
48
48
  await new SdCliLocalUpdater(this._rootPath).localUpdateAsync(true, opt);
49
49
  }
50
50
 
51
51
  this._logger.debug("프로젝트 패키지 목록 구성...");
52
- const allPkgs = await this._getAllPackagesAsync(config, opt.packages);
52
+ const allPkgs = await this._getAllPackagesAsync(config, opt.packages, opt.skipProcesses ?? [], !opt.localUpdate);
53
53
  const pkgs = allPkgs.filter((item) => !(item instanceof SdCliUnknownPackage)) as TSdCliBuildablePackage[];
54
54
 
55
55
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
@@ -141,6 +141,10 @@ export class SdCliProject {
141
141
  this._loggingResults(totalResultMap);
142
142
  this._logger.info(`모든 빌드가 완료되었습니다.`);
143
143
  this._loggingOpenClientHrefs();
144
+
145
+ return {
146
+ hasError: Array.from(totalResultMap.values()).mapMany().some((item) => item.severity === "error")
147
+ };
144
148
  }
145
149
 
146
150
 
@@ -174,19 +178,22 @@ export class SdCliProject {
174
178
  );
175
179
 
176
180
  this._logger.debug("프로젝트 패키지 목록 구성...");
177
- const allPkgs = await this._getAllPackagesAsync(config, opt.packages);
181
+ const allPkgs = await this._getAllPackagesAsync(config, opt.packages, [], false);
178
182
  const pkgs = allPkgs.filter((item) => !(item instanceof SdCliUnknownPackage) && item.config.publish) as TSdCliBuildablePackage[];
179
183
 
180
184
  // 빌드가 필요하면 빌드함
181
185
  if (opt.build) {
182
186
  this._logger.debug("빌드 수행...");
183
- await this.buildAsync({
187
+ const buildResult = await this.buildAsync({
184
188
  watch: false,
185
189
  packages: pkgs.map((item) => item.npmConfig.name)
186
190
  .filter((item) => !opt.packages || opt.packages.includes(item)),
187
191
  options: opt.options,
188
192
  config: opt.config
189
193
  });
194
+ if (buildResult.hasError) {
195
+ throw new Error("빌드중 에러가 발생했습니다.");
196
+ }
190
197
  }
191
198
 
192
199
  // 빌드시엔 빌드에서 버전업했고, 빌드가 아닌경우 여기서 버전업
@@ -239,7 +246,7 @@ export class SdCliProject {
239
246
  }
240
247
  }
241
248
 
242
- private async _getAllPackagesAsync(config: ISdProjectConfig, packages: string[] | undefined): Promise<TSdCliPackage[]> {
249
+ private async _getAllPackagesAsync(config: ISdProjectConfig, packages: string[] | undefined, skipProcesses: string[], useCache: boolean): Promise<TSdCliPackage[]> {
243
250
  // package.json에서 workspaces를 통해 패키지 경로 목록 가져오기
244
251
  const allPkgPaths = await this.npmConfig.workspaces?.mapManyAsync(async (item) => await FsUtil.globAsync(item));
245
252
  if (!allPkgPaths) {
@@ -268,32 +275,33 @@ export class SdCliProject {
268
275
  }
269
276
 
270
277
  // 각 package를 위한 worker 준비
271
- const workerCount = allPackageInfos.sum((item) => {
278
+ /*const workerCount = allPackageInfos.sum((item) => {
272
279
  if (item.config && item.config.type === "library") {
273
280
  return item.config.targets?.length ?? 1;
274
281
  }
275
282
  return 0;
276
- });
283
+ });*/
277
284
 
278
285
  const processWorkManager = await SdProcessWorkManager.createAsync(
279
286
  path.resolve(__dirname, `../workers/lib-build-worker`),
280
287
  [],
288
+ this._logger/*,
281
289
  Math.min(workerCount, Math.max(os.cpus().length - 2, 1)),
282
- Math.max(os.cpus().length - 2, 1)
290
+ Math.max(os.cpus().length - 2, 1)*/
283
291
  );
284
292
 
285
293
  // 패키지 목록 구성
286
294
  const pkgs: TSdCliPackage[] = [];
287
295
  for (const pkgInfo of allPackageInfos) {
288
296
  if (pkgInfo.config?.type === "library") {
289
- pkgs.push(new SdCliLibraryPackage(pkgInfo.rootPath, pkgInfo.config, processWorkManager));
297
+ pkgs.push(new SdCliLibraryPackage(pkgInfo.rootPath, pkgInfo.config, skipProcesses as any, processWorkManager));
290
298
  }
291
299
  else if (pkgInfo.config?.type === "client") {
292
300
  const serverPkgInfo = allPackageInfos.single((item) => item.name === (pkgInfo.config as ISdClientPackageConfig).server);
293
- pkgs.push(new SdCliClientPackage(pkgInfo.rootPath, pkgInfo.config, serverPkgInfo?.rootPath));
301
+ pkgs.push(new SdCliClientPackage(pkgInfo.rootPath, pkgInfo.config, useCache, serverPkgInfo?.rootPath));
294
302
  }
295
303
  else if (pkgInfo.config?.type === "server") {
296
- pkgs.push(new SdCliServerPackage(pkgInfo.rootPath, pkgInfo.config));
304
+ pkgs.push(new SdCliServerPackage(pkgInfo.rootPath, pkgInfo.config, useCache));
297
305
  }
298
306
  else {
299
307
  pkgs.push(new SdCliUnknownPackage(pkgInfo.rootPath));
@@ -322,12 +330,12 @@ export class SdCliProject {
322
330
 
323
331
  const warnings = totalResults
324
332
  .filter((item) => item.severity === "warning")
325
- .map((item) => item.message.trim() + "(" + item.pkgName + ")")
333
+ .map((item) => item.message.trim() + " (" + item.pkgName + ")")
326
334
  .distinct();
327
335
 
328
336
  const errors = totalResults
329
337
  .filter((item) => item.severity === "error")
330
- .map((item) => item.message.trim() + "(" + item.pkgName + ")")
338
+ .map((item) => item.message.trim() + " (" + item.pkgName + ")")
331
339
  .distinct();
332
340
 
333
341
  if (warnings.length > 0) {
@@ -16,6 +16,7 @@ export class SdCliClientPackage extends SdCliPackageBase {
16
16
 
17
17
  public constructor(public readonly rootPath: string,
18
18
  public readonly config: ISdClientPackageConfig,
19
+ public readonly useCache: boolean,
19
20
  public readonly _serverPath?: string) {
20
21
  super(rootPath);
21
22
  }
@@ -24,7 +25,7 @@ export class SdCliClientPackage extends SdCliPackageBase {
24
25
  await this._genBuildTsconfigAsync();
25
26
 
26
27
  const buildTsconfigFilePath = path.resolve(this.rootPath, `sd-tsconfig.json`);
27
- const builder = new SdCliNgClientBuilder(this.rootPath, buildTsconfigFilePath, process.cwd(), this.config);
28
+ const builder = new SdCliNgClientBuilder(this.rootPath, buildTsconfigFilePath, process.cwd(), this.config, this.useCache);
28
29
 
29
30
  await builder
30
31
  .on("change", () => {
@@ -40,7 +41,7 @@ export class SdCliClientPackage extends SdCliPackageBase {
40
41
  await this._genBuildTsconfigAsync();
41
42
 
42
43
  const buildTsconfigFilePath = path.resolve(this.rootPath, `sd-tsconfig.json`);
43
- const builder = new SdCliNgClientBuilder(this.rootPath, buildTsconfigFilePath, process.cwd(), this.config);
44
+ const builder = new SdCliNgClientBuilder(this.rootPath, buildTsconfigFilePath, process.cwd(), this.config, this.useCache);
44
45
  return await builder
45
46
  .on("change", () => {
46
47
  this.emit("change", undefined);
@@ -86,7 +87,8 @@ export class SdCliClientPackage extends SdCliPackageBase {
86
87
  strictInputAccessModifiers: true,
87
88
  strictTemplates: true,
88
89
  strictInputTypes: false,
89
- strictOutputEventTypes: false
90
+ strictOutputEventTypes: false,
91
+ disableTypeScriptVersionCheck: true
90
92
  };
91
93
 
92
94
  const buildTsconfigFilePath = path.resolve(this.rootPath, `sd-tsconfig.json`);