@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,18 +1,18 @@
1
- import ts from "typescript";
1
+ import ts, { 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 { NgtscProgram, OptimizeFor } from "@angular/compiler-cli";
6
- import { createHash } from "crypto";
7
6
  import { ComponentStylesheetBundler } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
8
7
  import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
9
8
  import browserslist from "browserslist";
10
9
  import { replaceBootstrap } from "@angular/build/src/tools/angular/transformers/jit-bootstrap-transformer";
10
+ import { SdCliPerformanceTimer } from "../utils/SdCliPerformanceTime";
11
11
  export class SdTsCompiler {
12
12
  #logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
13
13
  #parsedTsconfig;
14
14
  #isForAngular;
15
- // readonly #revDependencyCacheMap = new Map<string, Set<string>>();
15
+ #revDependencyCacheMap = new Map();
16
16
  #resourceDependencyCacheMap = new Map();
17
17
  #sourceFileCacheMap = new Map();
18
18
  #emittedFilesCacheMap = new Map();
@@ -20,18 +20,19 @@ export class SdTsCompiler {
20
20
  #compilerHost;
21
21
  #ngProgram;
22
22
  #program;
23
- #builder;
24
23
  #modifiedFileSet = new Set();
25
24
  #watchFileSet = new Set();
26
25
  #stylesheetBundlingResultMap = new Map();
27
26
  #pkgPath;
28
27
  #distPath;
29
28
  #globalStyleFilePath;
29
+ #watchScopePaths;
30
30
  #isForBundle;
31
31
  constructor(opt) {
32
32
  this.#pkgPath = opt.pkgPath;
33
33
  this.#globalStyleFilePath = opt.globalStyleFilePath != null ? path.normalize(opt.globalStyleFilePath) : undefined;
34
34
  this.#isForBundle = opt.isForBundle;
35
+ this.#watchScopePaths = opt.watchScopePaths;
35
36
  this.#debug("초기화...");
36
37
  //-- isForAngular / parsedTsConfig
37
38
  const tsconfigPath = path.resolve(opt.pkgPath, "tsconfig.json");
@@ -125,56 +126,58 @@ export class SdTsCompiler {
125
126
  return stylesheetResult.contents;
126
127
  }
127
128
  invalidate(modifiedFileSet) {
128
- for (const modifiedFile of Array.from(modifiedFileSet).map((item) => path.normalize(item))) {
129
- this.#modifiedFileSet.add(modifiedFile);
130
- this.#modifiedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
131
- }
129
+ this.#modifiedFileSet.adds(...Array.from(modifiedFileSet).map((item) => path.normalize(item)));
132
130
  }
133
131
  async buildAsync() {
134
- const affectedSourceFileSet = new Set();
132
+ let perf = new SdCliPerformanceTimer("esbuild");
133
+ const affectedFileSet = new Set();
135
134
  const emitFileSet = new Set();
136
135
  this.#debug(`get affected (old deps & old res deps)...`);
137
- for (const modifiedFile of this.#modifiedFileSet) {
138
- // affectedFileSet.add(modifiedFile);
139
- // affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
140
- // affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
141
- this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
142
- this.#sourceFileCacheMap.delete(path.normalize(modifiedFile));
143
- this.#stylesheetBundlingResultMap.delete(path.normalize(modifiedFile));
144
- this.#watchFileSet.delete(path.normalize(modifiedFile));
145
- }
146
- this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
147
- // this.#debug(`invalidate & clear cache...`);
148
- // this.#stylesheetBundler?.invalidate(affectedFileSet);
149
- // for (const affectedFile of affectedFileSet) {
150
- // this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
151
- // this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
152
- // this.#watchFileSet.delete(path.normalize(affectedFile));
153
- // }
154
- // this.#revDependencyCacheMap.clear();
155
- this.#resourceDependencyCacheMap.clear();
136
+ perf.run("get affected", () => {
137
+ for (const modifiedFile of this.#modifiedFileSet) {
138
+ affectedFileSet.add(modifiedFile);
139
+ affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
140
+ affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
141
+ this.#emittedFilesCacheMap.delete(path.normalize(modifiedFile));
142
+ }
143
+ });
144
+ this.#debug(`invalidate & clear cache...`);
145
+ perf.run("invalidate & clear cache", () => {
146
+ this.#stylesheetBundler?.invalidate(this.#modifiedFileSet);
147
+ for (const affectedFile of affectedFileSet) {
148
+ this.#sourceFileCacheMap.delete(path.normalize(affectedFile));
149
+ this.#stylesheetBundlingResultMap.delete(path.normalize(affectedFile));
150
+ this.#watchFileSet.delete(path.normalize(affectedFile));
151
+ }
152
+ this.#revDependencyCacheMap.clear();
153
+ this.#resourceDependencyCacheMap.clear();
154
+ });
156
155
  this.#debug(`create program...`);
157
- if (this.#isForAngular) {
158
- this.#ngProgram = new NgtscProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#ngProgram);
159
- this.#program = this.#ngProgram.getTsProgram();
160
- }
161
- else {
162
- this.#program = ts.createProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#program);
163
- }
164
- this.#debug(`create builder...`);
165
- const baseGetSourceFiles = this.#program.getSourceFiles;
156
+ perf.run("create program", () => {
157
+ if (this.#isForAngular) {
158
+ this.#ngProgram = new NgtscProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#ngProgram);
159
+ this.#program = this.#ngProgram.getTsProgram();
160
+ }
161
+ else {
162
+ this.#program = ts.createProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#program);
163
+ }
164
+ });
165
+ /*const baseGetSourceFiles = this.#program.getSourceFiles;
166
166
  this.#program.getSourceFiles = function (...parameters) {
167
- const files = baseGetSourceFiles(...parameters);
168
- for (const file of files) {
169
- if (file.version === undefined) {
170
- file.version = createHash("sha256").update(file.text).digest("hex");
171
- }
167
+ const files: readonly (ts.SourceFile & { version?: string })[] = baseGetSourceFiles(...parameters);
168
+
169
+ for (const file of files) {
170
+ if (file.version === undefined) {
171
+ file.version = createHash("sha256").update(file.text).digest("hex");
172
172
  }
173
- return files;
174
- };
175
- this.#builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(this.#program, this.#compilerHost, this.#builder);
173
+ }
174
+
175
+ return files;
176
+ };*/
176
177
  if (this.#ngProgram) {
177
- await this.#ngProgram.compiler.analyzeAsync();
178
+ await perf.run("ng analyze", async () => {
179
+ await this.#ngProgram.compiler.analyzeAsync();
180
+ });
178
181
  }
179
182
  const getOrgSourceFile = (sf) => {
180
183
  if (sf.fileName.endsWith(".ngtypecheck.ts")) {
@@ -184,310 +187,219 @@ export class SdTsCompiler {
184
187
  return sf;
185
188
  };
186
189
  this.#debug(`get affected (new deps)...`);
187
- // const sourceFileSet = new Set(
188
- // this.#program
189
- // .getSourceFiles()
190
- // .map((sf) => getOrgSourceFile(sf))
191
- // .filterExists(),
192
- // );
193
- // const depMap = new Map<
194
- // string,
195
- // {
196
- // fileName: string;
197
- // importName: string;
198
- // exportName?: string;
199
- // }[]
200
- // >();
201
- // for (const sf of sourceFileSet) {
202
- // const refs = this.#findDeps(sf);
203
- // depMap.set(path.normalize(sf.fileName), refs);
204
- // }
205
- //
206
- // const allDepMap = new Map<string, Set<string>>();
207
- // const getAllDeps = (fileName: string, prevSet?: Set<string>) => {
208
- // if (allDepMap.has(fileName)) {
209
- // return allDepMap.get(fileName)!;
210
- // }
211
- //
212
- // const result = new Set<string>();
213
- //
214
- // const deps = depMap.get(fileName) ?? [];
215
- // result.adds(...deps.map((item) => item.fileName));
216
- //
217
- // for (const dep of deps) {
218
- // const targetDeps = depMap.get(dep.fileName) ?? [];
219
- //
220
- // if (dep.importName === "*") {
221
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
222
- // if (prevSet?.has(targetRefItem.fileName)) continue;
223
- //
224
- // result.add(targetRefItem.fileName);
225
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
226
- // }
227
- // } else {
228
- // for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
229
- // if (prevSet?.has(targetRefItem.fileName)) continue;
230
- //
231
- // result.add(targetRefItem.fileName);
232
- // result.adds(...getAllDeps(targetRefItem.fileName, new Set<string>(prevSet).adds(...result)));
233
- // }
234
- // }
235
- // }
236
- //
237
- // return result;
238
- // };
239
- // for (const sf of sourceFileSet) {
240
- // const deps = getAllDeps(path.normalize(sf.fileName));
241
- // allDepMap.set(path.normalize(sf.fileName), deps);
242
- //
243
- // for (const dep of getAllDeps(path.normalize(sf.fileName))) {
244
- // const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
245
- // depCache.add(path.normalize(sf.fileName));
246
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
247
- // affectedFileSet.add(path.normalize(sf.fileName));
248
- // }
249
- // }
250
- //
251
- // if (this.#ngProgram) {
252
- // if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
253
- // continue;
254
- // }
255
- //
256
- // for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
257
- // const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set<string>());
258
- // ref.add(path.normalize(sf.fileName));
259
- // if (this.#modifiedFileSet.has(path.normalize(dep))) {
260
- // affectedFileSet.add(path.normalize(sf.fileName));
261
- // }
262
- // }
263
- // }
264
- // }
265
- // if (affectedFileSet.size === 0) {
266
- // this.#debug(`get affected (init)...`);
267
- //
268
- // for (const sf of this.#program.getSourceFiles()) {
269
- // const orgSf = getOrgSourceFile(sf);
270
- // if (!orgSf) continue;
271
- //
272
- // affectedFileSet.add(path.normalize(orgSf.fileName));
273
- // }
274
- // }
275
- this.#debug(`get diagnostics...`);
276
190
  const diagnostics = [];
277
- diagnostics.push(...this.#builder.getConfigFileParsingDiagnostics(), ...this.#builder.getOptionsDiagnostics(), ...this.#builder.getGlobalDiagnostics());
278
- /*diagnostics.push(
279
- ...this.#program.getConfigFileParsingDiagnostics(),
280
- ...this.#program.getOptionsDiagnostics(),
281
- ...this.#program.getGlobalDiagnostics(),
282
- );*/
283
- if (this.#ngProgram) {
284
- diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
285
- }
286
- this.#debug(`get diagnostics of files...`);
287
- while (true) {
288
- const affectedFileResult = this.#builder.getSemanticDiagnosticsOfNextAffectedFile(undefined, (sf) => {
289
- if (this.#ngProgram &&
290
- this.#ngProgram.compiler.ignoreForDiagnostics.has(sf) &&
291
- sf.fileName.endsWith(".ngtypecheck.ts")) {
292
- const orgSourceFile = getOrgSourceFile(sf);
293
- if (orgSourceFile) {
294
- affectedSourceFileSet.add(orgSourceFile);
295
- }
296
- return true;
297
- }
298
- return false;
299
- });
300
- if (!affectedFileResult)
301
- break;
302
- const affectedSourceFile = affectedFileResult.affected;
303
- affectedSourceFileSet.add(affectedSourceFile);
304
- }
305
- for (const affectedSourceFile of affectedSourceFileSet) {
306
- this.#debug(`get diagnostics of file [${affectedSourceFile.fileName}]`);
307
- diagnostics.push(...this.#program.getSyntacticDiagnostics(affectedSourceFile), ...this.#program.getSemanticDiagnostics(affectedSourceFile));
308
- if (this.#ngProgram) {
309
- if (affectedSourceFile.isDeclarationFile) {
191
+ perf.run("get affected (deps)", () => {
192
+ const sourceFileSet = new Set(this.#program.getSourceFiles()
193
+ .map((sf) => getOrgSourceFile(sf))
194
+ .filterExists());
195
+ const depMap = new Map();
196
+ for (const sf of sourceFileSet) {
197
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
310
198
  continue;
311
199
  }
312
- diagnostics.push(...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
200
+ const refs = this.#findDeps(sf);
201
+ diagnostics.push(...refs.filter((item) => "category" in item));
202
+ depMap.set(path.normalize(sf.fileName), refs
203
+ .filter((item) => "fileName" in item)
204
+ .filter((item) => this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(item.fileName, scopePath))));
313
205
  }
314
- }
315
- /*
316
- for (const affectedFile of affectedFileSet) {
317
- if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
318
- continue;
319
- }
320
-
321
- this.#debug(`get diagnostics of file [${affectedFile}]`);
322
-
323
- const affectedSourceFile = this.#program.getSourceFile(affectedFile);
324
- if (
325
- !affectedSourceFile ||
326
- (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
327
- ) {
328
- continue;
329
- }
330
-
331
- diagnostics.push(
332
- ...this.#program.getSyntacticDiagnostics(affectedSourceFile),
333
- ...this.#program.getSemanticDiagnostics(affectedSourceFile),
334
- );
335
-
336
- if (this.#ngProgram) {
337
- if (affectedSourceFile.isDeclarationFile) {
338
- continue;
339
- }
340
-
341
- diagnostics.push(
342
- ...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
343
- );
344
- }
345
- }*/
346
- this.#debug(`prepare emit...`);
347
- let transformers = {};
348
- if (this.#ngProgram) {
349
- transformers = {
350
- ...transformers,
351
- ...this.#ngProgram.compiler.prepareEmit().transformers,
206
+ const allDepMap = new Map();
207
+ const getAllDeps = (fileName, prevSet) => {
208
+ if (allDepMap.has(fileName)) {
209
+ return allDepMap.get(fileName);
210
+ }
211
+ const result = new Set();
212
+ const deps = depMap.get(fileName) ?? [];
213
+ result.adds(...deps.map((item) => item.fileName));
214
+ for (const dep of deps) {
215
+ const targetDeps = depMap.get(dep.fileName) ?? [];
216
+ if (dep.importName === "*") {
217
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
218
+ if (prevSet?.has(targetRefItem.fileName))
219
+ continue;
220
+ result.add(targetRefItem.fileName);
221
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
222
+ }
223
+ }
224
+ else {
225
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
226
+ if (prevSet?.has(targetRefItem.fileName))
227
+ continue;
228
+ result.add(targetRefItem.fileName);
229
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
230
+ }
231
+ }
232
+ }
233
+ return result;
352
234
  };
353
- (transformers.before ??= []).push(replaceBootstrap(() => this.#program.getTypeChecker()));
354
- }
355
- // (transformers.before ??= []).push(transformKeys(this.#program));
356
- this.#debug(`prepare emit files...`);
357
- while (this.#builder.emitNextAffectedFile((fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
358
- if (!sourceFiles || sourceFiles.length === 0) {
359
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
360
- return;
361
- }
362
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
363
- if (this.#ngProgram) {
364
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
365
- return;
235
+ for (const sf of sourceFileSet) {
236
+ const deps = getAllDeps(path.normalize(sf.fileName));
237
+ allDepMap.set(path.normalize(sf.fileName), deps);
238
+ for (const dep of getAllDeps(path.normalize(sf.fileName))) {
239
+ const depCache = this.#revDependencyCacheMap.getOrCreate(path.normalize(dep), new Set());
240
+ depCache.add(path.normalize(sf.fileName));
241
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
242
+ affectedFileSet.add(path.normalize(sf.fileName));
243
+ }
244
+ }
245
+ if (this.#ngProgram) {
246
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
247
+ continue;
248
+ }
249
+ for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
250
+ const ref = this.#resourceDependencyCacheMap.getOrCreate(path.normalize(dep), new Set());
251
+ ref.add(path.normalize(sf.fileName));
252
+ if (this.#modifiedFileSet.has(path.normalize(dep))) {
253
+ affectedFileSet.add(path.normalize(sf.fileName));
254
+ }
255
+ }
366
256
  }
367
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
368
257
  }
369
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
370
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
371
- let realFilePath = fileName;
372
- let realText = text;
373
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
374
- realFilePath = path.resolve(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
375
- if (fileName.endsWith(".js.map")) {
376
- const sourceMapContents = JSON.parse(realText);
377
- // remove "../../"
378
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
379
- realText = JSON.stringify(sourceMapContents);
258
+ });
259
+ if (affectedFileSet.size === 0) {
260
+ this.#debug(`get affected (init)...`);
261
+ perf.run("get affected (init)", () => {
262
+ for (const sf of this.#program.getSourceFiles()) {
263
+ if (!this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(sf.fileName, scopePath))) {
264
+ continue;
380
265
  }
266
+ const orgSf = getOrgSourceFile(sf);
267
+ if (!orgSf)
268
+ continue;
269
+ affectedFileSet.add(path.normalize(orgSf.fileName));
381
270
  }
382
- emitFileInfoCaches.push({
383
- outAbsPath: realFilePath,
384
- text: realText,
385
- });
271
+ });
272
+ }
273
+ this.#debug(`get diagnostics...`);
274
+ perf.run("get program diagnostics", () => {
275
+ diagnostics.push(...this.#program.getConfigFileParsingDiagnostics(), ...this.#program.getOptionsDiagnostics(), ...this.#program.getGlobalDiagnostics());
276
+ if (this.#ngProgram) {
277
+ diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
386
278
  }
387
- else {
388
- emitFileInfoCaches.push({ text });
279
+ });
280
+ this.#debug(`get diagnostics of files...`);
281
+ perf.run("get file diagnostics", () => {
282
+ for (const affectedFile of affectedFileSet) {
283
+ if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
284
+ continue;
285
+ }
286
+ const affectedSourceFile = this.#program.getSourceFile(affectedFile);
287
+ if (!affectedSourceFile ||
288
+ (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
289
+ continue;
290
+ }
291
+ // this.#debug(`get diagnostics of file ${affectedFile}...`);
292
+ diagnostics.push(...this.#program.getSyntacticDiagnostics(affectedSourceFile), ...this.#program.getSemanticDiagnostics(affectedSourceFile));
293
+ if (this.#ngProgram) {
294
+ perf.run("get file diagnostics: ng", () => {
295
+ if (affectedSourceFile.isDeclarationFile) {
296
+ return;
297
+ }
298
+ diagnostics.push(...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
299
+ });
300
+ }
389
301
  }
390
- emitFileSet.add(path.normalize(sourceFile.fileName));
391
- }, undefined, undefined, transformers)) { }
392
- // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
393
- // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
394
- /*for (const affectedFile of affectedFileSet) {
395
- if (this.#emittedFilesCacheMap.has(affectedFile)) {
396
- continue;
397
- }
398
-
399
- const sf = this.#program.getSourceFile(affectedFile);
400
- if (!sf) {
401
- continue;
402
- }*/
403
- /*for (const sf of sourceFileSet) {
404
- if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
405
- continue;
406
- }
407
-
408
- if (sf.isDeclarationFile) {
409
- continue;
410
- }
411
-
412
- if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
413
- continue;
414
- }
415
-
416
- // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
417
- if (!this.#isForBundle) {
418
- if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
419
- continue;
302
+ });
303
+ perf.run("emit", () => {
304
+ this.#debug(`prepare emit...`);
305
+ let transformers = {};
306
+ if (this.#ngProgram) {
307
+ transformers = {
308
+ ...transformers,
309
+ ...this.#ngProgram.compiler.prepareEmit().transformers,
310
+ };
311
+ (transformers.before ??= []).push(replaceBootstrap(() => this.#program.getTypeChecker()));
420
312
  }
421
- }
422
-
423
- this.#debug(`emit for`, sf.fileName);
424
- this.#program.emit(
425
- sf,
426
- (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
427
- if (!sourceFiles || sourceFiles.length === 0) {
428
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
429
- return;
430
- }
431
-
432
- const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
433
- if (this.#ngProgram) {
434
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
435
- return;
313
+ // (transformers.before ??= []).push(transformKeys(this.#program));
314
+ this.#debug(`emit for files...`);
315
+ // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 getSourceFiles로 바꿈
316
+ // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
317
+ // 그래도 affected로 다시 테스트
318
+ for (const affectedFile of affectedFileSet) {
319
+ if (this.#emittedFilesCacheMap.has(affectedFile)) {
320
+ continue;
436
321
  }
437
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
438
- }
439
-
440
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
441
- if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
442
- let realFilePath = fileName;
443
- let realText = text;
444
- if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
445
- realFilePath = path.resolve(
446
- this.#distPath,
447
- path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
448
- );
449
-
450
- if (fileName.endsWith(".js.map")) {
451
- const sourceMapContents = JSON.parse(realText);
452
- // remove "../../"
453
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
454
- realText = JSON.stringify(sourceMapContents);
455
- }
322
+ const sf = this.#program.getSourceFile(affectedFile);
323
+ if (!sf) {
324
+ continue;
456
325
  }
457
-
458
- emitFileInfoCaches.push({
459
- outAbsPath: realFilePath,
460
- text: realText,
461
- });
462
- } else {
463
- emitFileInfoCaches.push({ text });
464
- }
465
-
466
- emitFileSet.add(path.normalize(sourceFile.fileName));
467
- },
468
- undefined,
469
- undefined,
470
- transformers,
471
- );
472
- }*/
326
+ // for (const sf of sourceFileSet) {
327
+ /*if (this.#emittedFilesCacheMap.has(path.normalize(sf.fileName))) {
328
+ continue;
329
+ }*/
330
+ if (sf.isDeclarationFile) {
331
+ continue;
332
+ }
333
+ if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
334
+ continue;
335
+ }
336
+ if (this.#ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf) &&
337
+ !affectedFileSet.has(path.normalize(sf.fileName))) {
338
+ continue;
339
+ }
340
+ // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
341
+ if (!this.#isForBundle) {
342
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
343
+ continue;
344
+ }
345
+ }
346
+ // this.#debug(`emit for`, sf.fileName);
347
+ this.#program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
348
+ if (!sourceFiles || sourceFiles.length === 0) {
349
+ this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
350
+ return;
351
+ }
352
+ const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
353
+ if (this.#ngProgram) {
354
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
355
+ return;
356
+ }
357
+ this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
358
+ }
359
+ const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(path.normalize(sourceFile.fileName), []);
360
+ if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
361
+ let realFilePath = fileName;
362
+ let realText = text;
363
+ if (PathUtil.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
364
+ realFilePath = path.resolve(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
365
+ if (fileName.endsWith(".js.map")) {
366
+ const sourceMapContents = JSON.parse(realText);
367
+ // remove "../../"
368
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
369
+ realText = JSON.stringify(sourceMapContents);
370
+ }
371
+ }
372
+ emitFileInfoCaches.push({
373
+ outAbsPath: realFilePath,
374
+ text: realText,
375
+ });
376
+ }
377
+ else {
378
+ emitFileInfoCaches.push({ text });
379
+ }
380
+ emitFileSet.add(path.normalize(sourceFile.fileName));
381
+ }, undefined, undefined, transformers);
382
+ }
383
+ });
473
384
  //-- global style
474
385
  if (this.#globalStyleFilePath != null &&
475
386
  FsUtil.exists(this.#globalStyleFilePath) &&
476
387
  !this.#emittedFilesCacheMap.has(this.#globalStyleFilePath)) {
477
388
  this.#debug(`bundle global style...`);
478
- const data = await FsUtil.readFileAsync(this.#globalStyleFilePath);
479
- const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
480
- const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath, []);
481
- emitFileInfos.push({
482
- outAbsPath: path.resolve(this.#pkgPath, path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath).replace(/\.scss$/, ".css")),
483
- text: contents,
389
+ await perf.run("bundle global style", async () => {
390
+ const data = await FsUtil.readFileAsync(this.#globalStyleFilePath);
391
+ const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
392
+ const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath, []);
393
+ emitFileInfos.push({
394
+ outAbsPath: path.resolve(this.#pkgPath, path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath).replace(/\.scss$/, ".css")),
395
+ text: contents,
396
+ });
397
+ emitFileSet.add(this.#globalStyleFilePath);
484
398
  });
485
- emitFileSet.add(this.#globalStyleFilePath);
486
399
  }
487
400
  //-- init
488
401
  this.#modifiedFileSet.clear();
489
- const affectedFileSet = new Set(Array.from(affectedSourceFileSet).map((item) => path.normalize(item.fileName)));
490
- this.#debug(`build completed`, affectedFileSet, diagnostics.length);
402
+ this.#debug(`build completed`, perf.toString());
491
403
  //-- result
492
404
  return {
493
405
  program: this.#program,
@@ -502,5 +414,121 @@ export class SdTsCompiler {
502
414
  #debug(...msg) {
503
415
  this.#logger.debug(`[${path.basename(this.#pkgPath)}]`, ...msg);
504
416
  }
417
+ #findDeps(sf) {
418
+ const deps = [];
419
+ const tc = this.#program.getTypeChecker();
420
+ sf.forEachChild((node) => {
421
+ if (ts.isExportDeclaration(node)) {
422
+ if (node.moduleSpecifier) {
423
+ const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
424
+ if (!moduleSymbol) {
425
+ deps.push({
426
+ category: DiagnosticCategory.Error,
427
+ code: -1,
428
+ file: sf,
429
+ start: node.getStart(),
430
+ length: node.getEnd() - node.getStart(),
431
+ messageText: `export moduleSymbol not found`,
432
+ });
433
+ return;
434
+ }
435
+ const decls = moduleSymbol.getDeclarations();
436
+ if (!decls) {
437
+ deps.push({
438
+ category: DiagnosticCategory.Error,
439
+ code: -1,
440
+ file: sf,
441
+ start: node.getStart(),
442
+ length: node.getEnd() - node.getStart(),
443
+ messageText: `export decls not found`,
444
+ });
445
+ return;
446
+ }
447
+ const namedBindings = node.exportClause;
448
+ if (namedBindings && ts.isNamedExports(namedBindings)) {
449
+ for (const el of namedBindings.elements) {
450
+ for (const decl of decls) {
451
+ deps.push({
452
+ fileName: path.normalize(decl.getSourceFile().fileName),
453
+ importName: el.name.text,
454
+ exportName: el.propertyName?.text ?? el.name.text,
455
+ });
456
+ }
457
+ }
458
+ }
459
+ else {
460
+ if (!moduleSymbol.exports) {
461
+ deps.push({
462
+ category: DiagnosticCategory.Error,
463
+ code: -1,
464
+ file: sf,
465
+ start: node.getStart(),
466
+ length: node.getEnd() - node.getStart(),
467
+ messageText: `moduleSymbol exports not found`,
468
+ });
469
+ return;
470
+ }
471
+ for (const decl of decls) {
472
+ for (const key of moduleSymbol.exports.keys()) {
473
+ deps.push({
474
+ fileName: path.normalize(decl.getSourceFile().fileName),
475
+ importName: key.toString(),
476
+ exportName: key.toString(),
477
+ });
478
+ }
479
+ }
480
+ }
481
+ }
482
+ }
483
+ else if (ts.isImportDeclaration(node)) {
484
+ const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
485
+ if (!moduleSymbol) {
486
+ if (ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text.startsWith("./")) {
487
+ deps.push({
488
+ fileName: path.normalize(path.resolve(path.dirname(sf.fileName), node.moduleSpecifier.text)),
489
+ importName: "*",
490
+ });
491
+ }
492
+ /*else {
493
+ throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
494
+ }*/
495
+ }
496
+ else {
497
+ const decls = moduleSymbol.getDeclarations();
498
+ if (!decls) {
499
+ deps.push({
500
+ category: DiagnosticCategory.Error,
501
+ code: -1,
502
+ file: sf,
503
+ start: node.getStart(),
504
+ length: node.getEnd() - node.getStart(),
505
+ messageText: `import decls not found`,
506
+ });
507
+ return;
508
+ }
509
+ const namedBindings = node.importClause?.namedBindings;
510
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
511
+ for (const el of namedBindings.elements) {
512
+ for (const decl of decls) {
513
+ deps.push({
514
+ fileName: path.normalize(decl.getSourceFile().fileName),
515
+ importName: el.name.text,
516
+ });
517
+ }
518
+ }
519
+ }
520
+ else {
521
+ for (const decl of decls) {
522
+ deps.push({
523
+ fileName: path.normalize(decl.getSourceFile().fileName),
524
+ importName: "*",
525
+ });
526
+ }
527
+ }
528
+ }
529
+ }
530
+ });
531
+ return deps;
532
+ }
505
533
  }
506
534
  //# sourceMappingURL=SdTsCompiler.js.map