@simplysm/sd-cli 12.5.21 → 12.5.23

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 (195) hide show
  1. package/dist/{build-tools → entry}/SdCliCordova.d.ts +5 -6
  2. package/dist/{build-tools → entry}/SdCliCordova.js +117 -99
  3. package/dist/entry/SdCliCordova.js.map +1 -0
  4. package/dist/entry/SdCliElectron.d.ts +2 -2
  5. package/dist/entry/SdCliElectron.js +50 -40
  6. package/dist/entry/SdCliElectron.js.map +1 -1
  7. package/dist/entry/SdCliLocalUpdate.d.ts +1 -2
  8. package/dist/entry/SdCliLocalUpdate.js +26 -27
  9. package/dist/entry/SdCliLocalUpdate.js.map +1 -1
  10. package/dist/entry/SdCliProject.d.ts +1 -5
  11. package/dist/entry/SdCliProject.js +62 -288
  12. package/dist/entry/SdCliProject.js.map +1 -1
  13. package/dist/index.d.ts +23 -20
  14. package/dist/index.js +23 -20
  15. package/dist/index.js.map +1 -1
  16. package/dist/pkg-builders/SdMultiBuildRunner.d.ts +21 -0
  17. package/dist/pkg-builders/SdMultiBuildRunner.js +174 -0
  18. package/dist/pkg-builders/SdMultiBuildRunner.js.map +1 -0
  19. package/dist/pkg-builders/client/SdCliNgRoutesFileGenerator.d.ts +4 -0
  20. package/dist/{build-tools → pkg-builders/client}/SdCliNgRoutesFileGenerator.js +7 -7
  21. package/dist/pkg-builders/client/SdCliNgRoutesFileGenerator.js.map +1 -0
  22. package/dist/pkg-builders/client/SdClientBuildRunner.d.ts +20 -0
  23. package/dist/pkg-builders/client/SdClientBuildRunner.js +135 -0
  24. package/dist/pkg-builders/client/SdClientBuildRunner.js.map +1 -0
  25. package/dist/pkg-builders/client/SdNgBundler.d.ts +29 -0
  26. package/dist/{build-tools → pkg-builders/client}/SdNgBundler.js +107 -151
  27. package/dist/pkg-builders/client/SdNgBundler.js.map +1 -0
  28. package/dist/{build-tools → pkg-builders/client}/SdNgBundlerContext.d.ts +1 -2
  29. package/dist/{build-tools → pkg-builders/client}/SdNgBundlerContext.js +19 -45
  30. package/dist/pkg-builders/client/SdNgBundlerContext.js.map +1 -0
  31. package/dist/pkg-builders/client/createSdNgPlugin.d.ts +10 -0
  32. package/dist/{bundle-plugins/sdNgPlugin.js → pkg-builders/client/createSdNgPlugin.js} +32 -33
  33. package/dist/pkg-builders/client/createSdNgPlugin.js.map +1 -0
  34. package/dist/pkg-builders/lib/SdCliIndexFileGenerator.d.ts +5 -0
  35. package/dist/{build-tools → pkg-builders/lib}/SdCliIndexFileGenerator.js +11 -11
  36. package/dist/pkg-builders/lib/SdCliIndexFileGenerator.js.map +1 -0
  37. package/dist/pkg-builders/lib/SdJsLibBuildRunner.d.ts +16 -0
  38. package/dist/pkg-builders/lib/SdJsLibBuildRunner.js +81 -0
  39. package/dist/pkg-builders/lib/SdJsLibBuildRunner.js.map +1 -0
  40. package/dist/pkg-builders/lib/SdTsLibBuildRunner.d.ts +13 -0
  41. package/dist/pkg-builders/lib/SdTsLibBuildRunner.js +89 -0
  42. package/dist/pkg-builders/lib/SdTsLibBuildRunner.js.map +1 -0
  43. package/dist/pkg-builders/lib/SdTsLibBuilder.d.ts +14 -0
  44. package/dist/pkg-builders/lib/SdTsLibBuilder.js +54 -0
  45. package/dist/pkg-builders/lib/SdTsLibBuilder.js.map +1 -0
  46. package/dist/pkg-builders/server/SdServerBuildRunner.d.ts +17 -0
  47. package/dist/{builders/SdCliServerBuilder.js → pkg-builders/server/SdServerBuildRunner.js} +48 -53
  48. package/dist/pkg-builders/server/SdServerBuildRunner.js.map +1 -0
  49. package/dist/pkg-builders/server/SdServerBundler.d.ts +19 -0
  50. package/dist/{build-tools → pkg-builders/server}/SdServerBundler.js +25 -30
  51. package/dist/pkg-builders/server/SdServerBundler.js.map +1 -0
  52. package/dist/pkg-builders/server/createSdServerPlugin.d.ts +10 -0
  53. package/dist/pkg-builders/server/createSdServerPlugin.js +53 -0
  54. package/dist/pkg-builders/server/createSdServerPlugin.js.map +1 -0
  55. package/dist/sd-cli.js +61 -54
  56. package/dist/sd-cli.js.map +1 -1
  57. package/dist/ts-builder/SdTsCompileWorker.d.ts +9 -0
  58. package/dist/ts-builder/SdTsCompileWorker.js +16 -0
  59. package/dist/ts-builder/SdTsCompileWorker.js.map +1 -0
  60. package/dist/ts-builder/SdTsCompiler.d.ts +7 -0
  61. package/dist/ts-builder/SdTsCompiler.js +557 -0
  62. package/dist/ts-builder/SdTsCompiler.js.map +1 -0
  63. package/dist/types/build-plugin.type.d.ts +14 -0
  64. package/dist/types/build-plugin.type.js +2 -0
  65. package/dist/types/build-plugin.type.js.map +1 -0
  66. package/dist/types/build.type.d.ts +15 -0
  67. package/dist/types/build.type.js +2 -0
  68. package/dist/types/build.type.js.map +1 -0
  69. package/dist/types/common-configs.type.d.ts +22 -0
  70. package/dist/types/common-configs.type.js +2 -0
  71. package/dist/types/common-configs.type.js.map +1 -0
  72. package/dist/types/sd-configs.type.d.ts +99 -0
  73. package/dist/types/sd-configs.type.js +2 -0
  74. package/dist/types/sd-configs.type.js.map +1 -0
  75. package/dist/types/ts-compiler.type.d.ts +29 -0
  76. package/dist/types/ts-compiler.type.js +2 -0
  77. package/dist/types/ts-compiler.type.js.map +1 -0
  78. package/dist/types/workers.type.d.ts +49 -0
  79. package/dist/types/workers.type.js +2 -0
  80. package/dist/types/workers.type.js.map +1 -0
  81. package/dist/utils/SdCliConvertMessageUtil.d.ts +21 -0
  82. package/dist/utils/SdCliConvertMessageUtil.js +137 -0
  83. package/dist/utils/SdCliConvertMessageUtil.js.map +1 -0
  84. package/dist/workers/compile-worker.js +27 -0
  85. package/dist/workers/compile-worker.js.map +1 -0
  86. package/dist/workers/lint-worker.js +36 -0
  87. package/dist/workers/lint-worker.js.map +1 -0
  88. package/dist/workers/server-worker.d.ts +1 -0
  89. package/dist/workers/server-worker.js +49 -0
  90. package/dist/workers/server-worker.js.map +1 -0
  91. package/package.json +8 -11
  92. package/src/entry/SdCliCordova.ts +363 -0
  93. package/src/entry/SdCliElectron.ts +96 -69
  94. package/src/entry/SdCliLocalUpdate.ts +43 -44
  95. package/src/entry/SdCliProject.ts +72 -417
  96. package/src/index.ts +23 -20
  97. package/src/pkg-builders/SdMultiBuildRunner.ts +250 -0
  98. package/src/{build-tools → pkg-builders/client}/SdCliNgRoutesFileGenerator.ts +7 -7
  99. package/src/pkg-builders/client/SdClientBuildRunner.ts +191 -0
  100. package/src/{build-tools → pkg-builders/client}/SdNgBundler.ts +135 -190
  101. package/src/pkg-builders/client/SdNgBundlerContext.ts +111 -0
  102. package/src/{bundle-plugins/sdNgPlugin.ts → pkg-builders/client/createSdNgPlugin.ts} +43 -46
  103. package/src/{build-tools → pkg-builders/lib}/SdCliIndexFileGenerator.ts +11 -11
  104. package/src/pkg-builders/lib/SdJsLibBuildRunner.ts +105 -0
  105. package/src/pkg-builders/lib/SdTsLibBuildRunner.ts +128 -0
  106. package/src/pkg-builders/lib/SdTsLibBuilder.ts +69 -0
  107. package/src/{builders/SdCliServerBuilder.ts → pkg-builders/server/SdServerBuildRunner.ts} +66 -78
  108. package/src/{build-tools → pkg-builders/server}/SdServerBundler.ts +40 -41
  109. package/src/pkg-builders/server/createSdServerPlugin.ts +77 -0
  110. package/src/sd-cli.ts +197 -211
  111. package/src/ts-builder/SdTsCompileWorker.ts +21 -0
  112. package/src/ts-builder/SdTsCompiler.ts +775 -0
  113. package/src/types/build-plugin.type.ts +16 -0
  114. package/src/types/build.type.ts +17 -0
  115. package/src/types/common-configs.type.ts +27 -0
  116. package/src/types/sd-configs.type.ts +114 -0
  117. package/src/types/ts-compiler.type.ts +29 -0
  118. package/src/types/workers.type.ts +27 -0
  119. package/src/utils/SdCliConvertMessageUtil.ts +177 -0
  120. package/src/workers/compile-worker.ts +31 -0
  121. package/src/workers/lint-worker.ts +44 -0
  122. package/src/workers/server-worker.ts +52 -0
  123. package/tsconfig.json +7 -1
  124. package/dist/build-cluster.js +0 -201
  125. package/dist/build-cluster.js.map +0 -1
  126. package/dist/build-tools/SdCliCordova.js.map +0 -1
  127. package/dist/build-tools/SdCliIndexFileGenerator.d.ts +0 -5
  128. package/dist/build-tools/SdCliIndexFileGenerator.js.map +0 -1
  129. package/dist/build-tools/SdCliNgRoutesFileGenerator.d.ts +0 -4
  130. package/dist/build-tools/SdCliNgRoutesFileGenerator.js.map +0 -1
  131. package/dist/build-tools/SdLinter.d.ts +0 -5
  132. package/dist/build-tools/SdLinter.js +0 -49
  133. package/dist/build-tools/SdLinter.js.map +0 -1
  134. package/dist/build-tools/SdNgBundler.d.ts +0 -29
  135. package/dist/build-tools/SdNgBundler.js.map +0 -1
  136. package/dist/build-tools/SdNgBundlerContext.js.map +0 -1
  137. package/dist/build-tools/SdReactBundler.d.ts +0 -25
  138. package/dist/build-tools/SdReactBundler.js +0 -295
  139. package/dist/build-tools/SdReactBundler.js.map +0 -1
  140. package/dist/build-tools/SdReactBundlerContext.d.ts +0 -14
  141. package/dist/build-tools/SdReactBundlerContext.js +0 -59
  142. package/dist/build-tools/SdReactBundlerContext.js.map +0 -1
  143. package/dist/build-tools/SdServerBundler.d.ts +0 -20
  144. package/dist/build-tools/SdServerBundler.js.map +0 -1
  145. package/dist/build-tools/SdTsCompiler.d.ts +0 -34
  146. package/dist/build-tools/SdTsCompiler.js +0 -534
  147. package/dist/build-tools/SdTsCompiler.js.map +0 -1
  148. package/dist/build-tools/SdTsLibBundler.d.ts +0 -13
  149. package/dist/build-tools/SdTsLibBundler.js +0 -58
  150. package/dist/build-tools/SdTsLibBundler.js.map +0 -1
  151. package/dist/builders/SdCliClientBuilder.d.ts +0 -18
  152. package/dist/builders/SdCliClientBuilder.js +0 -172
  153. package/dist/builders/SdCliClientBuilder.js.map +0 -1
  154. package/dist/builders/SdCliJsLibLinter.d.ts +0 -13
  155. package/dist/builders/SdCliJsLibLinter.js +0 -60
  156. package/dist/builders/SdCliJsLibLinter.js.map +0 -1
  157. package/dist/builders/SdCliServerBuilder.d.ts +0 -15
  158. package/dist/builders/SdCliServerBuilder.js.map +0 -1
  159. package/dist/builders/SdCliTsLibBuilder.d.ts +0 -12
  160. package/dist/builders/SdCliTsLibBuilder.js +0 -90
  161. package/dist/builders/SdCliTsLibBuilder.js.map +0 -1
  162. package/dist/bundle-plugins/sdNgPlugin.d.ts +0 -16
  163. package/dist/bundle-plugins/sdNgPlugin.js.map +0 -1
  164. package/dist/bundle-plugins/sdReactPlugin.d.ts +0 -16
  165. package/dist/bundle-plugins/sdReactPlugin.js +0 -117
  166. package/dist/bundle-plugins/sdReactPlugin.js.map +0 -1
  167. package/dist/bundle-plugins/sdServerPlugin.d.ts +0 -16
  168. package/dist/bundle-plugins/sdServerPlugin.js +0 -63
  169. package/dist/bundle-plugins/sdServerPlugin.js.map +0 -1
  170. package/dist/commons.d.ts +0 -145
  171. package/dist/commons.js +0 -2
  172. package/dist/commons.js.map +0 -1
  173. package/dist/server-worker.js +0 -57
  174. package/dist/server-worker.js.map +0 -1
  175. package/dist/utils/SdCliBuildResultUtil.d.ts +0 -16
  176. package/dist/utils/SdCliBuildResultUtil.js +0 -54
  177. package/dist/utils/SdCliBuildResultUtil.js.map +0 -1
  178. package/src/build-cluster.ts +0 -212
  179. package/src/build-tools/SdCliCordova.ts +0 -340
  180. package/src/build-tools/SdLinter.ts +0 -65
  181. package/src/build-tools/SdNgBundlerContext.ts +0 -137
  182. package/src/build-tools/SdReactBundler.ts +0 -372
  183. package/src/build-tools/SdReactBundlerContext.ts +0 -71
  184. package/src/build-tools/SdTsCompiler.ts +0 -754
  185. package/src/build-tools/SdTsLibBundler.ts +0 -72
  186. package/src/builders/SdCliClientBuilder.ts +0 -233
  187. package/src/builders/SdCliJsLibLinter.ts +0 -72
  188. package/src/builders/SdCliTsLibBuilder.ts +0 -126
  189. package/src/bundle-plugins/sdReactPlugin.ts +0 -164
  190. package/src/bundle-plugins/sdServerPlugin.ts +0 -94
  191. package/src/commons.ts +0 -171
  192. package/src/server-worker.ts +0 -65
  193. package/src/utils/SdCliBuildResultUtil.ts +0 -63
  194. /package/dist/{build-cluster.d.ts → workers/compile-worker.d.ts} +0 -0
  195. /package/dist/{server-worker.d.ts → workers/lint-worker.d.ts} +0 -0
@@ -0,0 +1,775 @@
1
+ import ts from "typescript";
2
+ import path from "path";
3
+ import { FsUtil, Logger, PathUtil, SdWorker, TNormPath } from "@simplysm/sd-core-node";
4
+ import { StringUtil } from "@simplysm/sd-core-common";
5
+ import { NgtscProgram, OptimizeFor } from "@angular/compiler-cli";
6
+ import { ComponentStylesheetBundler } from "@angular/build/src/tools/esbuild/angular/component-stylesheets";
7
+ import { AngularCompilerHost } from "@angular/build/src/tools/angular/angular-host";
8
+ import { transformSupportedBrowsersToTargets } from "@angular/build/src/tools/esbuild/utils";
9
+ import browserslist from "browserslist";
10
+ import { replaceBootstrap } from "@angular/build/src/tools/angular/transformers/jit-bootstrap-transformer";
11
+ import { SdCliPerformanceTimer } from "../utils/SdCliPerformanceTime";
12
+ import { SdCliConvertMessageUtil } from "../utils/SdCliConvertMessageUtil";
13
+ import { ISdTsCompilerResult, IStylesheetBundlingResult, SdTsCompilerOptions } from "../types/ts-compiler.type";
14
+ import { ISdBuildMessage } from "../types/build.type";
15
+ import { TSdLintWorkerType } from "../types/workers.type";
16
+
17
+ export class SdTsCompiler {
18
+ readonly #logger = Logger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
19
+
20
+ readonly #parsedTsconfig: ts.ParsedCommandLine;
21
+ readonly #isForAngular: boolean;
22
+
23
+ readonly #revDependencyCacheMap = new Map<TNormPath, Set<TNormPath>>();
24
+ readonly #resourceDependencyCacheMap = new Map<TNormPath, Set<TNormPath>>();
25
+ readonly #sourceFileCacheMap = new Map<TNormPath, ts.SourceFile>();
26
+ readonly #emittedFilesCacheMap = new Map<
27
+ TNormPath,
28
+ {
29
+ outAbsPath?: TNormPath;
30
+ text: string;
31
+ }[]
32
+ >();
33
+
34
+ readonly #stylesheetBundler: ComponentStylesheetBundler | undefined;
35
+ readonly #compilerHost: ts.CompilerHost | AngularCompilerHost;
36
+
37
+ #ngProgram: NgtscProgram | undefined;
38
+ #program: ts.Program | undefined;
39
+
40
+ #modifiedFileSet = new Set<TNormPath>();
41
+ #affectedFileSet = new Set<TNormPath>();
42
+
43
+ readonly #watchFileSet = new Set<TNormPath>();
44
+ readonly #stylesheetBundlingResultMap = new Map<TNormPath, IStylesheetBundlingResult>();
45
+
46
+ readonly #pkgPath: TNormPath;
47
+ readonly #distPath: TNormPath;
48
+ readonly #globalStyleFilePath?: TNormPath;
49
+ readonly #watchScopePaths: TNormPath[];
50
+
51
+ readonly #isForBundle: boolean;
52
+
53
+ readonly #lintWorker = new SdWorker<TSdLintWorkerType>(import.meta.resolve("../workers/lint-worker"));
54
+
55
+ constructor(opt: SdTsCompilerOptions) {
56
+ this.#pkgPath = opt.pkgPath;
57
+ this.#globalStyleFilePath = opt.globalStyleFilePath;
58
+ this.#isForBundle = opt.isForBundle;
59
+ this.#watchScopePaths = opt.watchScopePaths;
60
+
61
+ this.#debug("초기화...");
62
+
63
+ //-- isForAngular / parsedTsConfig
64
+
65
+ const tsconfigPath = path.resolve(opt.pkgPath, "tsconfig.json");
66
+ const tsconfig = FsUtil.readJson(tsconfigPath);
67
+ this.#isForAngular = Boolean(tsconfig.angularCompilerOptions);
68
+ this.#parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, opt.pkgPath, {
69
+ ...tsconfig.angularCompilerOptions,
70
+ ...opt.additionalOptions,
71
+ });
72
+
73
+ this.#distPath = PathUtil.norm(this.#parsedTsconfig.options.outDir ?? path.resolve(opt.pkgPath, "dist"));
74
+
75
+ //-- compilerHost
76
+
77
+ this.#compilerHost = ts.createCompilerHost(this.#parsedTsconfig.options);
78
+
79
+ const baseGetSourceFile = this.#compilerHost.getSourceFile;
80
+ this.#compilerHost.getSourceFile = (
81
+ fileName,
82
+ languageVersionOrOptions,
83
+ onError,
84
+ shouldCreateNewSourceFile,
85
+ ...args
86
+ ) => {
87
+ if (!shouldCreateNewSourceFile && this.#sourceFileCacheMap.has(PathUtil.norm(fileName))) {
88
+ return this.#sourceFileCacheMap.get(PathUtil.norm(fileName));
89
+ }
90
+
91
+ const sf = baseGetSourceFile.call(this.#compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
92
+
93
+ if (sf) {
94
+ this.#sourceFileCacheMap.set(PathUtil.norm(fileName), sf);
95
+ } else {
96
+ this.#sourceFileCacheMap.delete(PathUtil.norm(fileName));
97
+ }
98
+
99
+ return sf;
100
+ };
101
+
102
+ const baseReadFile = this.#compilerHost.readFile;
103
+ this.#compilerHost.readFile = (fileName) => {
104
+ this.#watchFileSet.add(PathUtil.norm(fileName));
105
+ return baseReadFile.call(this.#compilerHost, fileName);
106
+ };
107
+
108
+ if (this.#isForAngular) {
109
+ //-- stylesheetBundler
110
+ this.#stylesheetBundler = new ComponentStylesheetBundler(
111
+ {
112
+ workspaceRoot: opt.pkgPath,
113
+ optimization: !opt.isDevMode,
114
+ inlineFonts: true,
115
+ preserveSymlinks: false,
116
+ sourcemap: "inline", //conf.dev ? 'inline' : false,
117
+ outputNames: { bundles: "[name]", media: "media/[name]" },
118
+ includePaths: [],
119
+ externalDependencies: [],
120
+ target: transformSupportedBrowsersToTargets(browserslist(["Chrome > 78"])),
121
+ postcssConfiguration: {
122
+ plugins: [["css-has-pseudo"]],
123
+ },
124
+ tailwindConfiguration: undefined,
125
+ cacheOptions: {
126
+ enabled: true,
127
+ path: ".cache/angular",
128
+ basePath: ".cache",
129
+ },
130
+ },
131
+ opt.isDevMode,
132
+ );
133
+
134
+ //-- compilerHost
135
+
136
+ (this.#compilerHost as AngularCompilerHost).readResource = (fileName: string) => {
137
+ return this.#compilerHost.readFile(fileName) ?? "";
138
+ };
139
+
140
+ (this.#compilerHost as AngularCompilerHost).transformResource = async (
141
+ data: string,
142
+ context: {
143
+ type: string;
144
+ containingFile: string;
145
+ resourceFile: string | null;
146
+ },
147
+ ) => {
148
+ if (context.type !== "style") {
149
+ return null;
150
+ }
151
+
152
+ const contents = await this.#bundleStylesheetAsync(
153
+ data,
154
+ PathUtil.norm(context.containingFile),
155
+ context.resourceFile != null ? PathUtil.norm(context.resourceFile) : undefined,
156
+ );
157
+
158
+ return StringUtil.isNullOrEmpty(contents) ? null : { content: contents };
159
+ };
160
+
161
+ (this.#compilerHost as AngularCompilerHost).getModifiedResourceFiles = () => {
162
+ return new Set(Array.from(this.#modifiedFileSet).map((item) => PathUtil.posix(item)));
163
+ };
164
+ }
165
+ }
166
+
167
+ async #bundleStylesheetAsync(data: string, containingFile: TNormPath, resourceFile: TNormPath | null = null) {
168
+ // containingFile: 포함된 파일 (.ts)
169
+ // resourceFile: 외부 리소스 파일 (styleUrls로 입력하지 않고 styles에 직접 입력한 경우 null)
170
+ // referencedFiles: import한 외부 scss 파일 혹은 woff파일등 외부 파일
171
+
172
+ this.#debug(`스타일시트 번들링...(${containingFile}, ${resourceFile})`);
173
+
174
+ const stylesheetResult =
175
+ resourceFile != null
176
+ ? await this.#stylesheetBundler!.bundleFile(resourceFile)
177
+ : await this.#stylesheetBundler!.bundleInline(data, containingFile, "scss");
178
+
179
+ if (stylesheetResult.referencedFiles) {
180
+ for (const referencedFile of stylesheetResult.referencedFiles) {
181
+ const depCacheSet = this.#resourceDependencyCacheMap.getOrCreate(
182
+ PathUtil.norm(referencedFile),
183
+ new Set<TNormPath>(),
184
+ );
185
+ depCacheSet.add(resourceFile ?? containingFile);
186
+ }
187
+
188
+ this.#watchFileSet.adds(
189
+ ...Array.from(stylesheetResult.referencedFiles.values()).map((item) => PathUtil.norm(item)),
190
+ );
191
+ }
192
+
193
+ this.#stylesheetBundlingResultMap.set(PathUtil.norm(resourceFile ?? containingFile), {
194
+ outputFiles: stylesheetResult.outputFiles,
195
+ metafile: stylesheetResult.metafile,
196
+ errors: stylesheetResult.errors,
197
+ warnings: stylesheetResult.warnings,
198
+ });
199
+
200
+ return stylesheetResult.contents;
201
+ }
202
+
203
+ async compileAsync(modifiedFileSet: Set<TNormPath>): Promise<ISdTsCompilerResult> {
204
+ let perf = new SdCliPerformanceTimer("esbuild compile");
205
+
206
+ this.#modifiedFileSet = new Set(modifiedFileSet);
207
+ this.#affectedFileSet = new Set<TNormPath>();
208
+
209
+ if (modifiedFileSet.size !== 0) {
210
+ this.#debug(`get affected (old deps & old res deps)...`);
211
+
212
+ perf.run("get affected", () => {
213
+ for (const modifiedFile of modifiedFileSet) {
214
+ this.#affectedFileSet.add(modifiedFile);
215
+ this.#affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
216
+ this.#affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
217
+
218
+ this.#emittedFilesCacheMap.delete(modifiedFile);
219
+ }
220
+ });
221
+
222
+ this.#debug(`invalidate & clear cache...`);
223
+
224
+ perf.run("invalidate & clear cache", () => {
225
+ this.#stylesheetBundler?.invalidate(modifiedFileSet);
226
+
227
+ for (const affectedFile of this.#affectedFileSet) {
228
+ this.#sourceFileCacheMap.delete(affectedFile);
229
+ this.#stylesheetBundlingResultMap.delete(affectedFile);
230
+ this.#watchFileSet.delete(affectedFile);
231
+ }
232
+
233
+ this.#revDependencyCacheMap.clear();
234
+ this.#resourceDependencyCacheMap.clear();
235
+ });
236
+ }
237
+
238
+ this.#debug(`create program...`);
239
+
240
+ perf.run("create program", () => {
241
+ if (this.#isForAngular) {
242
+ this.#ngProgram = new NgtscProgram(
243
+ this.#parsedTsconfig.fileNames,
244
+ this.#parsedTsconfig.options,
245
+ this.#compilerHost,
246
+ this.#ngProgram,
247
+ );
248
+ this.#program = this.#ngProgram.getTsProgram();
249
+ } else {
250
+ this.#program = ts.createProgram(
251
+ this.#parsedTsconfig.fileNames,
252
+ this.#parsedTsconfig.options,
253
+ this.#compilerHost,
254
+ this.#program,
255
+ );
256
+ }
257
+ });
258
+
259
+ if (this.#ngProgram) {
260
+ await perf.run("ng analyze", async () => {
261
+ await this.#ngProgram!.compiler.analyzeAsync();
262
+ });
263
+ }
264
+
265
+ const getOrgSourceFile = (sf: ts.SourceFile) => {
266
+ if (sf.fileName.endsWith(".ngtypecheck.ts")) {
267
+ const orgFileName = sf.fileName.slice(0, -15) + ".ts";
268
+ return this.#program!.getSourceFile(orgFileName);
269
+ }
270
+
271
+ return sf;
272
+ };
273
+
274
+ const sourceFileSet = new Set(
275
+ this.#program!.getSourceFiles()
276
+ .map((sf) => getOrgSourceFile(sf))
277
+ .filterExists(),
278
+ );
279
+
280
+ this.#debug(`get new deps...`);
281
+
282
+ const messages: ISdBuildMessage[] = [];
283
+
284
+ perf.run("get new deps", () => {
285
+ const depMap = new Map<
286
+ TNormPath,
287
+ {
288
+ fileName: TNormPath;
289
+ importName: string;
290
+ exportName?: string;
291
+ }[]
292
+ >();
293
+ for (const sf of sourceFileSet) {
294
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
295
+ continue;
296
+ }
297
+
298
+ const refs = this.#findDeps(sf);
299
+ messages.push(...refs.filter((item) => "severity" in item));
300
+ depMap.set(
301
+ PathUtil.norm(sf.fileName),
302
+ refs
303
+ .filter((item) => "fileName" in item)
304
+ .filter((item) =>
305
+ this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(item.fileName, scopePath)),
306
+ ),
307
+ );
308
+ }
309
+
310
+ const allDepMap = new Map<TNormPath, Set<TNormPath>>();
311
+ const getAllDeps = (fileName: TNormPath, prevSet?: Set<TNormPath>) => {
312
+ if (allDepMap.has(fileName)) {
313
+ return allDepMap.get(fileName)!;
314
+ }
315
+
316
+ const result = new Set<TNormPath>();
317
+
318
+ const deps = depMap.get(fileName) ?? [];
319
+ result.adds(...deps.map((item) => item.fileName));
320
+
321
+ for (const dep of deps) {
322
+ const targetDeps = depMap.get(dep.fileName) ?? [];
323
+
324
+ if (dep.importName === "*") {
325
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
326
+ if (prevSet?.has(targetRefItem.fileName)) continue;
327
+
328
+ result.add(targetRefItem.fileName);
329
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<TNormPath>(prevSet).adds(...result)));
330
+ }
331
+ } else {
332
+ for (const targetRefItem of targetDeps.filter((item) => item.exportName === dep.importName)) {
333
+ if (prevSet?.has(targetRefItem.fileName)) continue;
334
+
335
+ result.add(targetRefItem.fileName);
336
+ result.adds(...getAllDeps(targetRefItem.fileName, new Set<TNormPath>(prevSet).adds(...result)));
337
+ }
338
+ }
339
+ }
340
+
341
+ return result;
342
+ };
343
+
344
+ for (const sf of sourceFileSet) {
345
+ const deps = getAllDeps(PathUtil.norm(sf.fileName));
346
+ allDepMap.set(PathUtil.norm(sf.fileName), deps);
347
+
348
+ for (const dep of getAllDeps(PathUtil.norm(sf.fileName))) {
349
+ const depCache = this.#revDependencyCacheMap.getOrCreate(dep, new Set<TNormPath>());
350
+ depCache.add(PathUtil.norm(sf.fileName));
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(PathUtil.norm(dep), new Set<TNormPath>());
360
+ ref.add(PathUtil.norm(sf.fileName));
361
+ }
362
+ }
363
+ }
364
+ });
365
+
366
+ if (modifiedFileSet.size === 0) {
367
+ this.#debug(`get affected (init)...`);
368
+
369
+ perf.run("get affected (init)", () => {
370
+ for (const sf of sourceFileSet) {
371
+ if (!this.#watchScopePaths.some((scopePath) => PathUtil.isChildPath(sf.fileName, scopePath))) {
372
+ continue;
373
+ }
374
+
375
+ this.#affectedFileSet.add(PathUtil.norm(sf.fileName));
376
+ }
377
+ });
378
+ }
379
+
380
+ for (const dep of this.#revDependencyCacheMap.keys()) {
381
+ if (this.#modifiedFileSet.has(dep)) {
382
+ this.#affectedFileSet.adds(
383
+ ...Array.from(this.#revDependencyCacheMap.get(dep)!).mapMany((item) =>
384
+ [
385
+ item,
386
+ // .d.ts면 .js파일도 affected에 추가
387
+ item.endsWith(".d.ts") ? PathUtil.norm(item.replace(/\.d\.ts$/, ".js")) : undefined,
388
+ ].filterExists(),
389
+ ),
390
+ );
391
+ }
392
+
393
+ // dep이 emit된적이 없으면 affected에 추가해야함.
394
+ // dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
395
+ if (!this.#emittedFilesCacheMap.has(dep)) {
396
+ this.#affectedFileSet.add(dep);
397
+ }
398
+ }
399
+
400
+ if (this.#ngProgram) {
401
+ for (const dep of this.#resourceDependencyCacheMap.keys()) {
402
+ if (this.#modifiedFileSet.has(dep)) {
403
+ this.#affectedFileSet.adds(...this.#resourceDependencyCacheMap.get(dep)!);
404
+ }
405
+
406
+ // dep이 emit된적이 없으면 affected에 추가해야함.
407
+ // dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
408
+ if (!this.#emittedFilesCacheMap.has(dep)) {
409
+ this.#affectedFileSet.add(dep);
410
+ }
411
+ }
412
+ }
413
+
414
+ const emitFileSet = new Set<TNormPath>();
415
+
416
+ const [lintResults] = await Promise.all([
417
+ this.#lintWorker.run("lint", [
418
+ {
419
+ cwd: this.#pkgPath,
420
+ fileSet: this.#affectedFileSet,
421
+ },
422
+ ]),
423
+ (async () => {
424
+ this.#debug(`get diagnostics...`);
425
+
426
+ const diagnostics: ts.Diagnostic[] = [];
427
+
428
+ perf.run("get program diagnostics", () => {
429
+ diagnostics.push(
430
+ ...this.#program!.getConfigFileParsingDiagnostics(),
431
+ ...this.#program!.getOptionsDiagnostics(),
432
+ ...this.#program!.getGlobalDiagnostics(),
433
+ );
434
+
435
+ if (this.#ngProgram) {
436
+ diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
437
+ }
438
+ });
439
+
440
+ this.#debug(`get diagnostics of files...`);
441
+
442
+ for (const affectedFile of this.#affectedFileSet) {
443
+ if (!PathUtil.isChildPath(affectedFile, this.#pkgPath)) {
444
+ continue;
445
+ }
446
+
447
+ const affectedSourceFile = this.#program!.getSourceFile(affectedFile);
448
+
449
+ if (
450
+ !affectedSourceFile ||
451
+ (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))
452
+ ) {
453
+ continue;
454
+ }
455
+
456
+ // this.#debug(`get diagnostics of file ${affectedFile}...`);
457
+
458
+ perf.run("get file diagnostics", () => {
459
+ diagnostics.push(
460
+ ...this.#program!.getSyntacticDiagnostics(affectedSourceFile),
461
+ ...this.#program!.getSemanticDiagnostics(affectedSourceFile),
462
+ );
463
+ });
464
+
465
+ if (this.#ngProgram) {
466
+ perf.run("get file diagnostics: ng", () => {
467
+ if (affectedSourceFile.isDeclarationFile) {
468
+ return;
469
+ }
470
+
471
+ diagnostics.push(
472
+ ...this.#ngProgram!.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram),
473
+ );
474
+ });
475
+ }
476
+ }
477
+
478
+ perf.run("emit", () => {
479
+ this.#debug(`prepare emit...`);
480
+
481
+ let transformers: ts.CustomTransformers = {};
482
+
483
+ if (this.#ngProgram) {
484
+ transformers = {
485
+ ...transformers,
486
+ ...this.#ngProgram.compiler.prepareEmit().transformers,
487
+ };
488
+ (transformers.before ??= []).push(replaceBootstrap(() => this.#program!.getTypeChecker()));
489
+ }
490
+ // (transformers.before ??= []).push(transformKeys(this.#program));
491
+
492
+ this.#debug(`emit for files...`);
493
+
494
+ // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 sourceFileSet으로 바꿈
495
+ // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
496
+ // 그래도 affected로 다시 테스트
497
+ for (const affectedFile of this.#affectedFileSet) {
498
+ if (this.#emittedFilesCacheMap.has(affectedFile)) {
499
+ continue;
500
+ }
501
+
502
+ const sf = this.#program!.getSourceFile(affectedFile);
503
+ if (!sf) {
504
+ continue;
505
+ }
506
+
507
+ if (sf.isDeclarationFile) {
508
+ continue;
509
+ }
510
+
511
+ if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
512
+ continue;
513
+ }
514
+
515
+ if (this.#ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf)) {
516
+ continue;
517
+ }
518
+
519
+ // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
520
+ if (!this.#isForBundle) {
521
+ if (!PathUtil.isChildPath(sf.fileName, this.#pkgPath)) {
522
+ continue;
523
+ }
524
+ }
525
+
526
+ // this.#debug(`emit for`, sf.fileName);
527
+ this.#program!.emit(
528
+ sf,
529
+ (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
530
+ if (!sourceFiles || sourceFiles.length === 0) {
531
+ this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
532
+ return;
533
+ }
534
+
535
+ const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
536
+ if (this.#ngProgram) {
537
+ if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
538
+ return;
539
+ }
540
+ this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
541
+ }
542
+
543
+ const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(
544
+ PathUtil.norm(sourceFile.fileName),
545
+ [],
546
+ );
547
+
548
+ if (PathUtil.isChildPath(sourceFile.fileName, this.#pkgPath)) {
549
+ let realFilePath = PathUtil.norm(fileName);
550
+ let realText = text;
551
+ if (
552
+ PathUtil.isChildPath(
553
+ realFilePath,
554
+ path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"),
555
+ )
556
+ ) {
557
+ realFilePath = PathUtil.norm(
558
+ this.#distPath,
559
+ path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath),
560
+ );
561
+
562
+ if (fileName.endsWith(".js.map")) {
563
+ const sourceMapContents = JSON.parse(realText);
564
+ // remove "../../"
565
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
566
+ realText = JSON.stringify(sourceMapContents);
567
+ }
568
+ }
569
+
570
+ emitFileInfoCaches.push({
571
+ outAbsPath: realFilePath,
572
+ text: realText,
573
+ });
574
+ } else {
575
+ emitFileInfoCaches.push({ text });
576
+ }
577
+
578
+ emitFileSet.add(PathUtil.norm(sourceFile.fileName));
579
+ },
580
+ undefined,
581
+ undefined,
582
+ transformers,
583
+ );
584
+ }
585
+ });
586
+
587
+ //-- global style
588
+ if (
589
+ this.#globalStyleFilePath != null &&
590
+ FsUtil.exists(this.#globalStyleFilePath) &&
591
+ !this.#emittedFilesCacheMap.has(this.#globalStyleFilePath)
592
+ ) {
593
+ this.#debug(`bundle global style...`);
594
+
595
+ await perf.run("bundle global style", async () => {
596
+ const data = FsUtil.readFile(this.#globalStyleFilePath!);
597
+ const contents = await this.#bundleStylesheetAsync(
598
+ data,
599
+ this.#globalStyleFilePath!,
600
+ this.#globalStyleFilePath,
601
+ );
602
+ const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath!, []);
603
+ emitFileInfos.push({
604
+ outAbsPath: PathUtil.norm(
605
+ this.#pkgPath,
606
+ path
607
+ .relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath!)
608
+ .replace(/\.scss$/, ".css"),
609
+ ),
610
+ text: contents,
611
+ });
612
+ emitFileSet.add(this.#globalStyleFilePath!);
613
+ });
614
+ }
615
+
616
+ this.#debug(`build completed`, perf.toString());
617
+
618
+ //-- result
619
+
620
+ messages.push(...SdCliConvertMessageUtil.convertToBuildMessagesFromTsDiag(diagnostics));
621
+ })(),
622
+ ]);
623
+
624
+ messages.push(...SdCliConvertMessageUtil.convertToBuildMessagesFromEslint(lintResults));
625
+
626
+ return {
627
+ messages,
628
+ watchFileSet: this.#watchFileSet,
629
+ affectedFileSet: this.#affectedFileSet,
630
+ stylesheetBundlingResultMap: this.#stylesheetBundlingResultMap,
631
+ emittedFilesCacheMap: this.#emittedFilesCacheMap,
632
+ emitFileSet,
633
+ };
634
+ }
635
+
636
+ #debug(...msg: any[]): void {
637
+ this.#logger.debug(`[${path.basename(this.#pkgPath)}]`, ...msg);
638
+ }
639
+
640
+ #findDeps(sf: ts.SourceFile) {
641
+ const deps: (
642
+ | {
643
+ fileName: TNormPath;
644
+ importName: string;
645
+ exportName?: string;
646
+ }
647
+ // | ts.Diagnostic
648
+ | ISdBuildMessage
649
+ )[] = [];
650
+
651
+ const tc = this.#program!.getTypeChecker();
652
+
653
+ sf.forEachChild((node) => {
654
+ if (ts.isExportDeclaration(node)) {
655
+ if (node.moduleSpecifier) {
656
+ const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
657
+ if (!moduleSymbol) {
658
+ const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
659
+ deps.push({
660
+ filePath: PathUtil.norm(sf.fileName),
661
+ line: pos.line,
662
+ char: pos.character,
663
+ code: undefined,
664
+ severity: "error",
665
+ message: "export moduleSymbol not found",
666
+ type: "deps",
667
+ });
668
+ return;
669
+ }
670
+
671
+ const decls = moduleSymbol.getDeclarations();
672
+ if (!decls) {
673
+ const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
674
+ deps.push({
675
+ filePath: PathUtil.norm(sf.fileName),
676
+ line: pos.line,
677
+ char: pos.character,
678
+ code: undefined,
679
+ severity: "error",
680
+ message: "export decls not found",
681
+ type: "deps",
682
+ });
683
+ return;
684
+ }
685
+
686
+ const namedBindings = node.exportClause;
687
+ if (namedBindings && ts.isNamedExports(namedBindings)) {
688
+ for (const el of namedBindings.elements) {
689
+ for (const decl of decls) {
690
+ deps.push({
691
+ fileName: PathUtil.norm(decl.getSourceFile().fileName),
692
+ importName: el.name.text,
693
+ exportName: el.propertyName?.text ?? el.name.text,
694
+ });
695
+ }
696
+ }
697
+ } else {
698
+ if (!moduleSymbol.exports) {
699
+ const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
700
+ deps.push({
701
+ filePath: PathUtil.norm(sf.fileName),
702
+ line: pos.line,
703
+ char: pos.character,
704
+ code: undefined,
705
+ severity: "error",
706
+ message: "moduleSymbol exports not found",
707
+ type: "deps",
708
+ });
709
+ return;
710
+ }
711
+
712
+ for (const decl of decls) {
713
+ for (const key of moduleSymbol.exports.keys()) {
714
+ deps.push({
715
+ fileName: PathUtil.norm(decl.getSourceFile().fileName),
716
+ importName: key.toString(),
717
+ exportName: key.toString(),
718
+ });
719
+ }
720
+ }
721
+ }
722
+ }
723
+ } else if (ts.isImportDeclaration(node)) {
724
+ const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
725
+ if (!moduleSymbol) {
726
+ if (ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text.startsWith("./")) {
727
+ deps.push({
728
+ fileName: PathUtil.norm(path.resolve(path.dirname(sf.fileName), node.moduleSpecifier.text)),
729
+ importName: "*",
730
+ });
731
+ }
732
+ /*else {
733
+ throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
734
+ }*/
735
+ } else {
736
+ const decls = moduleSymbol.getDeclarations();
737
+ if (!decls) {
738
+ const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
739
+ deps.push({
740
+ filePath: PathUtil.norm(sf.fileName),
741
+ line: pos.line,
742
+ char: pos.character,
743
+ code: undefined,
744
+ severity: "error",
745
+ message: "import decls not found",
746
+ type: "deps",
747
+ });
748
+ return;
749
+ }
750
+
751
+ const namedBindings = node.importClause?.namedBindings;
752
+ if (namedBindings && ts.isNamedImports(namedBindings)) {
753
+ for (const el of namedBindings.elements) {
754
+ for (const decl of decls) {
755
+ deps.push({
756
+ fileName: PathUtil.norm(decl.getSourceFile().fileName),
757
+ importName: el.name.text,
758
+ });
759
+ }
760
+ }
761
+ } else {
762
+ for (const decl of decls) {
763
+ deps.push({
764
+ fileName: PathUtil.norm(decl.getSourceFile().fileName),
765
+ importName: "*",
766
+ });
767
+ }
768
+ }
769
+ }
770
+ }
771
+ });
772
+
773
+ return deps;
774
+ }
775
+ }