@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
@@ -3,18 +3,16 @@ import { INpmConfig, ISdClientPackageConfig, ISdPackageBuildResult, ITsconfig }
3
3
  import * as webpack from "webpack";
4
4
  import * as path from "path";
5
5
  import * as ts from "typescript";
6
- import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
6
+ import { FsUtil, Logger, PathUtil, SdProcessWorker } from "@simplysm/sd-core-node";
7
7
  import { JavaScriptOptimizerPlugin } from "@angular-devkit/build-angular/src/webpack/plugins/javascript-optimizer-plugin";
8
8
  import * as CssMinimizerPlugin from "css-minimizer-webpack-plugin";
9
9
  import * as esbuild from "esbuild";
10
10
  import {
11
- AnyComponentStyleBudgetChecker,
12
11
  CommonJsUsageWarnPlugin,
13
12
  DedupeModuleResolvePlugin,
14
13
  SuppressExtractedTextChunksWebpackPlugin
15
14
  } from "@angular-devkit/build-angular/src/webpack/plugins";
16
15
  import { LicenseWebpackPlugin } from "license-webpack-plugin";
17
- import { Type } from "@angular-devkit/build-angular";
18
16
  import { SassWorkerImplementation } from "@angular-devkit/build-angular/src/sass/sass-service";
19
17
  import * as MiniCssExtractPlugin from "mini-css-extract-plugin";
20
18
  import { AngularWebpackPlugin } from "@ngtools/webpack";
@@ -28,7 +26,6 @@ import { StringUtil, Wait } from "@simplysm/sd-core-common";
28
26
  import { augmentAppWithServiceWorker } from "@angular-devkit/build-angular/src/utils/service-worker";
29
27
  import * as browserslist from "browserslist";
30
28
  import * as WebpackHotMiddleware from "webpack-hot-middleware";
31
- import { SdCliNgLibraryBuilder } from "./SdCliNgLibraryBuilder";
32
29
  import * as os from "os";
33
30
  import { LintResult } from "eslint-webpack-plugin/declarations/options";
34
31
 
@@ -39,23 +36,23 @@ export class SdCliNgClientBuilder extends EventEmitter {
39
36
  public parsedTsconfig: ts.ParsedCommandLine;
40
37
  public readonly npmConfig: INpmConfig;
41
38
 
39
+ private _ngGenWorker?: SdProcessWorker;
40
+
41
+ protected readonly _logger: Logger;
42
+
42
43
  public constructor(public rootPath: string,
43
44
  public tsconfigFilePath: string,
44
45
  public projectRootPath: string,
45
- public config: ISdClientPackageConfig) {
46
+ public config: ISdClientPackageConfig,
47
+ public useCache: boolean) {
46
48
  super();
47
49
 
48
50
  const tsconfig: ITsconfig = FsUtil.readJson(this.tsconfigFilePath);
49
- const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this.rootPath);
50
- this.parsedTsconfig = {
51
- ...parsedTsconfig,
52
- options: {
53
- ...parsedTsconfig.options,
54
- ...tsconfig.angularCompilerOptions
55
- }
56
- };
51
+ this.parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this.rootPath, tsconfig.angularCompilerOptions);
57
52
 
58
53
  this.npmConfig = FsUtil.readJson(path.resolve(this.rootPath, "package.json"));
54
+
55
+ this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, this.npmConfig.name]);
59
56
  }
60
57
 
61
58
  public on(event: "change", listener: () => void): this;
@@ -72,12 +69,16 @@ export class SdCliNgClientBuilder extends EventEmitter {
72
69
  const buildResult: ISdPackageBuildResult[] = [];
73
70
 
74
71
  // GENERATOR
75
- const ngGenerator = new SdCliNgLibraryBuilder(this.rootPath, this.tsconfigFilePath, ["emit", "check", "lint"], undefined);
76
- const genFilePaths = await ngGenerator.reloadProgramAsync(false);
77
- const genResult = await ngGenerator.generateAdditionalFilesAsync(genFilePaths, false);
72
+ this._logger.debug("NgGen 수행");
73
+ const genResult = await this._runNgGenWorkerAsync(false);
74
+ // const ngGenerator = new SdCliNgLibraryBuilder(this.rootPath, this.tsconfigFilePath, ["emit", "check", "lint"], undefined);
75
+ // const genFilePaths = await ngGenerator.reloadProgramAsync(false);
76
+ // const genResult = await ngGenerator.generateAdditionalFilesAsync(genFilePaths, false);
78
77
  buildResult.push(...genResult.result);
78
+ this._logger.debug("NgGen 수행 결과", genResult);
79
79
 
80
80
  // WEBPACK 빌드
81
+ this._logger.debug("Webpack 빌드 수행");
81
82
  const webpackConfig = this._getWebpackConfig(false);
82
83
  const compiler = webpack(webpackConfig);
83
84
  const webpackBuildResults = await new Promise<ISdPackageBuildResult[]>((resolve, reject) => {
@@ -91,6 +92,7 @@ export class SdCliNgClientBuilder extends EventEmitter {
91
92
  resolve(results);
92
93
  });
93
94
  });
95
+ this._logger.debug("Webpack 빌드 결과", webpackBuildResults);
94
96
  buildResult.push(...webpackBuildResults);
95
97
 
96
98
  // .config.json 파일 쓰기
@@ -100,14 +102,16 @@ export class SdCliNgClientBuilder extends EventEmitter {
100
102
 
101
103
  // service-worker 처리
102
104
 
103
- const packageKey = this.npmConfig.name.split("/").last()!;
104
- await augmentAppWithServiceWorker(
105
- PathUtil.posix(this.projectRootPath) as any,
106
- PathUtil.posix(path.relative(this.projectRootPath, this.rootPath)) as any,
107
- PathUtil.posix(path.relative(this.projectRootPath, this.parsedTsconfig.options.outDir!)) as any,
108
- `/${packageKey}/`,
109
- PathUtil.posix(path.relative(this.projectRootPath, path.resolve(this.rootPath, "ngsw-config.json")))
110
- );
105
+ if (FsUtil.exists(path.resolve(this.rootPath, "ngsw-config.json"))) {
106
+ const packageKey = this.npmConfig.name.split("/").last()!;
107
+ await augmentAppWithServiceWorker(
108
+ PathUtil.posix(this.projectRootPath) as any,
109
+ PathUtil.posix(path.relative(this.projectRootPath, this.rootPath)) as any,
110
+ PathUtil.posix(path.relative(this.projectRootPath, this.parsedTsconfig.options.outDir!)) as any,
111
+ `/${packageKey}/`,
112
+ PathUtil.posix(path.relative(this.projectRootPath, path.resolve(this.rootPath, "ngsw-config.json")))
113
+ );
114
+ }
111
115
 
112
116
  this.emit("complete", buildResult.distinct());
113
117
  }
@@ -115,66 +119,73 @@ export class SdCliNgClientBuilder extends EventEmitter {
115
119
  public async watchAsync(serverPath?: string): Promise<NextHandleFunction[]> {
116
120
  await FsUtil.removeAsync(this.parsedTsconfig.options.outDir!);
117
121
 
118
- let buildResult: ISdPackageBuildResult[] = [];
122
+ let ngGenResults: ISdPackageBuildResult[] = [];
119
123
 
120
- const ngGenerator = new SdCliNgLibraryBuilder(this.rootPath, this.tsconfigFilePath, ["emit", "check", "lint"], undefined);
124
+ // const ngGenerator = new SdCliNgLibraryBuilder(this.rootPath, this.tsconfigFilePath, ["emit", "check", "lint", "genIndex"], undefined);
121
125
 
122
126
  // WEBPACK 빌드
127
+ let invalidFiles = new Set<string>();
123
128
  const webpackConfig = this._getWebpackConfig(true);
124
129
  const compiler = webpack(webpackConfig);
125
130
  return await new Promise<NextHandleFunction[]>((resolve, reject) => {
131
+ compiler.hooks.invalid.tap(this.constructor.name, (fileName) => {
132
+ if (fileName != null) {
133
+ invalidFiles.add(fileName);
134
+ }
135
+ });
136
+
126
137
  compiler.hooks.watchRun.tapAsync(this.constructor.name, async (compiler1, callback) => {
127
138
  this.emit("change");
128
139
 
129
- buildResult = [];
140
+ ngGenResults = [];
130
141
 
131
142
  // -- FIRST
132
143
 
133
144
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition,@typescript-eslint/strict-boolean-expressions
134
- if (!compiler.modifiedFiles || !compiler.removedFiles) {
135
- const genDirtyFilePaths = await ngGenerator.reloadProgramAsync(true);
136
- const genResult = await ngGenerator.generateAdditionalFilesAsync(genDirtyFilePaths, true);
137
- buildResult.push(...genResult.result);
138
-
145
+ if (invalidFiles.size === 0) {
146
+ this._logger.debug("첫 NgGen 수행");
147
+ const genResult = await this._runNgGenWorkerAsync(true);
148
+ // const genDirtyFilePaths = await ngGenerator.reloadProgramAsync(true);
149
+ // const genResult = await ngGenerator.generateAdditionalFilesAsync(genDirtyFilePaths, true);
150
+ ngGenResults.push(...genResult.result);
151
+ this._logger.debug("첫 NgGen 수행 결과", genResult);
152
+
153
+ this._logger.debug("Webpack 빌드 수행");
139
154
  callback();
140
155
  }
141
156
 
142
157
  // -- NOT FIRST
143
-
144
158
  else {
145
- const changedFiles = [...compiler.modifiedFiles, ...compiler.removedFiles];
146
-
147
159
  // 변경파일 중, 유효한 파일 추출
148
- const watchPaths = ngGenerator.getWatchPaths();
160
+ const changedFiles = [...invalidFiles];
161
+ invalidFiles = new Set<string>();
162
+
149
163
  const changedFilePaths = changedFiles
150
164
  .map((item) => PathUtil.posix(item))
151
165
  .filter((item) => path.basename(item).includes("."))
152
- .filter((item) => watchPaths.includes(path.dirname(item)))
153
166
  .distinct();
154
167
  if (changedFilePaths.length === 0) {
168
+ this._logger.debug("Webpack 빌드 수행");
155
169
  callback();
156
170
  return;
157
171
  }
158
172
 
159
- // 변경파일에 대한 프로그램 리로드
160
- const genDirtyFilePaths = await ngGenerator.reloadChangedProgramAsync(changedFilePaths, true);
161
- if (genDirtyFilePaths.length === 0) {
162
- callback();
163
- return;
164
- }
173
+ this._logger.debug("변경파일에 대한, NgGen 수행", changedFilePaths);
165
174
 
166
- // 변경파일에 대해 자동생성할 소스파일들 생성 및 리로드 (index.ts등)
167
- const genResult = await ngGenerator.generateAdditionalFilesAsync(genDirtyFilePaths, true);
168
- buildResult.push(...genResult.result);
175
+ const genResult = await this._runNgGenWorkerAsync(true, changedFilePaths);
176
+ ngGenResults.push(...genResult.result);
169
177
  if (genResult.dirtyFilePaths.length === 0) {
178
+ this._logger.debug("변경파일에 대한, NgGen 결과", genResult);
179
+ this._logger.debug("Webpack 빌드 수행");
170
180
  callback();
171
181
  return;
172
182
  }
173
- genDirtyFilePaths.push(...genResult.dirtyFilePaths);
183
+
184
+ this._logger.debug("변경파일에 대한, NgGen 결과", genResult);
174
185
 
175
186
  const modifiedFiles = [...compiler.modifiedFiles];
176
187
  const removedFiles = [...compiler.removedFiles];
177
- for (const genFilePath of genDirtyFilePaths.distinct()) {
188
+ for (const genFilePath of genResult.dirtyFilePaths.distinct()) {
178
189
  if (FsUtil.exists(genFilePath)) {
179
190
  modifiedFiles.push(genFilePath);
180
191
  }
@@ -185,6 +196,7 @@ export class SdCliNgClientBuilder extends EventEmitter {
185
196
  compiler.modifiedFiles = new Set(modifiedFiles.distinct());
186
197
  compiler.removedFiles = new Set(removedFiles.distinct());
187
198
 
199
+ this._logger.debug("Webpack 빌드 수행");
188
200
  callback();
189
201
  }
190
202
  });
@@ -196,7 +208,9 @@ export class SdCliNgClientBuilder extends EventEmitter {
196
208
 
197
209
  compiler.hooks.failed.tap(this.constructor.name, (err) => {
198
210
  const results = SdWebpackUtil.getWebpackResults(err);
199
- this.emit("complete", [...buildResult, ...results].distinct());
211
+ const allResults = [...ngGenResults, ...results].distinct();
212
+ this.emit("complete", allResults);
213
+ this._logger.debug("Webpack 빌드 수행 결과", allResults);
200
214
  reject(err);
201
215
  });
202
216
 
@@ -212,7 +226,9 @@ export class SdCliNgClientBuilder extends EventEmitter {
212
226
 
213
227
 
214
228
  await Wait.true(() => devMiddleware !== undefined && hotMiddleware !== undefined);
215
- this.emit("complete", [...buildResult, ...results].distinct());
229
+ const allResults = [...ngGenResults, ...results].distinct();
230
+ this.emit("complete", allResults);
231
+ this._logger.debug("Webpack 빌드 수행 결과", allResults);
216
232
  resolve([devMiddleware!, hotMiddleware!]);
217
233
  });
218
234
 
@@ -242,19 +258,16 @@ export class SdCliNgClientBuilder extends EventEmitter {
242
258
  profile: false,
243
259
  resolve: {
244
260
  roots: [this.rootPath],
245
- extensions: [".ts", ".tsx", ".mjs", ".js"],
261
+ extensions: [".ts", ".js"],
246
262
  symlinks: true,
247
- modules: [this.projectRootPath, "node_modules"],
263
+ // modules: allNodeModulePaths,
248
264
  mainFields: ["es2015", "browser", "module", "main"],
249
265
  fallback: this.config.resolveFallback
250
266
  },
251
- resolveLoader: {
267
+ /*resolveLoader: {
252
268
  symlinks: true,
253
- modules: [
254
- "node_modules",
255
- ...this._findAllNodeModules(__dirname, this.projectRootPath)
256
- ]
257
- },
269
+ modules: allNodeModulePaths
270
+ },*/
258
271
  context: this.projectRootPath,
259
272
  entry: {
260
273
  main: [
@@ -278,6 +291,7 @@ export class SdCliNgClientBuilder extends EventEmitter {
278
291
  // chunkFilename: watch ? "[name].js" : "[name].[chunkhash:20].js",
279
292
  filename: "[name].js",
280
293
  chunkFilename: "[name].js",
294
+ assetModuleFilename: "resources/[name][ext][query]",
281
295
  crossOriginLoading: false,
282
296
  trustedTypes: "angular#bundler"
283
297
  },
@@ -377,18 +391,22 @@ export class SdCliNgClientBuilder extends EventEmitter {
377
391
  {
378
392
  test: /\.[jt]sx?$/,
379
393
  loader: "@ngtools/webpack"
394
+ },
395
+ {
396
+ test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico|otf|xlsx?|pptx?|docx?|zip|pfx|pkl)$/,
397
+ type: "asset/resource"
380
398
  }
381
399
  ]
382
400
  },
383
401
  experiments: { syncWebAssembly: true, asyncWebAssembly: true },
384
- cache: watch ? { type: "memory", maxGenerations: 1 } : false,
402
+ cache: (watch && this.useCache) ? { type: "memory", maxGenerations: 1 } : false,
385
403
  optimization: {
386
404
  minimizer: watch ? [] : [
387
405
  new JavaScriptOptimizerPlugin({
388
406
  define: { ngDevMode: false, ngI18nClosureMode: false, ngJitMode: false },
389
407
  sourcemap: false,
390
408
  target: this.parsedTsconfig.options.target,
391
- keepNames: false,
409
+ keepNames: true,
392
410
  removeLicenses: true,
393
411
  advanced: true
394
412
  }) as any,
@@ -403,9 +421,9 @@ export class SdCliNgClientBuilder extends EventEmitter {
403
421
  minify: true,
404
422
  sourcefile,
405
423
  target: browserslist([
406
- "last 2 Chrome versions",
424
+ "last 1 Chrome versions",
407
425
  "last 2 Edge major versions"
408
- ])
426
+ ]).map((item) => item.replace(/ /g, ""))
409
427
  });
410
428
 
411
429
  return {
@@ -437,7 +455,7 @@ export class SdCliNgClientBuilder extends EventEmitter {
437
455
  ],
438
456
  moduleIds: "deterministic",
439
457
  chunkIds: watch ? "named" : "deterministic",
440
- emitOnErrors: false,
458
+ emitOnErrors: watch,
441
459
  runtimeChunk: "single",
442
460
  splitChunks: {
443
461
  maxAsyncRequests: Infinity,
@@ -504,13 +522,13 @@ export class SdCliNgClientBuilder extends EventEmitter {
504
522
  append: undefined
505
523
  })
506
524
  ] : [],
507
- new AnyComponentStyleBudgetChecker(watch ? [] : [
525
+ /*new AnyComponentStyleBudgetChecker(watch ? [] : [
508
526
  {
509
527
  type: Type.Any,
510
528
  maximumWarning: "2kb",
511
529
  maximumError: "4kb"
512
530
  }
513
- ]),
531
+ ]),*/
514
532
  {
515
533
  apply(compiler) {
516
534
  compiler.hooks.shutdown.tap("sass-worker", () => {
@@ -584,13 +602,37 @@ export class SdCliNgClientBuilder extends EventEmitter {
584
602
  }),
585
603
  ...watch ? [
586
604
  new webpack.HotModuleReplacementPlugin()
587
- ] : []
605
+ ] : [],
606
+ /*...watch ? [
607
+ new webpack.WatchIgnorePlugin({
608
+ paths: [
609
+ path.resolve(this.rootPath, "src/_modules/"),
610
+ path.resolve(this.rootPath, "src/_routes.ts")
611
+ ]
612
+ })
613
+ ] : [],*/
614
+ new webpack.ProgressPlugin({
615
+ handler: (per: number, msg: string, ...args: string[]) => {
616
+ const phaseText = msg ? ` - phase: ${msg}` : "";
617
+ const argsText = args.length > 0 ? ` - args: [${args.join(", ")}]` : "";
618
+ this._logger.debug(`Webpack 빌드 수행중...(${Math.round(per * 100)}%)${phaseText}${argsText}`);
619
+ }
620
+ })
588
621
  ],
589
622
  node: false,
590
623
  stats: "errors-warnings"
591
624
  };
592
625
  }
593
626
 
627
+ /*private _findAllInternalModuleCachePaths(): string[] {
628
+ return this._findAllNodeModules(this.rootPath, this.projectRootPath)
629
+ .mapMany((item) => (
630
+ FsUtil.readdir(item)
631
+ .filter((item1) => !item1.startsWith("@simplysm"))
632
+ .map((item1) => path.resolve(item, item1))
633
+ ));
634
+ }
635
+
594
636
  private _findAllNodeModules(from: string, root: string): string[] {
595
637
  const nodeModules: string[] = [];
596
638
 
@@ -609,5 +651,20 @@ export class SdCliNgClientBuilder extends EventEmitter {
609
651
  }
610
652
 
611
653
  return nodeModules;
654
+ }*/
655
+
656
+ private async _runNgGenWorkerAsync(watch: boolean, changedFilePaths?: string[]): Promise<{ dirtyFilePaths: string[]; result: ISdPackageBuildResult[] }> {
657
+ if (!this._ngGenWorker) {
658
+ this._ngGenWorker = await SdProcessWorker.createAsync(path.resolve(__dirname, `../workers/client-ng-gen-worker`), []);
659
+ }
660
+
661
+ const sender = this._ngGenWorker.createWorkSender();
662
+ return await new Promise<{ dirtyFilePaths: string[]; result: ISdPackageBuildResult[] }>(async (resolve) => {
663
+ await sender
664
+ .on("complete", (result) => {
665
+ resolve(result);
666
+ })
667
+ .sendAsync(this.rootPath, watch, changedFilePaths);
668
+ });
612
669
  }
613
670
  }
@@ -1,22 +1,22 @@
1
1
  import * as ts from "typescript";
2
- import { ISdAutoIndexConfig, ISdPackageBuildResult, ITsconfig } from "../commons";
2
+ import { ISdAutoIndexConfig, ISdPackageBuildResult } from "../commons";
3
3
  import * as path from "path";
4
4
  import { SdTsDiagnosticUtil } from "../utils/SdTsDiagnosticUtil";
5
5
  import { NgccProcessingCache } from "ng-packagr/lib/ng-package/ngcc-cache";
6
6
  import { NgccProcessor } from "ng-packagr/lib/ngc/ngcc-processor";
7
7
  import { EntryPointNode } from "ng-packagr/lib/ng-package/nodes";
8
8
  import { ngccTransformCompilerHost } from "ng-packagr/lib/ts/ngcc-transform-compiler-host";
9
- import { NgtscProgram } from "@angular/compiler-cli";
9
+ import { MetadataCollector, NgtscProgram } from "@angular/compiler-cli";
10
10
  import { ITsBuildFileCache, ITsGenResult, SdCliTypescriptBuilder } from "./SdCliTypescriptBuilder";
11
11
  import { NgCompiler } from "@angular/compiler-cli/src/ngtsc/core";
12
12
  import { NeverEntryError, StringUtil } from "@simplysm/sd-core-common";
13
- import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
13
+ import { PathUtil } from "@simplysm/sd-core-node";
14
14
  import * as os from "os";
15
15
  import * as nodeSass from "node-sass";
16
16
  import { createHash } from "crypto";
17
17
  import { SdCliNgModuleFilesGenerator } from "../build-tools/SdCliNgModuleFilesGenerator";
18
18
  import { OptimizeFor } from "@angular/compiler-cli/src/ngtsc/typecheck/api";
19
- import { CompilerHostAdapter, MetadataBundler } from "@angular/compiler-cli/src/metadata/bundler";
19
+ import { ModuleMetadata } from "@angular/compiler-cli/src/metadata/schema";
20
20
 
21
21
  export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
22
22
  protected _ngProgram?: NgtscProgram;
@@ -29,20 +29,10 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
29
29
 
30
30
  public constructor(public rootPath: string,
31
31
  public tsconfigFilePath: string,
32
- ignoreProcesses: ("emit" | "check" | "lint" | "genIndex" | "genNgModule")[],
32
+ skipProcesses: ("emit" | "check" | "lint" | "genIndex" | "genNgModule")[],
33
33
  public autoIndexConfig: ISdAutoIndexConfig | undefined) {
34
- super(rootPath, tsconfigFilePath, ignoreProcesses as ("emit" | "check" | "lint" | "genIndex")[], autoIndexConfig);
35
- this.ignoreProcesses = ignoreProcesses;
36
-
37
- const tsconfig: ITsconfig = FsUtil.readJson(this.tsconfigFilePath);
38
- this._parsedTsconfig = {
39
- ...this._parsedTsconfig,
40
- options: {
41
- baseUrl: path.dirname(this.tsconfigFilePath),
42
- ...this._parsedTsconfig.options,
43
- ...tsconfig.angularCompilerOptions
44
- }
45
- };
34
+ super(rootPath, tsconfigFilePath, skipProcesses as ("emit" | "check" | "lint" | "genIndex")[], autoIndexConfig);
35
+ this.skipProcesses = skipProcesses;
46
36
  }
47
37
 
48
38
  protected override async _runProgramAsync(dirtyFilePaths: string[]): Promise<ISdPackageBuildResult[]> {
@@ -53,7 +43,7 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
53
43
 
54
44
  const diagnostics: ts.Diagnostic[] = [];
55
45
 
56
- if (!this.ignoreProcesses.includes("check")) {
46
+ if (!this.skipProcesses.includes("check")) {
57
47
  diagnostics.push(
58
48
  ...this._ngCompiler.getOptionDiagnostics(),
59
49
  ...this._builder.getOptionsDiagnostics(),
@@ -62,9 +52,10 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
62
52
 
63
53
  await this._ngCompiler.analyzeAsync();
64
54
 
65
- for (const filePath of dirtyFilePaths) {
66
- const sourceFile = this._builder.getSourceFile(filePath);
67
- if (!sourceFile) continue;
55
+ for (const sourceFile of this._builder.getSourceFiles()) {
56
+ /*for (const filePath of dirtyFilePaths) {
57
+ const sourceFile = this._builder.getSourceFile(filePath);
58
+ if (!sourceFile) continue;*/
68
59
 
69
60
  if (this._ngCompiler.ignoreForDiagnostics.has(sourceFile)) continue;
70
61
  if (sourceFile.isDeclarationFile) continue;
@@ -77,7 +68,7 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
77
68
  }
78
69
  }
79
70
 
80
- if (!this.ignoreProcesses.includes("emit")) {
71
+ if (!this.skipProcesses.includes("emit")) {
81
72
  const transformers = this._ngCompiler.prepareEmit().transformers;
82
73
 
83
74
  for (const filePath of dirtyFilePaths) {
@@ -87,11 +78,21 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
87
78
  if (sourceFile.isDeclarationFile) continue;
88
79
 
89
80
  this._builder.emit(sourceFile, undefined, undefined, undefined, transformers);
81
+
82
+ // TODO: sd-metadata를 ModuleMetadata로 만들게 아니고, 아예 IAotModuleDefMetadata형식으로 만들어지게 해야함
83
+ if (this._program!.getCompilerOptions().declaration) {
84
+ if (sourceFile.fileName.endsWith(".ts") && !sourceFile.fileName.endsWith(".d.ts")) {
85
+ const metadata = this._getMetadata(sourceFile);
86
+ if (metadata) {
87
+ this._writeMetadataFile(sourceFile, metadata);
88
+ }
89
+ }
90
+ }
90
91
  }
91
92
 
92
- if (this._parsedTsconfig.options.declaration) {
93
+ /*if (this._parsedTsconfig.options.declaration) {
93
94
  this._writeMetadataBundles();
94
- }
95
+ }*/
95
96
  }
96
97
 
97
98
  const result = diagnostics.map((item) => SdTsDiagnosticUtil.convertDiagnosticsToResult(item)).filterExists();
@@ -101,7 +102,23 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
101
102
  return result;
102
103
  }
103
104
 
104
- private _writeMetadataBundles(): void {
105
+ private _writeMetadataFile(sourceFile: ts.SourceFile, metadata: ModuleMetadata): void {
106
+ const metadataText = JSON.stringify({
107
+ ...metadata,
108
+ importAs: this.npmConfig.name
109
+ });
110
+ const outFileName = path.resolve(
111
+ this._program!.getCompilerOptions().declarationDir!,
112
+ path.relative(path.resolve(this.rootPath, "src"), sourceFile.fileName)
113
+ ).replace(/\.ts$/, ".sd-metadata.json");
114
+ this._cacheCompilerHost!.writeFile(outFileName, metadataText, false, undefined, [sourceFile]);
115
+ }
116
+
117
+ private _getMetadata(sourceFile: ts.SourceFile): ModuleMetadata | undefined {
118
+ return new MetadataCollector().getMetadata(sourceFile, true);
119
+ }
120
+
121
+ /*private _writeMetadataBundles(): void {
105
122
  for (const rootFilePath of this._parsedTsconfig.fileNames) {
106
123
  const metadata = new MetadataBundler(
107
124
  rootFilePath.replace(/\.ts$/, ""),
@@ -120,17 +137,19 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
120
137
  if (!fileCache?.sourceFile) throw new NeverEntryError();
121
138
  this._cacheCompilerHost!.writeFile(outFileName, JSON.stringify(metadata), false, undefined, [fileCache.sourceFile]);
122
139
  }
123
- }
140
+ }*/
124
141
 
125
142
  public override async reloadProgramAsync(watch: boolean): Promise<string[]> {
126
143
  this._logger.debug("프로그램 리로드");
127
144
 
128
- this._moduleResolutionCache = ts.createModuleResolutionCache(this.rootPath, (s) => s, this._parsedTsconfig.options);
129
- this._cacheCompilerHost = await this._createCacheCompilerHostAsync(this._parsedTsconfig, this._moduleResolutionCache);
145
+ const parsedTsconfig = ts.parseJsonConfigFileContent(this._tsconfig, ts.sys, this.rootPath, this._tsconfig.angularCompilerOptions);
146
+
147
+ this._moduleResolutionCache = ts.createModuleResolutionCache(this.rootPath, (s) => s, parsedTsconfig.options);
148
+ this._cacheCompilerHost = await this._createCacheCompilerHostAsync(parsedTsconfig, this._moduleResolutionCache);
130
149
 
131
150
  this._ngProgram = new NgtscProgram(
132
- this._parsedTsconfig.fileNames,
133
- this._parsedTsconfig.options,
151
+ parsedTsconfig.fileNames,
152
+ parsedTsconfig.options,
134
153
  this._cacheCompilerHost,
135
154
  this._ngProgram
136
155
  );
@@ -152,15 +171,27 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
152
171
  };
153
172
 
154
173
  if (watch) {
155
- const builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
156
- this._program,
157
- this._cacheCompilerHost,
158
- this._builder as ts.EmitAndSemanticDiagnosticsBuilderProgram
159
- );
160
- this._builder = builder;
174
+ if (this.skipProcesses.includes("emit")) {
175
+ this._builder = ts.createSemanticDiagnosticsBuilderProgram(
176
+ this._program,
177
+ this._cacheCompilerHost,
178
+ this._builder as ts.SemanticDiagnosticsBuilderProgram
179
+ );
180
+ }
181
+ else {
182
+ this._builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(
183
+ this._program,
184
+ this._cacheCompilerHost,
185
+ this._builder as ts.EmitAndSemanticDiagnosticsBuilderProgram
186
+ );
187
+ }
188
+ const builder = this._builder as ts.SemanticDiagnosticsBuilderProgram;
161
189
 
162
- const affectedFilePaths: string[] = [];
190
+ let seq = 0;
191
+ const affectedFilePathSet = new Set<string>();
163
192
  while (true) {
193
+ const affectedFilePaths: string[] = [];
194
+ this._logger.debug(`프로그램 리로드 > 변경파일 목록구성: [SEQ: ${++seq}]`);
164
195
  const result = builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sourceFile) => {
165
196
  if (this._ngCompiler!.ignoreForDiagnostics.has(sourceFile) && sourceFile.fileName.endsWith(".ngtypecheck.ts")) {
166
197
  const originalFilename = sourceFile.fileName.slice(0, -15) + ".ts";
@@ -173,14 +204,20 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
173
204
  return false;
174
205
  });
175
206
 
176
- if (!result) break;
177
-
178
- if ("fileName" in result.affected) {
207
+ if (result && "fileName" in result.affected) {
179
208
  affectedFilePaths.push(result.affected.fileName);
180
209
  }
210
+
211
+ affectedFilePaths.distinctThis();
212
+
213
+ this._logger.debug(`프로그램 리로드 > 변경파일 목록구성: [SEQ: ${seq}, SIZE:${affectedFilePathSet.size}]\n` + affectedFilePaths.map((item) => "- " + item).join("\n"));
214
+
215
+ affectedFilePathSet.adds(...affectedFilePaths.distinct());
216
+
217
+ if (!result) break;
181
218
  }
182
219
 
183
- const result = affectedFilePaths.distinct();
220
+ const result = Array.from(affectedFilePathSet.values());
184
221
 
185
222
  this._logger.debug("프로그램 리로드", result);
186
223
 
@@ -234,7 +271,7 @@ export class SdCliNgLibraryBuilder extends SdCliTypescriptBuilder {
234
271
  this._logger.debug("Angular Module, RoutingModule 생성", dirtyFilePaths);
235
272
 
236
273
  const result: ITsGenResult = { dirtyFilePaths: [], result: [] };
237
- if (this.ignoreProcesses.includes("genNgModule")) return result;
274
+ if (this.skipProcesses.includes("genNgModule")) return result;
238
275
 
239
276
  const reloadResult = await this._moduleFilesGenerator.reloadSourceFilesAsync(
240
277
  dirtyFilePaths,