@simplysm/sd-cli 12.8.22 → 12.9.2

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 (96) hide show
  1. package/dist/entry/sd-cli-ai-command.js +2 -1
  2. package/dist/entry/sd-cli-ai-command.js.map +1 -1
  3. package/dist/entry/sd-cli-cordova.d.ts +1 -1
  4. package/dist/entry/sd-cli-cordova.js +1 -1
  5. package/dist/entry/sd-cli-cordova.js.map +1 -1
  6. package/dist/entry/sd-cli-electron.d.ts +6 -6
  7. package/dist/entry/sd-cli-electron.js +15 -9
  8. package/dist/entry/sd-cli-electron.js.map +1 -1
  9. package/dist/entry/sd-cli-local-update.d.ts +5 -5
  10. package/dist/entry/sd-cli-local-update.js +8 -12
  11. package/dist/entry/sd-cli-local-update.js.map +1 -1
  12. package/dist/entry/sd-cli-project.d.ts +11 -11
  13. package/dist/entry/sd-cli-project.js +11 -14
  14. package/dist/entry/sd-cli-project.js.map +1 -1
  15. package/dist/entry/utils/loadProjConfAsync.d.ts +5 -0
  16. package/dist/entry/utils/loadProjConfAsync.js +8 -0
  17. package/dist/entry/utils/loadProjConfAsync.js.map +1 -0
  18. package/dist/pkg-builders/client/sd-client.build-runner.js +1 -1
  19. package/dist/pkg-builders/client/sd-client.build-runner.js.map +1 -1
  20. package/dist/pkg-builders/client/sd-ng.bundler-context.d.ts +6 -5
  21. package/dist/pkg-builders/client/sd-ng.bundler-context.js +6 -6
  22. package/dist/pkg-builders/client/sd-ng.bundler-context.js.map +1 -1
  23. package/dist/pkg-builders/client/sd-ng.bundler.d.ts +14 -13
  24. package/dist/pkg-builders/client/sd-ng.bundler.js +4 -1
  25. package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
  26. package/dist/pkg-builders/client/sd-ng.plugin-creator.js +4 -88
  27. package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
  28. package/dist/pkg-builders/lib/sd-js-lib.build-runner.js.map +1 -1
  29. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.d.ts +1 -1
  30. package/dist/pkg-builders/lib/sd-ts-lib.build-runner.js.map +1 -1
  31. package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
  32. package/dist/pkg-builders/sd-multi.build-runner.d.ts +4 -0
  33. package/dist/pkg-builders/sd-multi.build-runner.js +33 -25
  34. package/dist/pkg-builders/sd-multi.build-runner.js.map +1 -1
  35. package/dist/pkg-builders/server/sd-server.build-runner.js.map +1 -1
  36. package/dist/pkg-builders/server/sd-server.bundler.d.ts +6 -2
  37. package/dist/pkg-builders/server/sd-server.bundler.js +18 -19
  38. package/dist/pkg-builders/server/sd-server.bundler.js.map +1 -1
  39. package/dist/sd-cli/vitest.config.d.ts +2 -0
  40. package/dist/sd-cli/vitest.config.js +15 -0
  41. package/dist/sd-cli/vitest.config.js.map +1 -0
  42. package/dist/sd-cli.js +7 -36
  43. package/dist/sd-cli.js.map +1 -1
  44. package/dist/ts-compiler/sd-dependency-analyzer.d.ts +8 -0
  45. package/dist/ts-compiler/sd-dependency-analyzer.js +244 -0
  46. package/dist/ts-compiler/sd-dependency-analyzer.js.map +1 -0
  47. package/dist/ts-compiler/sd-dependency-cache.d.ts +27 -0
  48. package/dist/ts-compiler/sd-dependency-cache.js +232 -0
  49. package/dist/ts-compiler/sd-dependency-cache.js.map +1 -0
  50. package/dist/ts-compiler/sd-ts-compiler.d.ts +8 -10
  51. package/dist/ts-compiler/sd-ts-compiler.js +106 -229
  52. package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
  53. package/dist/types/worker.types.d.ts +19 -0
  54. package/dist/utils/sd-cli-performance-time.d.ts +2 -1
  55. package/dist/utils/sd-cli-performance-time.js +9 -9
  56. package/dist/utils/sd-cli-performance-time.js.map +1 -1
  57. package/dist/workers/style-bundler.worker.d.ts +1 -0
  58. package/dist/workers/style-bundler.worker.js +56 -0
  59. package/dist/workers/style-bundler.worker.js.map +1 -0
  60. package/package.json +10 -10
  61. package/src/entry/sd-cli-ai-command.ts +2 -1
  62. package/src/entry/sd-cli-cordova.ts +5 -5
  63. package/src/entry/sd-cli-electron.ts +54 -23
  64. package/src/entry/sd-cli-local-update.ts +14 -29
  65. package/src/entry/sd-cli-project.ts +24 -41
  66. package/src/entry/utils/loadProjConfAsync.ts +12 -0
  67. package/src/pkg-builders/client/sd-client.build-runner.ts +7 -7
  68. package/src/pkg-builders/client/sd-ng.bundler-context.ts +15 -12
  69. package/src/pkg-builders/client/sd-ng.bundler.ts +21 -17
  70. package/src/pkg-builders/client/sd-ng.plugin-creator.ts +4 -93
  71. package/src/pkg-builders/lib/sd-js-lib.build-runner.ts +6 -6
  72. package/src/pkg-builders/lib/sd-ts-lib.build-runner.ts +7 -7
  73. package/src/pkg-builders/lib/sd-ts-lib.builder.ts +1 -1
  74. package/src/pkg-builders/sd-multi.build-runner.ts +54 -39
  75. package/src/pkg-builders/server/sd-server.build-runner.ts +6 -6
  76. package/src/pkg-builders/server/sd-server.bundler.ts +26 -28
  77. package/src/sd-cli.ts +7 -36
  78. package/src/ts-compiler/sd-dependency-analyzer.ts +312 -0
  79. package/src/ts-compiler/sd-dependency-cache.ts +328 -0
  80. package/src/ts-compiler/sd-ts-compiler.ts +165 -303
  81. package/src/types/worker.types.ts +17 -0
  82. package/src/utils/sd-cli-performance-time.ts +9 -9
  83. package/src/workers/style-bundler.worker.ts +70 -0
  84. package/tests/deps/sd-dependency-analyzer.spec.ts +272 -0
  85. package/tests/deps/sd-dependency-cache.spec.ts +144 -0
  86. package/tsconfig.json +1 -1
  87. package/tsconfig.test.json +8 -0
  88. package/vitest.config.ts +15 -0
  89. package/dist/index.d.ts +0 -34
  90. package/dist/index.js +0 -35
  91. package/dist/index.js.map +0 -1
  92. package/dist/ts-compiler/sd-ts-dependency-analyzer.d.ts +0 -6
  93. package/dist/ts-compiler/sd-ts-dependency-analyzer.js +0 -141
  94. package/dist/ts-compiler/sd-ts-dependency-analyzer.js.map +0 -1
  95. package/src/index.ts +0 -34
  96. package/src/ts-compiler/sd-ts-dependency-analyzer.ts +0 -185
@@ -1,14 +1,9 @@
1
1
  import ts from "typescript";
2
2
  import path from "path";
3
- import { FsUtils, PathUtils, SdLogger, TNormPath } from "@simplysm/sd-core-node";
3
+ import { FsUtils, PathUtils, SdLogger, SdWorker, TNormPath } from "@simplysm/sd-core-node";
4
4
  import { StringUtils } from "@simplysm/sd-core-common";
5
5
  import { NgtscProgram, OptimizeFor } from "@angular/compiler-cli";
6
- import {
7
- ComponentStylesheetBundler,
8
- } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
9
6
  import { AngularCompilerHost } from "@angular/build/src/tools/angular/angular-host";
10
- import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
11
- import browserslist from "browserslist";
12
7
  import {
13
8
  replaceBootstrap,
14
9
  } from "@angular/build/src/tools/angular/transformers/jit-bootstrap-transformer";
@@ -19,20 +14,26 @@ import {
19
14
  SdTsCompilerOptions,
20
15
  TStylesheetBundlingResult,
21
16
  } from "../types/ts-compiler.types";
22
- import { ISdBuildMessage } from "../types/build.types";
23
17
  import {
24
18
  createWorkerTransformer,
25
19
  } from "@angular/build/src/tools/angular/transformers/web-worker-transformer";
26
20
  import { ESLint } from "eslint";
27
- import { SdTsDependencyAnalyzer } from "./sd-ts-dependency-analyzer";
21
+ import { ISdAffectedFileTreeNode, SdDependencyCache } from "./sd-dependency-cache";
22
+ import { SdDependencyAnalyzer } from "./sd-dependency-analyzer";
23
+ import { TStyleBundlerWorkerType } from "../types/worker.types";
28
24
 
29
25
  export class SdTsCompiler {
30
26
  private _logger = SdLogger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
31
27
 
32
28
  private _isForAngular: boolean;
33
29
 
34
- private _allDepCacheMap = new Map<TNormPath, Set<TNormPath>>();
35
- private _revDepCacheMap = new Map<TNormPath, Set<TNormPath>>();
30
+ private _stylesheetBundlingWorker?: SdWorker<TStyleBundlerWorkerType>;
31
+
32
+ private _ngProgram: NgtscProgram | undefined;
33
+ private _program: ts.Program | undefined;
34
+
35
+ // 빌드정보 캐싱
36
+ private _depCache = new SdDependencyCache();
36
37
  private _sourceFileCacheMap = new Map<TNormPath, ts.SourceFile>();
37
38
  private _emittedFilesCacheMap = new Map<
38
39
  TNormPath,
@@ -42,15 +43,7 @@ export class SdTsCompiler {
42
43
  }[]
43
44
  >();
44
45
 
45
- private _stylesheetBundler: ComponentStylesheetBundler | undefined;
46
-
47
- private _ngProgram: NgtscProgram | undefined;
48
- private _program: ts.Program | undefined;
49
-
50
- private _modifiedFileSet = new Set<TNormPath>();
51
- private _affectedFileSet = new Set<TNormPath>();
52
-
53
- private _watchFileSet = new Set<TNormPath>();
46
+ // 빌드결과 캐싱
54
47
  private _stylesheetBundlingResultMap = new Map<TNormPath, TStylesheetBundlingResult>();
55
48
 
56
49
  private _perf!: SdCliPerformanceTimer;
@@ -61,46 +54,9 @@ export class SdTsCompiler {
61
54
  const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
62
55
  const tsconfig = FsUtils.readJson(tsconfigPath);
63
56
  this._isForAngular = Boolean(tsconfig.angularCompilerOptions);
64
-
65
- if (this._isForAngular) {
66
- //-- stylesheetBundler
67
- this._stylesheetBundler = new ComponentStylesheetBundler(
68
- {
69
- workspaceRoot: this._opt.pkgPath,
70
- optimization: !this._opt.isDevMode,
71
- inlineFonts: true,
72
- preserveSymlinks: false,
73
- sourcemap: this._opt.isDevMode ? "inline" : false,
74
- outputNames: { bundles: "[name]", media: "media/[name]" },
75
- includePaths: [],
76
- externalDependencies: [],
77
- target: transformSupportedBrowsersToTargets(browserslist(["Chrome > 78"])),
78
- postcssConfiguration: {
79
- plugins: [["css-has-pseudo"]],
80
- },
81
- tailwindConfiguration: undefined,
82
- cacheOptions: {
83
- enabled: true,
84
- path: ".cache/angular",
85
- basePath: ".cache",
86
- },
87
- },
88
- "scss",
89
- this._opt.isDevMode,
90
- );
91
- }
92
- }
93
-
94
- private _parseTsConfig(): ITsConfigInfo {
95
- const config = this._loadTsConfig();
96
- const compilerHost = this._createCompilerHost(config.options);
97
- return {
98
- ...config,
99
- compilerHost,
100
- };
101
57
  }
102
58
 
103
- private _loadTsConfig() {
59
+ private _parseTsConfig() {
104
60
  const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
105
61
  const tsconfig = FsUtils.readJson(tsconfigPath);
106
62
  const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._opt.pkgPath, {
@@ -120,7 +76,10 @@ export class SdTsCompiler {
120
76
  };
121
77
  }
122
78
 
123
- private _createCompilerHost(compilerOptions: ts.CompilerOptions) {
79
+ private _createCompilerHost(
80
+ compilerOptions: ts.CompilerOptions,
81
+ modifiedFileSet: Set<TNormPath>,
82
+ ) {
124
83
  const compilerHost = ts.createCompilerHost(compilerOptions);
125
84
 
126
85
  const baseGetSourceFile = compilerHost.getSourceFile;
@@ -156,12 +115,6 @@ export class SdTsCompiler {
156
115
  return sf;
157
116
  };
158
117
 
159
- const baseReadFile = compilerHost.readFile;
160
- compilerHost.readFile = (fileName) => {
161
- this._watchFileSet.add(PathUtils.norm(fileName));
162
- return baseReadFile.call(compilerHost, fileName);
163
- };
164
-
165
118
  if (this._isForAngular) {
166
119
  (compilerHost as AngularCompilerHost).readResource = (fileName: string) => {
167
120
  return compilerHost.readFile(fileName) ?? "";
@@ -191,13 +144,30 @@ export class SdTsCompiler {
191
144
  };
192
145
 
193
146
  (compilerHost as AngularCompilerHost).getModifiedResourceFiles = () => {
194
- return new Set(Array.from(this._modifiedFileSet).map((item) => PathUtils.posix(item)));
147
+ return new Set(Array.from(modifiedFileSet).map((item) => PathUtils.posix(item)));
195
148
  };
196
149
  }
197
150
 
198
151
  return compilerHost;
199
152
  }
200
153
 
154
+ private async _getOrCreateStyleBundleWorkerAsync() {
155
+ if (this._stylesheetBundlingWorker) {
156
+ return this._stylesheetBundlingWorker;
157
+ }
158
+
159
+ this._stylesheetBundlingWorker = new SdWorker<TStyleBundlerWorkerType>(
160
+ import.meta.resolve("../workers/style-bundler.worker"),
161
+ );
162
+
163
+ await this._stylesheetBundlingWorker.run(
164
+ "prepare",
165
+ [this._opt.pkgPath, this._opt.isDevMode],
166
+ );
167
+
168
+ return this._stylesheetBundlingWorker;
169
+ }
170
+
201
171
  private async _bundleStylesheetAsync(
202
172
  data: string,
203
173
  containingFile: TNormPath,
@@ -216,24 +186,12 @@ export class SdTsCompiler {
216
186
  }
217
187
 
218
188
  try {
219
- const result =
220
- resourceFile != null
221
- ? await this._stylesheetBundler!.bundleFile(resourceFile)
222
- : await this._stylesheetBundler!.bundleInline(data, containingFile, "scss");
223
-
224
- if (result.referencedFiles) {
225
- for (const referencedFile of result.referencedFiles) {
226
- const depCacheSet = this._revDepCacheMap.getOrCreate(
227
- PathUtils.norm(referencedFile),
228
- new Set<TNormPath>(),
229
- );
230
- depCacheSet.add(fileNPath);
231
- }
189
+ const worker = this._stylesheetBundlingWorker!;
190
+ const result = await worker.run("bundle", [data, containingFile, resourceFile]);
232
191
 
233
- this._watchFileSet.adds(
234
- ...Array.from(result.referencedFiles.values())
235
- .map((item) => PathUtils.norm(item)),
236
- );
192
+ for (const referencedFile of result.referencedFiles ?? []) {
193
+ // 참조하는 파일과 참조된 파일 사이의 의존성 관계 추가
194
+ this._depCache.addImport(fileNPath, PathUtils.norm(referencedFile), 0);
237
195
  }
238
196
 
239
197
  this._stylesheetBundlingResultMap.set(fileNPath, result);
@@ -256,123 +214,96 @@ export class SdTsCompiler {
256
214
  });
257
215
  }
258
216
 
259
- public async compileAsync(modifiedFileSet: Set<TNormPath>): Promise<ISdTsCompilerResult> {
217
+ async compileAsync(modifiedFileSet: Set<TNormPath>): Promise<ISdTsCompilerResult> {
260
218
  this._perf = new SdCliPerformanceTimer("esbuild compile");
261
219
 
262
- this._modifiedFileSet = new Set(modifiedFileSet);
263
- this._affectedFileSet = new Set<TNormPath>();
264
-
265
- /*for (const mod of modifiedFileSet) {
266
- const workerImporters = this.#workerRevDependencyCacheMap.get(mod);
267
- if (workerImporters) {
268
- this.#modifiedFileSet.adds(...workerImporters);
269
- } else {
270
- this.#modifiedFileSet.add(mod);
271
- }
272
- }*/
273
-
274
- const tsconf = this._parseTsConfig();
275
-
276
- const prepareResult = await this._prepareAsync(tsconf);
220
+ const prepareResult = await this._prepareAsync(modifiedFileSet);
277
221
 
278
- const [buildResult, lintResults] = await Promise.all([
279
- this._buildAsync(tsconf),
280
- this._lintAsync(),
222
+ const [globalStyleSheet, buildResult, lintResults] = await Promise.all([
223
+ this._buildGlobalStyleAsync(),
224
+ this._build(prepareResult),
225
+ this._lintAsync(prepareResult),
281
226
  ]);
282
227
 
283
- this._debug(`빌드 완료됨`, this._perf.toString());
284
- this._debug(`영향 받은 파일: ${this._affectedFileSet.size}개`);
285
- this._debug(`감시 중인 파일: ${this._watchFileSet.size}개`);
228
+ this._log(`빌드 완료됨`, this._perf.toString());
229
+ this._debug(`영향 받은 파일: ${prepareResult.affectedFileSet.size}개`);
230
+ this._debug(`감시 중인 파일: ${prepareResult.watchFileSet.size}개`);
286
231
 
287
232
  return {
288
233
  messages: [
289
- ...prepareResult.messages,
290
234
  ...SdCliConvertMessageUtils.convertToBuildMessagesFromTsDiag(buildResult.diagnostics),
291
235
  ...SdCliConvertMessageUtils.convertToBuildMessagesFromEslint(lintResults),
292
236
  ],
293
- watchFileSet: this._watchFileSet,
294
- affectedFileSet: this._affectedFileSet,
237
+ affectedFileSet: prepareResult.affectedFileSet,
238
+ watchFileSet: prepareResult.watchFileSet,
295
239
  stylesheetBundlingResultMap: this._stylesheetBundlingResultMap,
296
240
  emittedFilesCacheMap: this._emittedFilesCacheMap,
297
- emitFileSet: buildResult.emitFileSet,
241
+ emitFileSet: new Set([...buildResult.emitFileSet, globalStyleSheet].filterExists()),
298
242
  };
299
243
  }
300
244
 
301
- private async _prepareAsync(tsconf: ITsConfigInfo) {
302
- if (this._modifiedFileSet.size !== 0) {
303
- this._debug(`영향 받은 파일 추적 중... (구 의존성)`);
304
-
305
- this._perf.run("영향 받은 파일 추적", () => {
306
- for (const modifiedFile of this._modifiedFileSet) {
307
- this._affectedFileSet.add(modifiedFile);
245
+ private async _prepareAsync(modifiedFileSet: Set<TNormPath>): Promise<IPrepareResult> {
246
+ const worker = await this._getOrCreateStyleBundleWorkerAsync();
308
247
 
309
- this._affectedFileSet.adds(...(this._revDepCacheMap.get(modifiedFile) ?? []));
310
-
311
- // .d.ts → .js 대응
312
- if (modifiedFile.endsWith(".d.ts")) {
313
- const jsEquivalent = PathUtils.norm(modifiedFile.replace(/\.d\.ts$/, ".js"));
314
- this._affectedFileSet.add(jsEquivalent);
315
- }
316
- }
317
- });
248
+ const tsconfig = this._parseTsConfig();
318
249
 
250
+ if (modifiedFileSet.size !== 0) {
319
251
  this._debug(`캐시 무효화 및 초기화 중...`);
320
252
 
321
- this._perf.run("캐시 무효화 및 초기화", () => {
322
- this._stylesheetBundler?.invalidate(this._affectedFileSet);
253
+ await this._perf.run("캐시 무효화 및 초기화", async () => {
254
+ // 기존 의존성에 의해 영향받는 파일들 계산
255
+ const affectedFileSet = this._depCache.getAffectedFileSet(modifiedFileSet);
323
256
 
324
- const toDeleteSet = new Set<TNormPath>();
257
+ const getTreeText = (node: ISdAffectedFileTreeNode, indent = "") => {
258
+ let result = indent + node.fileNPath + "\n";
259
+ for (const child of node.children) {
260
+ result += getTreeText(child, indent + " ");
261
+ }
325
262
 
326
- // 초기: 명시적으로 수정된 파일들
327
- for (const file of this._affectedFileSet) {
328
- toDeleteSet.add(file);
263
+ return result;
264
+ };
329
265
 
330
- // 역방향으로 영향을 받는 파일들도 포함
331
- const dependents = this._revDepCacheMap.get(file);
332
- if (dependents) {
333
- for (const dep of dependents) {
334
- toDeleteSet.add(dep);
335
- }
336
- }
337
- }
266
+ const affectedFileTree = this._depCache.getAffectedFileTree(modifiedFileSet);
267
+ this._debug(`
268
+ 영향받은 기존파일:
269
+ ${affectedFileTree.map(item => getTreeText(item)).join("\n")}`.trim());
338
270
 
339
- for (const toDeleteFile of toDeleteSet) {
340
- this._emittedFilesCacheMap.delete(toDeleteFile);
341
- this._sourceFileCacheMap.delete(toDeleteFile);
342
- this._stylesheetBundlingResultMap.delete(toDeleteFile);
343
- this._watchFileSet.delete(toDeleteFile);
344
- this._allDepCacheMap.delete(toDeleteFile);
345
- this._revDepCacheMap.delete(toDeleteFile);
346
- }
271
+ // 스타일 번들러에서 영향받은 파일 관련 항목 무효화
272
+ await worker.run("invalidate", [affectedFileSet]);
347
273
 
348
- for (const [key, deps] of this._revDepCacheMap) {
349
- for (const file of toDeleteSet) {
350
- deps.delete(file);
351
- }
352
- if (deps.size === 0) {
353
- this._revDepCacheMap.delete(key);
354
- }
274
+ // 의존성 캐시에서 영향받은 파일 관련 항목 무효화
275
+ this._depCache.invalidates(affectedFileSet);
276
+
277
+ // 내부 캐시에서 영향받은 파일 관련 항목 무효화
278
+ for (const affectedFile of affectedFileSet) {
279
+ this._emittedFilesCacheMap.delete(affectedFile);
280
+ this._sourceFileCacheMap.delete(affectedFile);
281
+ this._stylesheetBundlingResultMap.delete(affectedFile);
355
282
  }
356
283
  });
357
284
  }
358
285
 
359
286
  this._debug(`ts.Program 생성 중...`);
360
287
 
288
+ const compilerHost = this._perf.run("ts.CompilerHost 생성", () => {
289
+ return this._createCompilerHost(tsconfig.options, modifiedFileSet);
290
+ });
291
+
361
292
  this._perf.run("ts.Program 생성", () => {
362
293
  if (this._isForAngular) {
363
294
  this._ngProgram = new NgtscProgram(
364
- tsconf.fileNames,
365
- tsconf.options,
366
- tsconf.compilerHost,
295
+ tsconfig.fileNames,
296
+ tsconfig.options,
297
+ compilerHost,
367
298
  this._ngProgram,
368
299
  );
369
300
  this._program = this._ngProgram.getTsProgram();
370
301
  }
371
302
  else {
372
303
  this._program = ts.createProgram(
373
- tsconf.fileNames,
374
- tsconf.options,
375
- tsconf.compilerHost,
304
+ tsconfig.fileNames,
305
+ tsconfig.options,
306
+ compilerHost,
376
307
  this._program,
377
308
  );
378
309
  }
@@ -386,119 +317,40 @@ export class SdTsCompiler {
386
317
 
387
318
  this._debug(`새 의존성 분석 중...`);
388
319
 
389
- const messages: ISdBuildMessage[] = [];
390
320
  this._perf.run("새 의존성 분석", () => {
391
- const analysed = SdTsDependencyAnalyzer.analyze(
321
+ // SdTsDependencyAnalyzer를 통해 의존성 분석 및 SdDepCache 업데이트
322
+ SdDependencyAnalyzer.analyze(
392
323
  this._program!,
393
- tsconf.compilerHost,
324
+ compilerHost,
394
325
  this._opt.watchScopePaths,
395
- this._allDepCacheMap,
326
+ this._depCache,
396
327
  );
397
- messages.push(...analysed);
398
-
399
- for (const fileNPath of this._allDepCacheMap.keys()) {
400
- // const filePath = PathUtils.norm(sf.fileName);
401
- const deps = this._allDepCacheMap.get(fileNPath)!;
402
-
403
- for (const dep of deps) {
404
- const depCache = this._revDepCacheMap.getOrCreate(dep, new Set<TNormPath>());
405
- depCache.add(fileNPath);
406
- }
407
-
408
- if (this._ngProgram) {
409
- const sf = this._program!.getSourceFile(fileNPath)!;
410
-
411
- if (this._ngProgram.compiler.ignoreForEmit.has(sf)) {
412
- continue;
413
- }
414
328
 
415
- for (const dep of this._ngProgram.compiler.getResourceDependencies(sf)) {
416
- const ref = this._revDepCacheMap.getOrCreate(
417
- PathUtils.norm(dep),
418
- new Set<TNormPath>(),
419
- );
420
- ref.add(fileNPath);
421
- }
422
- }
423
- }
424
- });
425
-
426
- if (this._modifiedFileSet.size === 0) {
427
- this._debug(`영향 받은 파일 추가 중... (새 의존성)`);
428
-
429
- this._perf.run("영향 받은 파일 추가 중 (새 의존성)", () => {
430
- for (const fileNPath of this._allDepCacheMap.keys()) {
431
- if (!this._opt.watchScopePaths.some((scopePath) => PathUtils.isChildPath(
432
- fileNPath,
433
- scopePath,
434
- ))) {
435
- continue;
436
- }
437
-
438
- this._affectedFileSet.add(fileNPath);
439
- }
440
- });
441
- }
442
-
443
- /**
444
- * AI가 넣으라고해서 넣었지만 이유는 잘 모르겠음.
445
- * AI측의 설명은 아래와 같음:
446
- *
447
- * 변경된 파일이 .d.ts일 경우, 타입 정보만을 가져다 쓰는 다수의 .ts 파일들이
448
- * 직접적으로 import하고 있어도 revDepMap에는 기록되지 않을 수 있음.
449
- *
450
- * 따라서 .d.ts 파일을 참조하는 모든 파일을 allDepCacheMap에서 역추적하여
451
- * 간접 영향 파일들을 정확하게 affectedFileSet에 포함시켜야 함.
452
- *
453
- * 이 블록은 정확도 보완을 위한 보증 로직이며, 특히 초기 빌드 또는 watch 시 의존성 누락을 방지함.
454
- */
455
- for (const modifiedFile of this._modifiedFileSet) {
456
- // 신규 추가된 파일이 누락되지 않도록 추가하라고 하여 넣음
457
- if (
458
- !this._revDepCacheMap.has(modifiedFile) &&
459
- !this._allDepCacheMap.has(modifiedFile) &&
460
- this._program!.getSourceFile(modifiedFile)
461
- ) {
462
- this._affectedFileSet.add(modifiedFile);
463
- }
464
-
465
- // AI가 넣으라 한부분에 대한 설명은 여기서부터임
466
- if (!modifiedFile.endsWith(".d.ts")) continue;
467
-
468
- for (const [importer, deps] of this._allDepCacheMap) {
469
- if (deps.has(modifiedFile)) {
470
- this._affectedFileSet.add(importer);
471
- }
472
- }
473
- }
474
-
475
- for (const dep of this._revDepCacheMap.keys()) {
476
- if (this._modifiedFileSet.has(dep)) {
477
- this._affectedFileSet.adds(
478
- ...Array.from(this._revDepCacheMap.get(dep)!).mapMany((item) =>
479
- [
480
- item,
481
- // .d.ts면 .js파일도 affected에 추가
482
- item.endsWith(".d.ts") ? PathUtils.norm(item.replace(/\.d\.ts$/, ".js")) : undefined,
483
- ].filterExists(),
484
- ),
329
+ // Angular 리소스 의존성 추가
330
+ if (this._ngProgram) {
331
+ SdDependencyAnalyzer.analyzeAngularResources(
332
+ this._ngProgram,
333
+ this._opt.watchScopePaths,
334
+ this._depCache,
485
335
  );
486
336
  }
337
+ });
487
338
 
488
- // dep이 emit된적이 없으면 affected에 추가해야함.
489
- // dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
490
- if (!this._emittedFilesCacheMap.has(dep)) {
491
- this._affectedFileSet.add(dep);
492
- }
493
- }
339
+ const affectedFileSet = modifiedFileSet.size === 0
340
+ ? this._depCache.getFiles()
341
+ : this._depCache.getAffectedFileSet(modifiedFileSet);
342
+ const watchFileSet = this._depCache.getFiles();
494
343
 
495
344
  return {
496
- messages,
345
+ tsconfig,
346
+ compilerHost,
347
+ affectedFileSet,
348
+ watchFileSet,
497
349
  };
498
350
  }
499
351
 
500
- private async _lintAsync() {
501
- const lintFilePaths = Array.from(this._affectedFileSet)
352
+ private async _lintAsync(prepareResult: IPrepareResult) {
353
+ const lintFilePaths = Array.from(prepareResult.affectedFileSet)
502
354
  .filter((item) => PathUtils.isChildPath(item, this._opt.pkgPath))
503
355
  .filter((item) => (
504
356
  (!item.endsWith(".d.ts") && item.endsWith(".ts")) ||
@@ -516,7 +368,6 @@ export class SdTsCompiler {
516
368
  overrideConfig: {
517
369
  languageOptions: {
518
370
  parserOptions: {
519
- // parser: tseslint.parser,
520
371
  project: null,
521
372
  programs: [this._program],
522
373
  },
@@ -524,16 +375,45 @@ export class SdTsCompiler {
524
375
  },
525
376
  });
526
377
  return await linter.lintFiles(lintFilePaths);
378
+ }
379
+
380
+ private async _buildGlobalStyleAsync() {
381
+ //-- global style
382
+ if (
383
+ this._opt.globalStyleFilePath != null &&
384
+ FsUtils.exists(this._opt.globalStyleFilePath) &&
385
+ !this._emittedFilesCacheMap.has(this._opt.globalStyleFilePath)
386
+ ) {
387
+ this._debug(`전역 스타일 번들링 중...`);
388
+
389
+ await this._perf.run("전역 스타일 번들링", async () => {
390
+ const data = await FsUtils.readFileAsync(this._opt.globalStyleFilePath!);
391
+ const stylesheetBundlingResult = await this._bundleStylesheetAsync(
392
+ data,
393
+ this._opt.globalStyleFilePath!,
394
+ this._opt.globalStyleFilePath,
395
+ );
396
+ const emitFileInfos = this._emittedFilesCacheMap.getOrCreate(
397
+ this._opt.globalStyleFilePath!,
398
+ [],
399
+ );
400
+ emitFileInfos.push({
401
+ outAbsPath: PathUtils.norm(
402
+ this._opt.pkgPath,
403
+ path.relative(path.resolve(this._opt.pkgPath, "src"), this._opt.globalStyleFilePath!)
404
+ .replace(/\.scss$/, ".css"),
405
+ ),
406
+ text: stylesheetBundlingResult.contents ?? "",
407
+ });
408
+ });
527
409
 
528
- // return await this.#lintWorker.run("lint", [
529
- // {
530
- // cwd: this.#pkgPath,
531
- // fileSet: this.#affectedFileSet,
532
- // },
533
- // ]);
410
+ return this._opt.globalStyleFilePath;
411
+ }
412
+
413
+ return undefined;
534
414
  }
535
415
 
536
- private async _buildAsync(tsconf: ITsConfigInfo) {
416
+ private _build(prepareResult: IPrepareResult) {
537
417
  const emitFileSet = new Set<TNormPath>();
538
418
  const diagnostics: ts.Diagnostic[] = [];
539
419
 
@@ -553,7 +433,7 @@ export class SdTsCompiler {
553
433
 
554
434
  this._debug(`개별 파일 진단 수집 중...`);
555
435
 
556
- for (const affectedFile of this._affectedFileSet) {
436
+ for (const affectedFile of prepareResult.affectedFileSet) {
557
437
  if (!PathUtils.isChildPath(affectedFile, this._opt.pkgPath)) continue;
558
438
 
559
439
  const affectedSourceFile = this._program!.getSourceFile(affectedFile);
@@ -612,7 +492,7 @@ export class SdTsCompiler {
612
492
  // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 sourceFileSet으로 바꿈
613
493
  // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
614
494
  // 그래도 affected로 다시 테스트 (조금이라도 더 빠르게)
615
- for (const affectedFile of this._affectedFileSet) {
495
+ for (const affectedFile of prepareResult.affectedFileSet) {
616
496
  if (this._emittedFilesCacheMap.has(affectedFile)) continue;
617
497
 
618
498
  const sf = this._program!.getSourceFile(affectedFile);
@@ -630,7 +510,7 @@ export class SdTsCompiler {
630
510
  sf,
631
511
  (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
632
512
  if (!sourceFiles || sourceFiles.length === 0) {
633
- tsconf.compilerHost.writeFile(
513
+ prepareResult.compilerHost.writeFile(
634
514
  fileName,
635
515
  text,
636
516
  writeByteOrderMark,
@@ -653,7 +533,11 @@ export class SdTsCompiler {
653
533
  );
654
534
 
655
535
  if (PathUtils.isChildPath(sourceFile.fileName, this._opt.pkgPath)) {
656
- const real = this._convertOutputToReal(fileName, tsconf.distPath, text);
536
+ const real = this._convertOutputToReal(
537
+ fileName,
538
+ prepareResult.tsconfig.distPath,
539
+ text,
540
+ );
657
541
 
658
542
  emitFileInfoCaches.push({
659
543
  outAbsPath: real.filePath,
@@ -673,37 +557,6 @@ export class SdTsCompiler {
673
557
  }
674
558
  });
675
559
 
676
- //-- global style
677
- if (
678
- this._opt.globalStyleFilePath != null &&
679
- FsUtils.exists(this._opt.globalStyleFilePath) &&
680
- !this._emittedFilesCacheMap.has(this._opt.globalStyleFilePath)
681
- ) {
682
- this._debug(`전역 스타일 번들링 중...`);
683
-
684
- await this._perf.run("전역 스타일 번들링", async () => {
685
- const data = FsUtils.readFile(this._opt.globalStyleFilePath!);
686
- const stylesheetBundlingResult = await this._bundleStylesheetAsync(
687
- data,
688
- this._opt.globalStyleFilePath!,
689
- this._opt.globalStyleFilePath,
690
- );
691
- const emitFileInfos = this._emittedFilesCacheMap.getOrCreate(
692
- this._opt.globalStyleFilePath!,
693
- [],
694
- );
695
- emitFileInfos.push({
696
- outAbsPath: PathUtils.norm(
697
- this._opt.pkgPath,
698
- path.relative(path.resolve(this._opt.pkgPath, "src"), this._opt.globalStyleFilePath!)
699
- .replace(/\.scss$/, ".css"),
700
- ),
701
- text: stylesheetBundlingResult.contents ?? "",
702
- });
703
- emitFileSet.add(this._opt.globalStyleFilePath!);
704
- });
705
- }
706
-
707
560
  return {
708
561
  emitFileSet,
709
562
  diagnostics,
@@ -733,12 +586,21 @@ export class SdTsCompiler {
733
586
  private _debug(...msg: any[]): void {
734
587
  this._logger.debug(`[${path.basename(this._opt.pkgPath)}]`, ...msg);
735
588
  }
589
+ private _log(...msg: any[]): void {
590
+ this._logger.log(`[${path.basename(this._opt.pkgPath)}]`, ...msg);
591
+ }
736
592
  }
737
593
 
738
594
 
739
595
  interface ITsConfigInfo {
740
596
  fileNames: string[];
741
597
  options: ts.CompilerOptions;
742
- compilerHost: ts.CompilerHost;
743
598
  distPath: string;
599
+ }
600
+
601
+ interface IPrepareResult {
602
+ tsconfig: ITsConfigInfo;
603
+ compilerHost: ts.CompilerHost;
604
+ affectedFileSet: Set<TNormPath>;
605
+ watchFileSet: Set<TNormPath>;
744
606
  }