@simplysm/sd-cli 6.0.27 → 6.0.36

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 (78) 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 +98 -57
  4. package/dist-node/build-tools/SdCliNgModuleFilesGenerator.js.map +1 -1
  5. package/dist-node/build-tools/metadata/SdAotMetadataReader.js +16 -12
  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 +38 -34
  16. package/dist-node/builders/SdCliNgLibraryBuilder.js.map +1 -1
  17. package/dist-node/builders/SdCliServerBuilder.js +46 -45
  18. package/dist-node/builders/SdCliServerBuilder.js.map +1 -1
  19. package/dist-node/builders/SdCliTypescriptBuilder.js +65 -60
  20. package/dist-node/builders/SdCliTypescriptBuilder.js.map +1 -1
  21. package/dist-node/entry-points/SdCliLocalUpdater.js +30 -29
  22. package/dist-node/entry-points/SdCliLocalUpdater.js.map +1 -1
  23. package/dist-node/entry-points/SdCliProject.js +10 -16
  24. package/dist-node/entry-points/SdCliProject.js.map +1 -1
  25. package/dist-node/packages/SdCliClientPackage.js +6 -4
  26. package/dist-node/packages/SdCliClientPackage.js.map +1 -1
  27. package/dist-node/packages/SdCliLibraryPackage.js +5 -3
  28. package/dist-node/packages/SdCliLibraryPackage.js.map +1 -1
  29. package/dist-node/packages/SdCliServerPackage.js +4 -3
  30. package/dist-node/packages/SdCliServerPackage.js.map +1 -1
  31. package/dist-node/utils/SdProjectConfigUtil.js +1 -1
  32. package/dist-node/utils/SdProjectConfigUtil.js.map +1 -1
  33. package/dist-node/utils/SdWebpackUtil.js +33 -13
  34. package/dist-node/utils/SdWebpackUtil.js.map +1 -1
  35. package/dist-node/workers/client-ng-gen-worker.js +54 -0
  36. package/dist-node/workers/client-ng-gen-worker.js.map +1 -0
  37. package/dist-node/workers/lib-build-worker.js +7 -6
  38. package/dist-node/workers/lib-build-worker.js.map +1 -1
  39. package/dist-types/build-tools/metadata/SdIvyMetadataReader.d.ts +1 -0
  40. package/dist-types/build-tools/metadata/SdMetadataError.d.ts +6 -0
  41. package/dist-types/build-tools/metadata/SdMyMetadataReader.d.ts +1 -0
  42. package/dist-types/builders/SdCliNgClientBuilder.d.ts +6 -2
  43. package/dist-types/builders/SdCliNgLibraryBuilder.d.ts +1 -1
  44. package/dist-types/builders/SdCliServerBuilder.d.ts +2 -1
  45. package/dist-types/builders/SdCliTypescriptBuilder.d.ts +5 -5
  46. package/dist-types/commons.d.ts +4 -1
  47. package/dist-types/entry-points/SdCliLocalUpdater.d.ts +1 -1
  48. package/dist-types/entry-points/SdCliProject.d.ts +2 -0
  49. package/dist-types/packages/SdCliClientPackage.d.ts +2 -1
  50. package/dist-types/packages/SdCliLibraryPackage.d.ts +2 -1
  51. package/dist-types/packages/SdCliServerPackage.d.ts +2 -1
  52. package/dist-types/utils/SdWebpackUtil.d.ts +1 -1
  53. package/dist-types/workers/client-ng-gen-worker.d.ts +1 -0
  54. package/package.json +7 -7
  55. package/schema/schema.json +185 -122
  56. package/sd-tsconfig.node.json +2 -1
  57. package/src/bin/sd-cli.ts +19 -4
  58. package/src/build-tools/SdCliNgModuleFilesGenerator.ts +114 -70
  59. package/src/build-tools/metadata/SdAotMetadataReader.ts +8 -2
  60. package/src/build-tools/metadata/SdIvyMetadataReader.ts +27 -4
  61. package/src/build-tools/metadata/SdMetadataError.ts +7 -0
  62. package/src/build-tools/metadata/SdMyMetadataReader.ts +25 -3
  63. package/src/builders/SdCliNgClientBuilder.ts +123 -66
  64. package/src/builders/SdCliNgLibraryBuilder.ts +79 -39
  65. package/src/builders/SdCliServerBuilder.ts +61 -44
  66. package/src/builders/SdCliTypescriptBuilder.ts +92 -73
  67. package/src/commons.ts +3 -2
  68. package/src/entry-points/SdCliLocalUpdater.ts +40 -33
  69. package/src/entry-points/SdCliProject.ts +14 -13
  70. package/src/packages/SdCliClientPackage.ts +5 -3
  71. package/src/packages/SdCliLibraryPackage.ts +4 -2
  72. package/src/packages/SdCliServerPackage.ts +4 -3
  73. package/src/utils/SdCliFileCrypto.ts +1 -1
  74. package/src/utils/SdProjectConfigUtil.ts +1 -1
  75. package/src/utils/SdWebpackUtil.ts +42 -22
  76. package/src/workers/client-ng-gen-worker.ts +60 -0
  77. package/src/workers/lib-build-worker.ts +7 -6
  78. package/tsconfig.json +2 -1
@@ -4,6 +4,7 @@ import {
4
4
  isMetadataGlobalReferenceExpression,
5
5
  isMetadataImportedSymbolReferenceExpression,
6
6
  isMetadataSymbolicCallExpression,
7
+ isMetadataSymbolicIfExpression,
7
8
  isMetadataSymbolicReferenceExpression,
8
9
  MetadataEntry,
9
10
  MetadataObject,
@@ -17,7 +18,9 @@ export class SdAotMetadataReader {
17
18
  }
18
19
 
19
20
  public getMetadatas(): IAotModuleDefMetadata {
20
- if (StringUtil.isNullOrEmpty(this._metadataRoot.importAs)) throw new NeverEntryError();
21
+ if (StringUtil.isNullOrEmpty(this._metadataRoot.importAs)) {
22
+ throw new NeverEntryError();
23
+ }
21
24
 
22
25
  const result: IAotModuleDefMetadata = {
23
26
  moduleName: this._metadataRoot.importAs,
@@ -186,7 +189,7 @@ export class SdAotMetadataReader {
186
189
  if (dec.arguments && dec.arguments.length !== 0) {
187
190
  const paramObj = dec.arguments[0] as MetadataObject;
188
191
 
189
- if (paramObj.providedIn !== undefined) {
192
+ if (paramObj.providedIn != null) {
190
193
  if (typeof paramObj.providedIn !== "string") throw new NeverEntryError();
191
194
  result.providedIn = paramObj.providedIn;
192
195
  }
@@ -255,6 +258,9 @@ export class SdAotMetadataReader {
255
258
  );
256
259
  result.push(...subProvRefTargets);
257
260
  }
261
+ else if (isMetadataSymbolicIfExpression(refTarget.metadata)) {
262
+ result.push(...this._getProviderReferenceTargets([refTarget.metadata.thenExpression, refTarget.metadata.elseExpression]));
263
+ }
258
264
  else {
259
265
  throw new NeverEntryError();
260
266
  }
@@ -7,6 +7,8 @@ import { Reference } from "@angular/compiler-cli/src/ngtsc/imports";
7
7
  import { NgtscProgram } from "@angular/compiler-cli";
8
8
  import * as path from "path";
9
9
  import { INpmConfig } from "../../commons";
10
+ import { IMyModuleImport } from "./SdMyMetadataReader";
11
+ import { SdMetadataError } from "./SdMetadataError";
10
12
 
11
13
  export class SdIvyMetadataReader {
12
14
  private readonly _typeChecker: ts.TypeChecker;
@@ -76,7 +78,7 @@ export class SdIvyMetadataReader {
76
78
  return result;
77
79
  }
78
80
 
79
- private _getAliasedModuleImportInfo(identifier: ts.Identifier): IIvyModuleImport {
81
+ private _getAliasedModuleImportInfo(identifier: ts.Identifier): IMyModuleImport {
80
82
  const moduleSymbol = this._typeChecker.getSymbolAtLocation(identifier);
81
83
  if (!moduleSymbol) throw new NeverEntryError();
82
84
  if (moduleSymbol.valueDeclaration) {
@@ -86,9 +88,18 @@ export class SdIvyMetadataReader {
86
88
  else {
87
89
  const aliasedTargetSymbol = this._typeChecker.getAliasedSymbol(moduleSymbol);
88
90
  const declarations = aliasedTargetSymbol.getDeclarations();
89
- if (!declarations) throw new NeverEntryError();
90
- const moduleFilePaths = declarations.map((item) => PathUtil.posix(item.getSourceFile().fileName)).distinct();
91
- if (moduleFilePaths.length !== 1) throw new NeverEntryError();
91
+ if (!declarations || declarations.length < 1) {
92
+ throw new SdMetadataError(this._sourceFile.fileName, `'${identifier.text}'를 찾을 수 없습니다.`);
93
+ }
94
+ const moduleFilePaths = declarations
95
+ .filter((item) => (
96
+ this._hasParentsOrMe(item, (item1) => Boolean(item1.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword)))
97
+ ))
98
+ .map((item) => PathUtil.posix(item.getSourceFile().fileName))
99
+ .distinct();
100
+ if (moduleFilePaths.length !== 1) {
101
+ throw new SdMetadataError(this._sourceFile.fileName, `'${identifier.text}'의 경로가 중복되었습니다.\n${moduleFilePaths.join("\n")}`);
102
+ }
92
103
 
93
104
  const moduleFilePath = moduleFilePaths[0];
94
105
 
@@ -96,6 +107,18 @@ export class SdIvyMetadataReader {
96
107
  }
97
108
  }
98
109
 
110
+ private _hasParentsOrMe(node: ts.Node, fn: (node1: ts.Node) => boolean): boolean {
111
+ let currNode = node as ts.Node | undefined;
112
+ while (true) {
113
+ if (!currNode) return false;
114
+
115
+ const result = fn(currNode);
116
+ if (result) return true;
117
+
118
+ currNode = currNode.parent as ts.Node | undefined;
119
+ }
120
+ }
121
+
99
122
  private getPackageName(): string {
100
123
  let cursorDirPath = path.dirname(this._sourceFile.fileName);
101
124
  while (true) {
@@ -0,0 +1,7 @@
1
+ import { SdError } from "@simplysm/sd-core-common";
2
+
3
+ export class SdMetadataError extends SdError {
4
+ public constructor(public fileName: string, public message: string) {
5
+ super(message);
6
+ }
7
+ }
@@ -1,6 +1,7 @@
1
1
  import * as ts from "typescript";
2
2
  import { NeverEntryError } from "@simplysm/sd-core-common";
3
3
  import { PathUtil } from "@simplysm/sd-core-node";
4
+ import { SdMetadataError } from "./SdMetadataError";
4
5
 
5
6
  export class SdMyMetadataReader {
6
7
  private readonly _typeChecker: ts.TypeChecker;
@@ -150,9 +151,18 @@ export class SdMyMetadataReader {
150
151
  else {
151
152
  const aliasedTargetSymbol = this._typeChecker.getAliasedSymbol(moduleSymbol);
152
153
  const declarations = aliasedTargetSymbol.getDeclarations();
153
- if (!declarations) throw new NeverEntryError();
154
- const moduleFilePaths = declarations.map((item) => PathUtil.posix(item.getSourceFile().fileName)).distinct();
155
- if (moduleFilePaths.length !== 1) throw new NeverEntryError();
154
+ if (!declarations || declarations.length < 1) {
155
+ throw new SdMetadataError(this._sourceFile.fileName, `'${identifier.text}'를 찾을 수 없습니다.`);
156
+ }
157
+ const moduleFilePaths = declarations
158
+ .filter((item) => (
159
+ this._hasParentsOrMe(item, (item1) => Boolean(item1.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword)))
160
+ ))
161
+ .map((item) => PathUtil.posix(item.getSourceFile().fileName))
162
+ .distinct();
163
+ if (moduleFilePaths.length !== 1) {
164
+ throw new SdMetadataError(this._sourceFile.fileName, `'${identifier.text}'의 경로가 중복되었습니다.\n${moduleFilePaths.join("\n")}`);
165
+ }
156
166
 
157
167
  const moduleFilePath = moduleFilePaths[0];
158
168
 
@@ -160,6 +170,18 @@ export class SdMyMetadataReader {
160
170
  }
161
171
  }
162
172
 
173
+ private _hasParentsOrMe(node: ts.Node, fn: (node1: ts.Node) => boolean): boolean {
174
+ let currNode = node as ts.Node | undefined;
175
+ while (true) {
176
+ if (!currNode) return false;
177
+
178
+ const result = fn(currNode);
179
+ if (result) return true;
180
+
181
+ currNode = currNode.parent as ts.Node | undefined;
182
+ }
183
+ }
184
+
163
185
  private _getNgModuleDecoratorParam(decExp: ts.CallExpression): { exports: IMyModuleImport[]; providers: IMyModuleImport[] } {
164
186
  const result: { exports: IMyModuleImport[]; providers: IMyModuleImport[] } = {
165
187
  exports: [],
@@ -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
  }