@simplysm/sd-cli 12.5.19 → 12.5.21

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 (58) hide show
  1. package/dist/build-tools/SdNgBundler.d.ts +1 -0
  2. package/dist/build-tools/SdNgBundler.js +70 -57
  3. package/dist/build-tools/SdNgBundler.js.map +1 -1
  4. package/dist/build-tools/SdReactBundler.d.ts +25 -0
  5. package/dist/build-tools/SdReactBundler.js +295 -0
  6. package/dist/build-tools/SdReactBundler.js.map +1 -0
  7. package/dist/build-tools/SdReactBundlerContext.d.ts +14 -0
  8. package/dist/build-tools/SdReactBundlerContext.js +59 -0
  9. package/dist/build-tools/SdReactBundlerContext.js.map +1 -0
  10. package/dist/build-tools/SdServerBundler.d.ts +1 -0
  11. package/dist/build-tools/SdServerBundler.js +8 -7
  12. package/dist/build-tools/SdServerBundler.js.map +1 -1
  13. package/dist/build-tools/SdTsCompiler.d.ts +1 -0
  14. package/dist/build-tools/SdTsCompiler.js +355 -327
  15. package/dist/build-tools/SdTsCompiler.js.map +1 -1
  16. package/dist/build-tools/SdTsLibBundler.d.ts +1 -1
  17. package/dist/build-tools/SdTsLibBundler.js +2 -1
  18. package/dist/build-tools/SdTsLibBundler.js.map +1 -1
  19. package/dist/builders/SdCliClientBuilder.js +42 -20
  20. package/dist/builders/SdCliClientBuilder.js.map +1 -1
  21. package/dist/builders/SdCliServerBuilder.js +2 -1
  22. package/dist/builders/SdCliServerBuilder.js.map +1 -1
  23. package/dist/builders/SdCliTsLibBuilder.js +4 -2
  24. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  25. package/dist/bundle-plugins/sdNgPlugin.d.ts +1 -0
  26. package/dist/bundle-plugins/sdNgPlugin.js +38 -23
  27. package/dist/bundle-plugins/sdNgPlugin.js.map +1 -1
  28. package/dist/bundle-plugins/sdReactPlugin.d.ts +16 -0
  29. package/dist/bundle-plugins/sdReactPlugin.js +117 -0
  30. package/dist/bundle-plugins/sdReactPlugin.js.map +1 -0
  31. package/dist/bundle-plugins/sdServerPlugin.d.ts +1 -0
  32. package/dist/bundle-plugins/sdServerPlugin.js +1 -0
  33. package/dist/bundle-plugins/sdServerPlugin.js.map +1 -1
  34. package/dist/entry/SdCliProject.js +7 -4
  35. package/dist/entry/SdCliProject.js.map +1 -1
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.js +4 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/utils/SdCliPerformanceTime.d.ts +9 -0
  40. package/dist/utils/SdCliPerformanceTime.js +40 -0
  41. package/dist/utils/SdCliPerformanceTime.js.map +1 -0
  42. package/package.json +13 -10
  43. package/src/build-tools/SdNgBundler.ts +82 -68
  44. package/src/build-tools/SdReactBundler.ts +372 -0
  45. package/src/build-tools/SdReactBundlerContext.ts +71 -0
  46. package/src/build-tools/SdServerBundler.ts +22 -20
  47. package/src/build-tools/SdTsCompiler.ts +341 -357
  48. package/src/build-tools/SdTsLibBundler.ts +2 -1
  49. package/src/builders/SdCliClientBuilder.ts +53 -29
  50. package/src/builders/SdCliServerBuilder.ts +5 -4
  51. package/src/builders/SdCliTsLibBuilder.ts +7 -4
  52. package/src/bundle-plugins/sdNgPlugin.ts +44 -23
  53. package/src/bundle-plugins/sdReactPlugin.ts +164 -0
  54. package/src/bundle-plugins/sdServerPlugin.ts +2 -0
  55. package/src/entry/SdCliProject.ts +6 -4
  56. package/src/index.ts +4 -0
  57. package/src/utils/SdCliPerformanceTime.ts +42 -0
  58. package/tsconfig.json +1 -1
@@ -1,15 +1,15 @@
1
- import ts, { CompilerOptions } from "typescript";
1
+ import ts, { CompilerOptions, DiagnosticCategory } from "typescript";
2
2
  import path from "path";
3
3
  import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
4
4
  import { StringUtil } from "@simplysm/sd-core-common";
5
5
  import esbuild from "esbuild";
6
6
  import { NgtscProgram, OptimizeFor } from "@angular/compiler-cli";
7
- import { createHash } from "crypto";
8
7
  import { ComponentStylesheetBundler } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
9
8
  import { AngularCompilerHost } from "@angular/build/src/tools/angular/angular-host";
10
9
  import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
11
10
  import browserslist from "browserslist";
12
11
  import { replaceBootstrap } from "@angular/build/src/tools/angular/transformers/jit-bootstrap-transformer";
12
+ import { SdCliPerformanceTimer } from "../utils/SdCliPerformanceTime";
13
13
 
14
14
  export class SdTsCompiler {
15
15
  readonly #logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
@@ -17,7 +17,7 @@ export class SdTsCompiler {
17
17
  readonly #parsedTsconfig: ts.ParsedCommandLine;
18
18
  readonly #isForAngular: boolean;
19
19
 
20
- // readonly #revDependencyCacheMap = new Map<string, Set<string>>();
20
+ readonly #revDependencyCacheMap = new Map<string, Set<string>>();
21
21
  readonly #resourceDependencyCacheMap = new Map<string, Set<string>>();
22
22
  readonly #sourceFileCacheMap = new Map<string, ts.SourceFile>();
23
23
  readonly #emittedFilesCacheMap = new Map<
@@ -33,7 +33,6 @@ export class SdTsCompiler {
33
33
 
34
34
  #ngProgram: NgtscProgram | undefined;
35
35
  #program: ts.Program | undefined;
36
- #builder: ts.EmitAndSemanticDiagnosticsBuilderProgram | undefined;
37
36
 
38
37
  readonly #modifiedFileSet = new Set<string>();
39
38
 
@@ -43,6 +42,7 @@ export class SdTsCompiler {
43
42
  readonly #pkgPath: string;
44
43
  readonly #distPath: string;
45
44
  readonly #globalStyleFilePath?: string;
45
+ readonly #watchScopePaths: string[];
46
46
 
47
47
  readonly #isForBundle: boolean;
48
48
 
@@ -51,11 +51,13 @@ export class SdTsCompiler {
51
51
  additionalOptions: CompilerOptions;
52
52
  isForBundle: boolean;
53
53
  isDevMode: boolean;
54
+ watchScopePaths: string[];
54
55
  globalStyleFilePath?: string;
55
56
  }) {
56
57
  this.#pkgPath = opt.pkgPath;
57
58
  this.#globalStyleFilePath = opt.globalStyleFilePath != null ? path.normalize(opt.globalStyleFilePath) : undefined;
58
59
  this.#isForBundle = opt.isForBundle;
60
+ this.#watchScopePaths = opt.watchScopePaths;
59
61
 
60
62
  this.#debug("초기화...");
61
63
 
@@ -196,65 +198,64 @@ export class SdTsCompiler {
196
198
  }
197
199
 
198
200
  invalidate(modifiedFileSet: Set<string>) {
199
- for (const modifiedFile of Array.from(modifiedFileSet).map((item) => path.normalize(item))) {
200
- this.#modifiedFileSet.add(modifiedFile);
201
- this.#modifiedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
202
- }
201
+ this.#modifiedFileSet.adds(...Array.from(modifiedFileSet).map((item) => path.normalize(item)));
203
202
  }
204
203
 
205
204
  async buildAsync(): Promise<ISdTsCompilerResult> {
206
- const affectedSourceFileSet = new Set<ts.SourceFile>();
205
+ let perf = new SdCliPerformanceTimer("esbuild");
206
+
207
+ const affectedFileSet = new Set<string>();
207
208
  const emitFileSet = new Set<string>();
208
209
 
209
210
  this.#debug(`get affected (old deps & old res deps)...`);
210
211
 
211
- for (const modifiedFile of this.#modifiedFileSet) {
212
- // affectedFileSet.add(modifiedFile);
213
- // affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
214
- // affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
212
+ perf.run("get affected", () => {
213
+ for (const modifiedFile of this.#modifiedFileSet) {
214
+ affectedFileSet.add(modifiedFile);
215
+ affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
216
+ affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
215
217
 
216
- this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
217
- this.#sourceFileCacheMap.delete(path.normalize(modifiedFile));
218
- this.#stylesheetBundlingResultMap.delete(path.normalize(modifiedFile));
219
- this.#watchFileSet.delete(path.normalize(modifiedFile));
220
- }
221
- this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
218
+ this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
219
+ }
220
+ });
222
221
 
223
- // this.#debug(`invalidate & clear cache...`);
222
+ this.#debug(`invalidate & clear cache...`);
224
223
 
225
- // this.#stylesheetBundler?.invalidate(affectedFileSet);
224
+ perf.run("invalidate & clear cache", () => {
225
+ this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
226
226
 
227
- // for (const affectedFile of affectedFileSet) {
228
- // this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
229
- // this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
230
- // this.#watchFileSet.delete(path.normalize(affectedFile));
231
- // }
227
+ for (const affectedFile of affectedFileSet) {
228
+ this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
229
+ this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
230
+ this.#watchFileSet.delete(path.normalize(affectedFile));
231
+ }
232
232
 
233
- // this.#revDependencyCacheMap.clear();
234
- this.#resourceDependencyCacheMap.clear();
233
+ this.#revDependencyCacheMap.clear();
234
+ this.#resourceDependencyCacheMap.clear();
235
+ });
235
236
 
236
237
  this.#debug(`create program...`);
237
238
 
238
- if (this.#isForAngular) {
239
- this.#ngProgram = new NgtscProgram(
240
- this.#parsedTsconfig.fileNames,
241
- this.#parsedTsconfig.options,
242
- this.#compilerHost,
243
- this.#ngProgram,
244
- );
245
- this.#program = this.#ngProgram.getTsProgram();
246
- } else {
247
- this.#program = ts.createProgram(
248
- this.#parsedTsconfig.fileNames,
249
- this.#parsedTsconfig.options,
250
- this.#compilerHost,
251
- this.#program,
252
- );
253
- }
254
-
255
- this.#debug(`create builder...`);
239
+ perf.run("create program", () => {
240
+ if (this.#isForAngular) {
241
+ this.#ngProgram = new NgtscProgram(
242
+ this.#parsedTsconfig.fileNames,
243
+ this.#parsedTsconfig.options,
244
+ this.#compilerHost,
245
+ this.#ngProgram,
246
+ );
247
+ this.#program = this.#ngProgram.getTsProgram();
248
+ } else {
249
+ this.#program = ts.createProgram(
250
+ this.#parsedTsconfig.fileNames,
251
+ this.#parsedTsconfig.options,
252
+ this.#compilerHost,
253
+ this.#program,
254
+ );
255
+ }
256
+ });
256
257
 
257
- const baseGetSourceFiles = this.#program.getSourceFiles;
258
+ /*const baseGetSourceFiles = this.#program.getSourceFiles;
258
259
  this.#program.getSourceFiles = function (...parameters) {
259
260
  const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
260
261
 
@@ -265,12 +266,12 @@ export class SdTsCompiler {
265
266
  }
266
267
 
267
268
  return files;
268
- };
269
-
270
- this.#builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(this.#program, this.#compilerHost, this.#builder);
269
+ };*/
271
270
 
272
271
  if (this.#ngProgram) {
273
- await this.#ngProgram.compiler.analyzeAsync();
272
+ await perf.run("ng analyze", async () => {
273
+ await this.#ngProgram!.compiler.analyzeAsync();
274
+ });
274
275
  }
275
276
 
276
277
  const getOrgSourceFile = (sf: ts.SourceFile) => {
@@ -284,340 +285,281 @@ export class SdTsCompiler {
284
285
 
285
286
  this.#debug(`get affected (new deps)...`);
286
287
 
287
- // const sourceFileSet = new Set(
288
- // this.#program
289
- // .getSourceFiles()
290
- // .map((sf) => getOrgSourceFile(sf))
291
- // .filterExists(),
292
- // );
293
-
294
- // const depMap = new Map<
295
- // string,
296
- // {
297
- // fileName: string;
298
- // importName: string;
299
- // exportName?: string;
300
- // }[]
301
- // >();
302
- // for (const sf of sourceFileSet) {
303
- // const refs = this.#findDeps(sf);
304
- // depMap.set(path.normalize(sf.fileName), refs);
305
- // }
306
- //
307
- // const allDepMap = new Map<string, Set<string>>();
308
- // const getAllDeps = (fileName: string, prevSet?: Set<string>) => {
309
- // if (allDepMap.has(fileName)) {
310
- // return allDepMap.get(fileName)!;
311
- // }
312
- //
313
- // const result = new Set<string>();
314
- //
315
- // const deps = depMap.get(fileName) ?? [];
316
- // result.adds(...deps.map((item) => item.fileName));
317
- //
318
- // for (const dep of deps) {
319
- // const targetDeps = depMap.get(dep.fileName) ?? [];
320
- //
321
- // if (dep.importName === "*") {
322
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
323
- // if (prevSet?.has(targetRefItem.fileName)) continue;
324
- //
325
- // result.add(targetRefItem.fileName);
326
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
327
- // }
328
- // } else {
329
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
330
- // if (prevSet?.has(targetRefItem.fileName)) continue;
331
- //
332
- // result.add(targetRefItem.fileName);
333
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
334
- // }
335
- // }
336
- // }
337
- //
338
- // return result;
339
- // };
340
-
341
- // for (const sf of sourceFileSet) {
342
- // const deps = getAllDeps(path.normalize(sf.fileName));
343
- // allDepMap.set(path.normalize(sf.fileName), deps);
344
- //
345
- // for (const dep of getAllDeps(path.normalize(sf.fileName))) {
346
- // const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
347
- // depCache.add(path.normalize(sf.fileName));
348
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
349
- // affectedFileSet.add(path.normalize(sf.fileName));
350
- // }
351
- // }
352
- //
353
- // if (this.#ngProgram) {
354
- // if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
355
- // continue;
356
- // }
357
- //
358
- // for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
359
- // const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
360
- // ref.add(path.normalize(sf.fileName));
361
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
362
- // affectedFileSet.add(path.normalize(sf.fileName));
363
- // }
364
- // }
365
- // }
366
- // }
367
-
368
- // if (affectedFileSet.size === 0) {
369
- // this.#debug(`get affected (init)...`);
370
- //
371
- // for (const sf of this.#program.getSourceFiles()) {
372
- // const orgSf = getOrgSourceFile(sf);
373
- // if (!orgSf) continue;
374
- //
375
- // affectedFileSet.add(path.normalize(orgSf.fileName));
376
- // }
377
- // }
288
+ const diagnostics: ts.Diagnostic[] = [];
378
289
 
379
- this.#debug(`get diagnostics...`);
290
+ perf.run("get affected (deps)", () => {
291
+ const sourceFileSet = new Set(
292
+ this.#program!.getSourceFiles()
293
+ .map((sf) => getOrgSourceFile(sf))
294
+ .filterExists(),
295
+ );
380
296
 
381
- const diagnostics: ts.Diagnostic[] = [];
297
+ const depMap = new Map<
298
+ string,
299
+ {
300
+ fileName: string;
301
+ importName: string;
302
+ exportName?: string;
303
+ }[]
304
+ >();
305
+ for (const sf of sourceFileSet) {
306
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
307
+ continue;
308
+ }
382
309
 
383
- diagnostics.push(
384
- ...this.#builder.getConfigFileParsingDiagnostics(),
385
- ...this.#builder.getOptionsDiagnostics(),
386
- ...this.#builder.getGlobalDiagnostics(),
387
- );
310
+ const refs = this.#findDeps(sf);
311
+ diagnostics.push(...refs.filter((item) => "category" in item));
312
+ depMap.set(
313
+ path.normalize(sf.fileName),
314
+ refs
315
+ .filter((item) => "fileName" in item)
316
+ .filter((item) =>
317
+ this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(item.fileName, scopePath)),
318
+ ),
319
+ );
320
+ }
388
321
 
389
- /*diagnostics.push(
390
- ...this.#program.getConfigFileParsingDiagnostics(),
391
- ...this.#program.getOptionsDiagnostics(),
392
- ...this.#program.getGlobalDiagnostics(),
393
- );*/
322
+ const allDepMap = new Map<string, Set<string>>();
323
+ const getAllDeps = (fileName: string, prevSet?: Set<string>) => {
324
+ if (allDepMap.has(fileName)) {
325
+ return allDepMap.get(fileName)!;
326
+ }
394
327
 
395
- if (this.#ngProgram) {
396
- diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
397
- }
328
+ const result = new Set<string>();
398
329
 
399
- this.#debug(`get diagnostics of files...`);
330
+ const deps = depMap.get(fileName) ?? [];
331
+ result.adds(...deps.map((item) => item.fileName));
400
332
 
401
- while (true) {
402
- const affectedFileResult = this.#builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sf) => {
403
- if (
404
- this.#ngProgram &&
405
- this.#ngProgram.compiler.ignoreForDiagnostics.has(sf) &&
406
- sf.fileName.endsWith(".ngtypecheck.ts")
407
- ) {
408
- const orgSourceFile = getOrgSourceFile(sf);
409
- if (orgSourceFile) {
410
- affectedSourceFileSet.add(orgSourceFile);
333
+ for (const dep of deps) {
334
+ const targetDeps = depMap.get(dep.fileName) ?? [];
335
+
336
+ if (dep.importName === "*") {
337
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
338
+ if (prevSet?.has(targetRefItem.fileName)) continue;
339
+
340
+ result.add(targetRefItem.fileName);
341
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
342
+ }
343
+ } else {
344
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
345
+ if (prevSet?.has(targetRefItem.fileName)) continue;
346
+
347
+ result.add(targetRefItem.fileName);
348
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
349
+ }
411
350
  }
412
- return true;
413
351
  }
414
- return false;
415
- });
416
- if (!affectedFileResult) break;
417
352
 
418
- const affectedSourceFile = affectedFileResult.affected as ts.SourceFile;
353
+ return result;
354
+ };
419
355
 
420
- affectedSourceFileSet.add(affectedSourceFile);
421
- }
356
+ for (const sf of sourceFileSet) {
357
+ const deps = getAllDeps(path.normalize(sf.fileName));
358
+ allDepMap.set(path.normalize(sf.fileName), deps);
422
359
 
423
- for (const affectedSourceFile of affectedSourceFileSet) {
424
- this.#debug(`get diagnostics of file [${affectedSourceFile.fileName}]`);
360
+ for (const dep of getAllDeps(path.normalize(sf.fileName))) {
361
+ const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
362
+ depCache.add(path.normalize(sf.fileName));
363
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
364
+ affectedFileSet.add(path.normalize(sf.fileName));
365
+ }
366
+ }
425
367
 
426
- diagnostics.push(
427
- ...this.#program.getSyntacticDiagnostics(affectedSourceFile),
428
- ...this.#program.getSemanticDiagnostics(affectedSourceFile),
429
- );
368
+ if (this.#ngProgram) {
369
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
370
+ continue;
371
+ }
430
372
 
431
- if (this.#ngProgram) {
432
- if (affectedSourceFile.isDeclarationFile) {
433
- continue;
373
+ for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
374
+ const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
375
+ ref.add(path.normalize(sf.fileName));
376
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
377
+ affectedFileSet.add(path.normalize(sf.fileName));
378
+ }
379
+ }
434
380
  }
435
-
436
- diagnostics.push(
437
- ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
438
- );
439
381
  }
440
- }
382
+ });
441
383
 
442
- /*
443
- for (const affectedFile of affectedFileSet) {
444
- if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
445
- continue;
446
- }
384
+ if (affectedFileSet.size === 0) {
385
+ this.#debug(`get affected (init)...`);
447
386
 
448
- this.#debug(`get diagnostics of file [${affectedFile}]`);
387
+ perf.run("get affected (init)", () => {
388
+ for (const sf of this.#program!.getSourceFiles()) {
389
+ if (!this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(sf.fileName, scopePath))) {
390
+ continue;
391
+ }
449
392
 
450
- const affectedSourceFile = this.#program.getSourceFile(affectedFile);
451
- if (
452
- !affectedSourceFile ||
453
- (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
454
- ) {
455
- continue;
456
- }
393
+ const orgSf = getOrgSourceFile(sf);
394
+ if (!orgSf) continue;
457
395
 
396
+ affectedFileSet.add(path.normalize(orgSf.fileName));
397
+ }
398
+ });
399
+ }
400
+
401
+ this.#debug(`get diagnostics...`);
402
+
403
+ perf.run("get program diagnostics", () => {
458
404
  diagnostics.push(
459
- ...this.#program.getSyntacticDiagnostics(affectedSourceFile),
460
- ...this.#program.getSemanticDiagnostics(affectedSourceFile),
405
+ ...this.#program!.getConfigFileParsingDiagnostics(),
406
+ ...this.#program!.getOptionsDiagnostics(),
407
+ ...this.#program!.getGlobalDiagnostics(),
461
408
  );
462
409
 
463
410
  if (this.#ngProgram) {
464
- if (affectedSourceFile.isDeclarationFile) {
465
- continue;
466
- }
467
-
468
- diagnostics.push(
469
- ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
470
- );
411
+ diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
471
412
  }
472
- }*/
413
+ });
414
+
415
+ this.#debug(`get diagnostics of files...`);
473
416
 
474
- this.#debug(`prepare emit...`);
417
+ perf.run("get file diagnostics", () => {
418
+ for (const affectedFile of affectedFileSet) {
419
+ if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
420
+ continue;
421
+ }
475
422
 
476
- let transformers: ts.CustomTransformers = {};
423
+ const affectedSourceFile = this.#program!.getSourceFile(affectedFile);
477
424
 
478
- if (this.#ngProgram) {
479
- transformers = {
480
- ...transformers,
481
- ...this.#ngProgram.compiler.prepareEmit().transformers,
482
- };
483
- (transformers.before ??= []).push(replaceBootstrap(() => this.#program!.getTypeChecker()));
484
- }
485
- // (transformers.before ??= []).push(transformKeys(this.#program));
425
+ if (
426
+ !affectedSourceFile ||
427
+ (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
428
+ ) {
429
+ continue;
430
+ }
486
431
 
487
- this.#debug(`prepare emit files...`);
432
+ // this.#debug(`get diagnostics of file ${affectedFile}...`);
488
433
 
489
- while (
490
- this.#builder.emitNextAffectedFile(
491
- (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
492
- if (!sourceFiles || sourceFiles.length === 0) {
493
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
494
- return;
495
- }
434
+ diagnostics.push(
435
+ ...this.#program!.getSyntacticDiagnostics(affectedSourceFile),
436
+ ...this.#program!.getSemanticDiagnostics(affectedSourceFile),
437
+ );
496
438
 
497
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
498
- if (this.#ngProgram) {
499
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
439
+ if (this.#ngProgram) {
440
+ perf.run("get file diagnostics: ng", () => {
441
+ if (affectedSourceFile.isDeclarationFile) {
500
442
  return;
501
443
  }
502
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
503
- }
504
444
 
505
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
506
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
507
- let realFilePath = fileName;
508
- let realText = text;
509
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
510
- realFilePath = path.resolve(
511
- this.#distPath,
512
- path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
513
- );
514
-
515
- if (fileName.endsWith(".js.map")) {
516
- const sourceMapContents = JSON.parse(realText);
517
- // remove "../../"
518
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
519
- realText = JSON.stringify(sourceMapContents);
520
- }
521
- }
445
+ diagnostics.push(
446
+ ...this.#ngProgram!.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
447
+ );
448
+ });
449
+ }
450
+ }
451
+ });
522
452
 
523
- emitFileInfoCaches.push({
524
- outAbsPath: realFilePath,
525
- text: realText,
526
- });
527
- } else {
528
- emitFileInfoCaches.push({ text });
529
- }
453
+ perf.run("emit", () => {
454
+ this.#debug(`prepare emit...`);
530
455
 
531
- emitFileSet.add(path.normalize(sourceFile.fileName));
532
- },
533
- undefined,
534
- undefined,
535
- transformers,
536
- )
537
- ) {}
538
-
539
- // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
540
- // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
541
- /*for (const affectedFile of affectedFileSet) {
542
- if (this.#emittedFilesCacheMap.has(affectedFile)) {
543
- continue;
456
+ let transformers: ts.CustomTransformers = {};
457
+
458
+ if (this.#ngProgram) {
459
+ transformers = {
460
+ ...transformers,
461
+ ...this.#ngProgram.compiler.prepareEmit().transformers,
462
+ };
463
+ (transformers.before ??= []).push(replaceBootstrap(() => this.#program!.getTypeChecker()));
544
464
  }
465
+ // (transformers.before ??= []).push(transformKeys(this.#program));
545
466
 
546
- const sf = this.#program.getSourceFile(affectedFile);
547
- if (!sf) {
548
- continue;
549
- }*/
467
+ this.#debug(`emit for files...`);
550
468
 
551
- /*for (const sf of sourceFileSet) {
552
- if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
553
- continue;
554
- }
469
+ // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
470
+ // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
471
+ // 그래도 affected로 다시 테스트
472
+ for (const affectedFile of affectedFileSet) {
473
+ if (this.#emittedFilesCacheMap.has(affectedFile)) {
474
+ continue;
475
+ }
555
476
 
556
- if (sf.isDeclarationFile) {
557
- continue;
558
- }
477
+ const sf = this.#program!.getSourceFile(affectedFile);
478
+ if (!sf) {
479
+ continue;
480
+ }
559
481
 
560
- if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
561
- continue;
562
- }
482
+ // for (const sf of sourceFileSet) {
483
+ /*if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
484
+ continue;
485
+ }*/
563
486
 
564
- // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
565
- if (!this.#isForBundle) {
566
- if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
487
+ if (sf.isDeclarationFile) {
567
488
  continue;
568
489
  }
569
- }
570
490
 
571
- this.#debug(`emit for`, sf.fileName);
572
- this.#program.emit(
573
- sf,
574
- (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
575
- if (!sourceFiles || sourceFiles.length === 0) {
576
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
577
- return;
491
+ if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
492
+ continue;
493
+ }
494
+
495
+ if (
496
+ this.#ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf) &&
497
+ !affectedFileSet.has(path.normalize(sf.fileName))
498
+ ) {
499
+ continue;
500
+ }
501
+
502
+ // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
503
+ if (!this.#isForBundle) {
504
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
505
+ continue;
578
506
  }
507
+ }
579
508
 
580
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
581
- if (this.#ngProgram) {
582
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
509
+ // this.#debug(`emit for`, sf.fileName);
510
+ this.#program!.emit(
511
+ sf,
512
+ (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
513
+ if (!sourceFiles || sourceFiles.length === 0) {
514
+ this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
583
515
  return;
584
516
  }
585
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
586
- }
587
517
 
588
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
589
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
590
- let realFilePath = fileName;
591
- let realText = text;
592
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
593
- realFilePath = path.resolve(
594
- this.#distPath,
595
- path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
596
- );
597
-
598
- if (fileName.endsWith(".js.map")) {
599
- const sourceMapContents = JSON.parse(realText);
600
- // remove "../../"
601
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
602
- realText = JSON.stringify(sourceMapContents);
518
+ const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
519
+ if (this.#ngProgram) {
520
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
521
+ return;
603
522
  }
523
+ this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
604
524
  }
605
525
 
606
- emitFileInfoCaches.push({
607
- outAbsPath: realFilePath,
608
- text: realText,
609
- });
610
- } else {
611
- emitFileInfoCaches.push({ text });
612
- }
526
+ const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
527
+
528
+ if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
529
+ let realFilePath = fileName;
530
+ let realText = text;
531
+ if (
532
+ PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))
533
+ ) {
534
+ realFilePath = path.resolve(
535
+ this.#distPath,
536
+ path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
537
+ );
538
+
539
+ if (fileName.endsWith(".js.map")) {
540
+ const sourceMapContents = JSON.parse(realText);
541
+ // remove "../../"
542
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
543
+ realText = JSON.stringify(sourceMapContents);
544
+ }
545
+ }
613
546
 
614
- emitFileSet.add(path.normalize(sourceFile.fileName));
615
- },
616
- undefined,
617
- undefined,
618
- transformers,
619
- );
620
- }*/
547
+ emitFileInfoCaches.push({
548
+ outAbsPath: realFilePath,
549
+ text: realText,
550
+ });
551
+ } else {
552
+ emitFileInfoCaches.push({ text });
553
+ }
554
+
555
+ emitFileSet.add(path.normalize(sourceFile.fileName));
556
+ },
557
+ undefined,
558
+ undefined,
559
+ transformers,
560
+ );
561
+ }
562
+ });
621
563
 
622
564
  //-- global style
623
565
  if (
@@ -627,30 +569,31 @@ export class SdTsCompiler {
627
569
  ) {
628
570
  this.#debug(`bundle global style...`);
629
571
 
630
- const data = await FsUtil.readFileAsync(this.#globalStyleFilePath);
631
- const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
632
- const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath, []);
633
- emitFileInfos.push({
634
- outAbsPath: path.resolve(
635
- this.#pkgPath,
636
- path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath).replace(/\.scss$/, ".css"),
637
- ),
638
- text: contents,
572
+ await perf.run("bundle global style", async () => {
573
+ const data = await FsUtil.readFileAsync(this.#globalStyleFilePath!);
574
+ const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath!, this.#globalStyleFilePath);
575
+ const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath!, []);
576
+ emitFileInfos.push({
577
+ outAbsPath: path.resolve(
578
+ this.#pkgPath,
579
+ path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath!).replace(/\.scss$/, ".css"),
580
+ ),
581
+ text: contents,
582
+ });
583
+ emitFileSet.add(this.#globalStyleFilePath!);
639
584
  });
640
- emitFileSet.add(this.#globalStyleFilePath);
641
585
  }
642
586
 
643
587
  //-- init
644
588
 
645
589
  this.#modifiedFileSet.clear();
646
590
 
647
- const affectedFileSet = new Set(Array.from(affectedSourceFileSet).map((item) => path.normalize(item.fileName)));
648
- this.#debug(`build completed`, affectedFileSet, diagnostics.length);
591
+ this.#debug(`build completed`, perf.toString());
649
592
 
650
593
  //-- result
651
594
 
652
595
  return {
653
- program: this.#program,
596
+ program: this.#program!,
654
597
  typescriptDiagnostics: diagnostics,
655
598
  stylesheetBundlingResultMap: this.#stylesheetBundlingResultMap,
656
599
  emittedFilesCacheMap: this.#emittedFilesCacheMap,
@@ -664,12 +607,15 @@ export class SdTsCompiler {
664
607
  this.#logger.debug(`[${path.basename(this.#pkgPath)}]`, ...msg);
665
608
  }
666
609
 
667
- /*#findDeps(sf: ts.SourceFile) {
668
- const deps: {
669
- fileName: string;
670
- importName: string;
671
- exportName?: string;
672
- }[] = [];
610
+ #findDeps(sf: ts.SourceFile) {
611
+ const deps: (
612
+ | {
613
+ fileName: string;
614
+ importName: string;
615
+ exportName?: string;
616
+ }
617
+ | ts.Diagnostic
618
+ )[] = [];
673
619
 
674
620
  const tc = this.#program!.getTypeChecker();
675
621
 
@@ -677,10 +623,30 @@ export class SdTsCompiler {
677
623
  if (ts.isExportDeclaration(node)) {
678
624
  if (node.moduleSpecifier) {
679
625
  const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
680
- if (!moduleSymbol) throw new NeverEntryError(`export moduleSymbol: ${sf.fileName}`);
626
+ if (!moduleSymbol) {
627
+ deps.push({
628
+ category: DiagnosticCategory.Error,
629
+ code: -1,
630
+ file: sf,
631
+ start: node.getStart(),
632
+ length: node.getEnd() - node.getStart(),
633
+ messageText: `export moduleSymbol not found`,
634
+ });
635
+ return;
636
+ }
681
637
 
682
638
  const decls = moduleSymbol.getDeclarations();
683
- if (!decls) throw new NeverEntryError(`export decls: ${sf.fileName}`);
639
+ if (!decls) {
640
+ deps.push({
641
+ category: DiagnosticCategory.Error,
642
+ code: -1,
643
+ file: sf,
644
+ start: node.getStart(),
645
+ length: node.getEnd() - node.getStart(),
646
+ messageText: `export decls not found`,
647
+ });
648
+ return;
649
+ }
684
650
 
685
651
  const namedBindings = node.exportClause;
686
652
  if (namedBindings && ts.isNamedExports(namedBindings)) {
@@ -695,7 +661,15 @@ export class SdTsCompiler {
695
661
  }
696
662
  } else {
697
663
  if (!moduleSymbol.exports) {
698
- throw new NeverEntryError("1234");
664
+ deps.push({
665
+ category: DiagnosticCategory.Error,
666
+ code: -1,
667
+ file: sf,
668
+ start: node.getStart(),
669
+ length: node.getEnd() - node.getStart(),
670
+ messageText: `moduleSymbol exports not found`,
671
+ });
672
+ return;
699
673
  }
700
674
 
701
675
  for (const decl of decls) {
@@ -718,12 +692,22 @@ export class SdTsCompiler {
718
692
  importName: "*",
719
693
  });
720
694
  }
721
- /!*else {
695
+ /*else {
722
696
  throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
723
- }*!/
697
+ }*/
724
698
  } else {
725
699
  const decls = moduleSymbol.getDeclarations();
726
- if (!decls) throw new NeverEntryError(`import decls: ${sf.fileName}`);
700
+ if (!decls) {
701
+ deps.push({
702
+ category: DiagnosticCategory.Error,
703
+ code: -1,
704
+ file: sf,
705
+ start: node.getStart(),
706
+ length: node.getEnd() - node.getStart(),
707
+ messageText: `import decls not found`,
708
+ });
709
+ return;
710
+ }
727
711
 
728
712
  const namedBindings = node.importClause?.namedBindings;
729
713
  if (namedBindings && ts.isNamedImports(namedBindings)) {
@@ -748,7 +732,7 @@ export class SdTsCompiler {
748
732
  });
749
733
 
750
734
  return deps;
751
- }*/
735
+ }
752
736
  }
753
737
 
754
738
  export interface ISdTsCompilerResult {