@simplysm/sd-cli 11.0.9 → 11.0.12

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 (61) hide show
  1. package/dist/build-cluster.js +25 -36
  2. package/dist/build-cluster.js.map +1 -1
  3. package/dist/build-tools/SdCliCordova.js +5 -5
  4. package/dist/build-tools/SdCliCordova.js.map +1 -1
  5. package/dist/build-tools/SdCliNgRoutesFileGenerator.d.ts +4 -0
  6. package/dist/build-tools/SdCliNgRoutesFileGenerator.js +64 -0
  7. package/dist/build-tools/SdCliNgRoutesFileGenerator.js.map +1 -0
  8. package/dist/build-tools/SdLinter.js +8 -1
  9. package/dist/build-tools/SdLinter.js.map +1 -1
  10. package/dist/build-tools/SdNgBundler.d.ts +18 -8
  11. package/dist/build-tools/SdNgBundler.js +286 -213
  12. package/dist/build-tools/SdNgBundler.js.map +1 -1
  13. package/dist/build-tools/SdTsBundler.d.ts +6 -5
  14. package/dist/build-tools/SdTsBundler.js +78 -80
  15. package/dist/build-tools/SdTsBundler.js.map +1 -1
  16. package/dist/build-tools/SdTsCompiler.d.ts +1 -0
  17. package/dist/build-tools/SdTsCompiler.js +5 -1
  18. package/dist/build-tools/SdTsCompiler.js.map +1 -1
  19. package/dist/builders/SdCliClientBuilder.js +51 -36
  20. package/dist/builders/SdCliClientBuilder.js.map +1 -1
  21. package/dist/builders/SdCliServerBuilder.d.ts +6 -2
  22. package/dist/builders/SdCliServerBuilder.js +107 -141
  23. package/dist/builders/SdCliServerBuilder.js.map +1 -1
  24. package/dist/builders/SdCliTsLibBuilder.d.ts +6 -3
  25. package/dist/builders/SdCliTsLibBuilder.js +42 -45
  26. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  27. package/dist/commons.d.ts +0 -2
  28. package/dist/entry/SdCliElectron.js +3 -3
  29. package/dist/entry/SdCliElectron.js.map +1 -1
  30. package/dist/entry/SdCliProject.d.ts +0 -3
  31. package/dist/entry/SdCliProject.js +10 -33
  32. package/dist/entry/SdCliProject.js.map +1 -1
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.js +3 -0
  35. package/dist/index.js.map +1 -1
  36. package/dist/sd-cli.js +3 -21
  37. package/dist/sd-cli.js.map +1 -1
  38. package/dist/utils/SdMemoryLoadResultCache.d.ts +9 -0
  39. package/dist/utils/SdMemoryLoadResultCache.js +39 -0
  40. package/dist/utils/SdMemoryLoadResultCache.js.map +1 -0
  41. package/dist/utils/SdSourceFileCache.d.ts +5 -0
  42. package/dist/utils/SdSourceFileCache.js +9 -0
  43. package/dist/utils/SdSourceFileCache.js.map +1 -0
  44. package/package.json +17 -17
  45. package/src/build-cluster.ts +26 -36
  46. package/src/build-tools/SdCliCordova.ts +5 -5
  47. package/src/build-tools/SdCliNgRoutesFileGenerator.ts +80 -0
  48. package/src/build-tools/SdLinter.ts +12 -1
  49. package/src/build-tools/SdNgBundler.ts +431 -333
  50. package/src/build-tools/SdTsBundler.ts +86 -86
  51. package/src/build-tools/SdTsCompiler.ts +6 -1
  52. package/src/builders/SdCliClientBuilder.ts +62 -43
  53. package/src/builders/SdCliServerBuilder.ts +64 -63
  54. package/src/builders/SdCliTsLibBuilder.ts +58 -50
  55. package/src/commons.ts +1 -2
  56. package/src/entry/SdCliElectron.ts +3 -3
  57. package/src/entry/SdCliProject.ts +12 -41
  58. package/src/index.ts +3 -0
  59. package/src/sd-cli.ts +3 -21
  60. package/src/utils/SdMemoryLoadResultCache.ts +44 -0
  61. package/src/utils/SdSourceFileCache.ts +6 -0
@@ -1,14 +1,8 @@
1
- import {
2
- createCompilerPlugin,
3
- SourceFileCache
4
- } from "@angular-devkit/build-angular/src/tools/esbuild/angular/compiler-plugin";
5
- import {NormalizedApplicationBuildOptions} from "@angular-devkit/build-angular/src/builders/application/options";
1
+ import {createCompilerPlugin} from "@angular-devkit/build-angular/src/tools/esbuild/angular/compiler-plugin";
6
2
  import path from "path";
7
- import {CrossOrigin} from "@angular-devkit/build-angular/src/builders/application/schema";
8
- import {BundlerContext} from "@angular-devkit/build-angular/src/tools/esbuild/bundler-context";
3
+ import {BundlerContext, InitialFileRecord} from "@angular-devkit/build-angular/src/tools/esbuild/bundler-context";
9
4
  import esbuild from "esbuild";
10
- import {createCompilerPluginOptions} from "@angular-devkit/build-angular/src/tools/esbuild/compiler-plugin-options";
11
- import {FsUtil, Logger, PathUtil} from "@simplysm/sd-core-node";
5
+ import {FsUtil, PathUtil} from "@simplysm/sd-core-node";
12
6
  import {fileURLToPath} from "url";
13
7
  import {createVirtualModulePlugin} from "@angular-devkit/build-angular/src/tools/esbuild/virtual-module-plugin";
14
8
  import {
@@ -17,32 +11,62 @@ import {
17
11
  import nodeStdLibBrowser from "node-stdlib-browser";
18
12
  import nodeStdLibBrowserPlugin from "node-stdlib-browser/helpers/esbuild/plugin";
19
13
  import {ExecutionResult} from "@angular-devkit/build-angular/src/tools/esbuild/bundler-execution-result";
20
- import {INpmConfig, ISdCliClientPackageConfig, ISdCliPackageBuildResult} from "../commons";
21
- import {generateIndexHtml} from "@angular-devkit/build-angular/src/tools/esbuild/index-html-generator";
14
+ import {INpmConfig, ISdCliPackageBuildResult} from "../commons";
22
15
  import {copyAssets} from "@angular-devkit/build-angular/src/utils/copy-assets";
23
16
  import {extractLicenses} from "@angular-devkit/build-angular/src/tools/esbuild/license-extractor";
24
17
  import {augmentAppWithServiceWorkerEsbuild} from "@angular-devkit/build-angular/src/utils/service-worker";
25
- import {createGlobalStylesBundleOptions} from "@angular-devkit/build-angular/src/tools/esbuild/global-styles";
18
+ import browserslist from "browserslist";
19
+ import {transformSupportedBrowsersToTargets} from "@angular-devkit/build-angular/src/tools/esbuild/utils";
20
+ import {createCssResourcePlugin} from "@angular-devkit/build-angular/src/tools/esbuild/stylesheets/css-resource-plugin";
21
+ import {CssStylesheetLanguage} from "@angular-devkit/build-angular/src/tools/esbuild/stylesheets/css-language";
22
+ import {SassStylesheetLanguage} from "@angular-devkit/build-angular/src/tools/esbuild/stylesheets/sass-language";
23
+ import {
24
+ StylesheetPluginFactory
25
+ } from "@angular-devkit/build-angular/src/tools/esbuild/stylesheets/stylesheet-plugin-factory";
26
+ import {
27
+ HintMode,
28
+ IndexHtmlGenerator,
29
+ IndexHtmlTransformResult
30
+ } from "@angular-devkit/build-angular/src/utils/index-file/index-html-generator";
26
31
  import {Entrypoint} from "@angular-devkit/build-angular/src/utils/index-file/augment-index-html";
32
+ import {CrossOrigin} from "@angular-devkit/build-angular";
33
+ import {InlineCriticalCssProcessor} from "@angular-devkit/build-angular/src/utils/index-file/inline-critical-css";
34
+ import {SdSourceFileCache} from "../utils/SdSourceFileCache";
27
35
 
28
36
  export class SdNgBundler {
29
- private readonly _logger = Logger.get(["simplysm", "sd-cli", "SdNgEsbuildBuilder"]);
30
-
31
- private readonly _sourceFileCache = new SourceFileCache();
32
- private readonly _options: NormalizedApplicationBuildOptions;
37
+ private readonly _sourceFileCache = new SdSourceFileCache();
33
38
 
34
39
  private _contexts: BundlerContext[] | undefined;
35
40
 
36
41
  private readonly _outputCache = new Map<string, string | number>();
37
42
 
38
- public constructor(opt: {
39
- dev: boolean,
40
- builderType: keyof ISdCliClientPackageConfig["builder"],
41
- pkgPath: string,
42
- cordovaPlatforms: string[] | undefined,
43
- outputPath: string
43
+ private readonly _pkgNpmConf: INpmConfig;
44
+ private readonly _mainFilePath: string;
45
+ private readonly _tsConfigFilePath: string;
46
+ private readonly _swConfFilePath: string;
47
+ private readonly _browserTarget: string[];
48
+ private readonly _indexHtmlFilePath: string;
49
+ private readonly _pkgName: string;
50
+ private readonly _baseHref: string;
51
+
52
+ private _depsMap?: Map<string, Set<string>>;
53
+
54
+ public constructor(private readonly _opt: {
55
+ dev: boolean;
56
+ outputPath: string;
57
+ pkgPath: string;
58
+ builderType: string;
59
+ cordovaPlatforms: string[] | undefined;
60
+ env: Record<string, string> | undefined;
44
61
  }) {
45
- this._options = this._getOptions(opt);
62
+ this._pkgNpmConf = FsUtil.readJson(path.resolve(this._opt.pkgPath, "package.json"));
63
+ this._mainFilePath = path.resolve(this._opt.pkgPath, "src/main.ts");
64
+ this._tsConfigFilePath = path.resolve(this._opt.pkgPath, "tsconfig.json");
65
+ this._swConfFilePath = path.resolve(this._opt.pkgPath, "ngsw-config.json");
66
+ this._browserTarget = transformSupportedBrowsersToTargets(browserslist("defaults and fully supports es6-module"));
67
+ this._indexHtmlFilePath = path.resolve(this._opt.pkgPath, "src/index.html");
68
+ this._pkgName = path.basename(this._opt.pkgPath);
69
+ this._baseHref = this._opt.builderType === "web" ? `/${this._pkgName}/` : this._opt.dev ? `/${this._pkgName}/${this._opt.builderType}/` : ``;
46
70
  }
47
71
 
48
72
  public removeCache(filePaths: string[]): void {
@@ -65,49 +89,50 @@ export class SdNgBundler {
65
89
 
66
90
  const results = [
67
91
  ...bundlingResult.warnings.map((warn) => ({
68
- filePath: warn.location?.file !== undefined ? path.resolve(this._options.workspaceRoot, warn.location.file) : undefined,
92
+ filePath: warn.location?.file !== undefined ? path.resolve(this._opt.pkgPath, warn.location.file) : undefined,
69
93
  line: warn.location?.line,
70
94
  char: warn.location?.column,
71
95
  code: undefined,
72
- severity: "warning" as const,
96
+ severity: "warning",
73
97
  message: warn.text.replace(/^(NG|TS)[0-9]+: /, ""),
74
- type: "build" as const
98
+ type: "build"
75
99
  })),
76
100
  ...bundlingResult.errors?.map((err) => ({
77
- filePath: err.location?.file !== undefined ? path.resolve(this._options.workspaceRoot, err.location.file) : undefined,
101
+ filePath: err.location?.file !== undefined ? path.resolve(this._opt.pkgPath, err.location.file) : undefined,
78
102
  line: err.location?.line,
79
103
  char: err.location?.column !== undefined ? err.location.column + 1 : undefined,
80
104
  code: undefined,
81
- severity: "error" as const,
105
+ severity: "error",
82
106
  message: err.text.replace(/^[^:]*: /, ""),
83
- type: "build" as const
107
+ type: "build"
84
108
  })) ?? []
85
- ];
109
+ ] as ISdCliPackageBuildResult[];
86
110
  const watchFilePaths = [
87
111
  ...this._sourceFileCache.keys(),
88
- ...this._sourceFileCache.babelFileCache.keys()
89
- ].map((item) => path.resolve(item));
90
- let affectedSourceFilePaths = watchFilePaths.filter((item) => PathUtil.isChildPath(item, this._options.workspaceRoot));
112
+ ...this._sourceFileCache.babelFileCache.keys(),
113
+ ...this._sourceFileCache.loadResultCache.fileDependencies.keys()
114
+ ].map((item) => path.resolve(item)).distinct();
115
+
116
+ let affectedSourceFilePaths = watchFilePaths.filter((item) => PathUtil.isChildPath(item, this._opt.pkgPath));
117
+
91
118
  if (bundlingResult.errors) {
92
- return {
93
- filePaths: watchFilePaths,
94
- affectedFilePaths: affectedSourceFilePaths,
95
- results
96
- };
119
+ // TODO: 제대로 deps를 적용해야함.. 코드 분석 필요
120
+ this._depsMap = this._depsMap ?? new Map<string, Set<string>>();
97
121
  }
98
-
99
- const depsMap = new Map<string, Set<string>>();
100
- for (const entry of Object.entries(bundlingResult.metafile.inputs)) {
101
- for (const imp of entry[1].imports) {
102
- const deps = depsMap.getOrCreate(path.resolve(this._options.workspaceRoot, imp.path), new Set<string>());
103
- deps.add(path.resolve(this._options.workspaceRoot, entry[0]));
122
+ else {
123
+ this._depsMap = new Map<string, Set<string>>();
124
+ for (const entry of Object.entries(bundlingResult.metafile.inputs)) {
125
+ for (const imp of entry[1].imports) {
126
+ const deps = this._depsMap.getOrCreate(path.resolve(this._opt.pkgPath, imp.path), new Set<string>());
127
+ deps.add(path.resolve(this._opt.pkgPath, entry[0]));
128
+ }
104
129
  }
105
130
  }
106
131
 
107
132
  const searchAffectedFiles = (filePath: string, prev?: Set<string>): Set<string> => {
108
133
  const result = new Set<string>(prev);
109
134
 
110
- const importerPaths = depsMap.get(filePath);
135
+ const importerPaths = this._depsMap!.get(filePath);
111
136
  if (!importerPaths) return result;
112
137
 
113
138
  for (const importerPath of importerPaths) {
@@ -125,67 +150,99 @@ export class SdNgBundler {
125
150
  affectedFilePathSet.add(path.resolve(modFile));
126
151
  affectedFilePathSet.adds(...searchAffectedFiles(path.resolve(modFile)));
127
152
  }
128
- affectedSourceFilePaths = Array.from(affectedFilePathSet.values()).filter((item) => PathUtil.isChildPath(item, this._options.workspaceRoot));
153
+ affectedSourceFilePaths = Array.from(affectedFilePathSet.values()).filter((item) => PathUtil.isChildPath(item, this._opt.pkgPath));
154
+ }
155
+
156
+ if (bundlingResult.errors) {
157
+ return {
158
+ filePaths: watchFilePaths,
159
+ affectedFilePaths: affectedSourceFilePaths,
160
+ results
161
+ };
129
162
  }
130
163
 
131
164
  const executionResult = new ExecutionResult(this._contexts, this._sourceFileCache);
132
165
  executionResult.outputFiles.push(...bundlingResult.outputFiles);
133
166
 
134
- //-- index
135
- if (this._options.indexHtmlOptions) {
136
- const genIndexHtmlResult = await generateIndexHtml(
137
- bundlingResult.initialFiles,
138
- executionResult,
139
- this._options
140
- );
141
- if (genIndexHtmlResult.warnings.length > 0) {
142
- this._logger.warn(...genIndexHtmlResult.warnings);
143
- }
144
- if (genIndexHtmlResult.errors.length > 0) {
145
- this._logger.warn(...genIndexHtmlResult.errors);
146
- }
167
+ //-- Check commonjs
168
+ // if (!this._opt.dev) {
169
+ // const messages = checkCommonJSModules(bundlingResult.metafile, []);
170
+ // for (const msg of messages) {
171
+ // results.push({
172
+ // filePath: msg.location?.file,
173
+ // line: msg.location?.line,
174
+ // char: msg.location?.column,
175
+ // code: msg.pluginName,
176
+ // severity: "warning",
177
+ // message: msg.text ?? "",
178
+ // type: "build"
179
+ // });
180
+ // }
181
+ // }
147
182
 
148
- executionResult.addOutputFile(this._options.indexHtmlOptions!.output, genIndexHtmlResult.content);
183
+ //-- index
184
+ const genIndexHtmlResult = await this._genIndexHtmlAsync(
185
+ bundlingResult.outputFiles,
186
+ bundlingResult.initialFiles
187
+ );
188
+ for (const warning of genIndexHtmlResult.warnings) {
189
+ results.push({
190
+ filePath: undefined,
191
+ line: undefined,
192
+ char: undefined,
193
+ code: undefined,
194
+ severity: "warning",
195
+ message: warning,
196
+ type: "build",
197
+ });
149
198
  }
199
+ for (const error of genIndexHtmlResult.errors) {
200
+ results.push({
201
+ filePath: undefined,
202
+ line: undefined,
203
+ char: undefined,
204
+ code: undefined,
205
+ severity: "error",
206
+ message: error,
207
+ type: "build",
208
+ });
209
+ }
210
+ executionResult.addOutputFile("index.html", genIndexHtmlResult.content);
150
211
 
151
212
  //-- copy assets
152
- if (this._options.assets) {
153
- executionResult.assetFiles.push(...(await copyAssets(this._options.assets!, [], this._options.workspaceRoot)));
154
- }
213
+ executionResult.assetFiles.push(...(await this._copyAssetsAsync()));
155
214
 
156
215
  //-- extract 3rdpartylicenses
157
- if (this._options.extractLicenses) {
158
- executionResult.addOutputFile('3rdpartylicenses.txt', await extractLicenses(bundlingResult.metafile, this._options.workspaceRoot));
216
+ if (!this._opt.dev) {
217
+ executionResult.addOutputFile('3rdpartylicenses.txt', await extractLicenses(bundlingResult.metafile, this._opt.pkgPath));
159
218
  }
160
219
 
161
220
  //-- service worker
162
- if (this._options.serviceWorker !== undefined) {
221
+ if (FsUtil.exists(this._swConfFilePath)) {
163
222
  try {
164
- const serviceWorkerResult = await augmentAppWithServiceWorkerEsbuild(
165
- this._options.workspaceRoot,
166
- this._options.serviceWorker,
167
- this._options.baseHref ?? '/',
223
+ const serviceWorkerResult = await this._genServiceWorkerAsync(
168
224
  executionResult.outputFiles,
169
225
  executionResult.assetFiles
170
226
  );
171
227
  executionResult.addOutputFile('ngsw.json', serviceWorkerResult.manifest);
172
228
  executionResult.assetFiles.push(...serviceWorkerResult.assetFiles);
173
229
  }
174
- catch (error) {
175
- this._logger.error(error instanceof Error ? error.message : `${error}`);
176
-
177
- return {
178
- filePaths: watchFilePaths,
179
- affectedFilePaths: affectedSourceFilePaths,
180
- results
181
- };
230
+ catch (err) {
231
+ results.push({
232
+ filePath: undefined,
233
+ line: undefined,
234
+ char: undefined,
235
+ code: undefined,
236
+ severity: "error",
237
+ message: err.toString(),
238
+ type: "build",
239
+ });
182
240
  }
183
241
  }
184
242
 
185
243
  //-- write
186
-
187
244
  for (const outputFile of executionResult.outputFiles) {
188
- const distFilePath = path.resolve(this._options.outputPath, outputFile.path);
245
+ const distFilePath = path.resolve(this._opt.outputPath, outputFile.path);
189
246
 
190
247
  const prev = this._outputCache.get(distFilePath);
191
248
  if (prev !== Buffer.from(outputFile.contents).toString("base64")) {
@@ -197,7 +254,7 @@ export class SdNgBundler {
197
254
  const prev = this._outputCache.get(assetFile.source);
198
255
  const curr = FsUtil.lstat(assetFile.source).mtime.getTime();
199
256
  if (prev !== curr) {
200
- await FsUtil.copyAsync(assetFile.source, path.resolve(this._options.outputPath, assetFile.destination));
257
+ await FsUtil.copyAsync(assetFile.source, path.resolve(this._opt.outputPath, assetFile.destination));
201
258
  this._outputCache.set(assetFile.source, curr);
202
259
  }
203
260
  }
@@ -209,271 +266,312 @@ export class SdNgBundler {
209
266
  };
210
267
  }
211
268
 
212
- private async _getAppContextAsync(): Promise<BundlerContext> {
213
- const esbuildOption = await this._getEsBuildOptionsAsync();
269
+ private async _genIndexHtmlAsync(
270
+ outputFiles: esbuild.OutputFile[],
271
+ initialFiles: Map<string, InitialFileRecord>,
272
+ ): Promise<IndexHtmlTransformResult> {
273
+ const readAsset = (filePath: string): Promise<string> => {
274
+ const relFilePath = path.relative("/", filePath);
275
+ const currFile = outputFiles.find((outputFile) => outputFile.path === relFilePath);
276
+ if (currFile) {
277
+ return Promise.resolve(currFile.text);
278
+ }
214
279
 
215
- return new BundlerContext(
216
- this._options.workspaceRoot,
217
- true,
218
- esbuildOption
219
- );
220
- }
280
+ throw new Error(`Output file does not exist: ${relFilePath}`);
281
+ };
221
282
 
222
- private _getStyleContext(): BundlerContext {
223
- const esbuildOptions = createGlobalStylesBundleOptions(
224
- this._options,
225
- [
226
- 'chrome117.0', 'chrome116.0',
227
- 'edge117.0', 'edge116.0',
228
- 'firefox118.0', 'firefox115.0',
229
- 'ios17.0', 'ios16.6',
230
- 'ios16.5', 'ios16.4',
231
- 'ios16.3', 'ios16.2',
232
- 'ios16.1', 'ios16.0',
233
- 'safari17.0', 'safari16.6',
234
- 'safari16.5', 'safari16.4',
235
- 'safari16.3', 'safari16.2',
236
- 'safari16.1', 'safari16.0'
283
+ const indexHtmlGenerator = new IndexHtmlGenerator({
284
+ indexPath: this._indexHtmlFilePath,
285
+ entrypoints: [
286
+ ['runtime', true],
287
+ ['polyfills', true],
288
+ ['styles', false],
289
+ ['vendor', true],
290
+ ['main', true],
291
+ ...this._opt.builderType === "cordova" ? [
292
+ ["cordova-entry", true] as Entrypoint
293
+ ] : []
237
294
  ],
238
- true,
239
- this._sourceFileCache.loadResultCache
295
+ optimization: {
296
+ scripts: !this._opt.dev,
297
+ fonts: {inline: !this._opt.dev},
298
+ styles: {
299
+ minify: !this._opt.dev,
300
+ inlineCritical: false
301
+ },
302
+ },
303
+ crossOrigin: CrossOrigin.None,
304
+ });
305
+ indexHtmlGenerator.readAsset = readAsset;
306
+
307
+ const hints: { url: string; mode: HintMode; as?: string; }[] = [];
308
+ if (!this._opt.dev) {
309
+ for (const [key, value] of initialFiles) {
310
+ if (value.entrypoint) {
311
+ continue;
312
+ }
313
+
314
+ if (value.type === 'script') {
315
+ hints.push({url: key, mode: 'modulepreload' as const});
316
+ }
317
+ else if (value.type === 'style') {
318
+ hints.push({url: key, mode: 'preload' as const, as: 'style'});
319
+ }
320
+ }
321
+ }
322
+
323
+ const transformResult = await indexHtmlGenerator.process({
324
+ baseHref: this._baseHref,
325
+ lang: undefined,
326
+ outputPath: "/",
327
+ files: [...initialFiles].map(([file, record]) => ({
328
+ name: record.name ?? '',
329
+ file,
330
+ extension: path.extname(file),
331
+ })),
332
+ hints,
333
+ });
334
+
335
+ if (this._opt.dev) {
336
+ return transformResult;
337
+ }
338
+ else {
339
+ const inlineCriticalCssProcessor = new InlineCriticalCssProcessor({
340
+ minify: false,
341
+ readAsset,
342
+ });
343
+ const {content, errors, warnings} = await inlineCriticalCssProcessor.process(
344
+ transformResult.content,
345
+ {outputPath: "/",},
346
+ );
347
+
348
+ return {
349
+ warnings: [...transformResult.warnings, ...warnings],
350
+ errors: [...transformResult.errors, ...errors],
351
+ content
352
+ };
353
+ }
354
+ }
355
+
356
+ private async _copyAssetsAsync(): Promise<{
357
+ source: string;
358
+ destination: string;
359
+ }[]> {
360
+ return await copyAssets([
361
+ {input: 'src', glob: 'favicon.ico', output: ''},
362
+ {input: 'src', glob: 'manifest.webmanifest', output: ''},
363
+ {input: 'src/assets', glob: '**/*', output: 'assets'},
364
+ ...this._opt.dev && this._opt.cordovaPlatforms ? this._opt.cordovaPlatforms.mapMany((platform) => [
365
+ {
366
+ input: `.cordova/platforms/${platform}/platform_www/plugins`,
367
+ glob: '**/*',
368
+ output: `cordova-${platform}/plugins`
369
+ },
370
+ {
371
+ input: `.cordova/platforms/${platform}/platform_www`,
372
+ glob: 'cordova.js',
373
+ output: `cordova-${platform}`
374
+ },
375
+ {
376
+ input: `.cordova/platforms/${platform}/platform_www`,
377
+ glob: 'cordova_plugins.js',
378
+ output: `cordova-${platform}`
379
+ },
380
+ {
381
+ input: `.cordova/platforms/${platform}/www`,
382
+ glob: 'config.xml',
383
+ output: `cordova-${platform}`
384
+ },
385
+ ]) : []
386
+ ], [], this._opt.pkgPath);
387
+ }
388
+
389
+ private async _genServiceWorkerAsync(
390
+ outputFiles: esbuild.OutputFile[],
391
+ assetFiles: {
392
+ source: string;
393
+ destination: string;
394
+ }[]
395
+ ): Promise<{
396
+ manifest: string;
397
+ assetFiles: {
398
+ source: string;
399
+ destination: string;
400
+ }[];
401
+ }> {
402
+ return await augmentAppWithServiceWorkerEsbuild(
403
+ this._opt.pkgPath,
404
+ this._swConfFilePath,
405
+ this._baseHref,
406
+ outputFiles,
407
+ assetFiles
240
408
  );
409
+ }
241
410
 
411
+ private async _getAppContextAsync(): Promise<BundlerContext> {
242
412
  return new BundlerContext(
243
- this._options.workspaceRoot,
413
+ this._opt.pkgPath,
244
414
  true,
245
- esbuildOptions!,
246
- () => true
415
+ {
416
+ absWorkingDir: this._opt.pkgPath,
417
+ bundle: true,
418
+ keepNames: true,
419
+ format: 'esm',
420
+ assetNames: 'media/[name]',
421
+ conditions: ['es2020', 'es2015', 'module'],
422
+ resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
423
+ metafile: true,
424
+ legalComments: this._opt.dev ? 'eof' : 'none',
425
+ logLevel: 'silent',
426
+ minifyIdentifiers: !this._opt.dev,
427
+ minifySyntax: !this._opt.dev,
428
+ minifyWhitespace: !this._opt.dev,
429
+ pure: ['forwardRef'],
430
+ outdir: this._opt.pkgPath,
431
+ outExtension: undefined,
432
+ sourcemap: this._opt.dev,
433
+ splitting: true,
434
+ chunkNames: 'chunk-[hash]',
435
+ tsconfig: this._tsConfigFilePath,
436
+ external: [],
437
+ write: false,
438
+ preserveSymlinks: false,
439
+ define: {
440
+ ...!this._opt.dev ? {ngDevMode: 'false'} : {},
441
+ ngJitMode: 'false',
442
+ global: 'global',
443
+ process: 'process',
444
+ Buffer: 'Buffer',
445
+ 'process.env.SD_VERSION': JSON.stringify(this._pkgNpmConf.version),
446
+ "process.env.NODE_ENV": JSON.stringify(this._opt.dev ? "development" : "production"),
447
+ ...this._opt.env ? Object.keys(this._opt.env).toObject(
448
+ key => `process.env.${key}`,
449
+ key => JSON.stringify(this._opt.env![key])
450
+ ) : {}
451
+ },
452
+ platform: 'browser',
453
+ mainFields: ['es2020', 'es2015', 'browser', 'module', 'main'],
454
+ entryNames: '[name]',
455
+ entryPoints: {
456
+ main: this._mainFilePath,
457
+ polyfills: 'angular:polyfills',
458
+ ...this._opt.builderType === "cordova" ? {
459
+ "cordova-entry": path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../lib/cordova-entry.js`)
460
+ } : {}
461
+ },
462
+ target: this._browserTarget,
463
+ supported: {'async-await': false, 'object-rest-spread': false},
464
+ loader: {
465
+ ".png": "file",
466
+ ".jpeg": "file",
467
+ ".jpg": "file",
468
+ ".jfif": "file",
469
+ ".gif": "file",
470
+ ".svg": "file",
471
+ ".woff": "file",
472
+ ".woff2": "file",
473
+ ".ttf": "file",
474
+ ".eot": "file",
475
+ ".ico": "file",
476
+ ".otf": "file",
477
+ ".csv": "file",
478
+ ".xlsx": "file",
479
+ ".xls": "file",
480
+ ".pptx": "file",
481
+ ".ppt": "file",
482
+ ".docx": "file",
483
+ ".doc": "file",
484
+ ".zip": "file",
485
+ ".pfx": "file",
486
+ ".pkl": "file"
487
+ },
488
+ inject: [PathUtil.posix(fileURLToPath(await import.meta.resolve!("node-stdlib-browser/helpers/esbuild/shim")))],
489
+ plugins: [
490
+ createVirtualModulePlugin({
491
+ namespace: "angular:polyfills",
492
+ loadContent: () => ({
493
+ contents: `import "./src/polyfills.ts";`,
494
+ loader: 'js',
495
+ resolveDir: this._opt.pkgPath
496
+ })
497
+ }) as esbuild.Plugin,
498
+ createSourcemapIgnorelistPlugin(),
499
+ createCompilerPlugin({
500
+ sourcemap: this._opt.dev,
501
+ thirdPartySourcemaps: false,
502
+ tsconfig: this._tsConfigFilePath,
503
+ jit: false,
504
+ advancedOptimizations: true,
505
+ fileReplacements: undefined,
506
+ sourceFileCache: this._sourceFileCache,
507
+ loadResultCache: this._sourceFileCache.loadResultCache
508
+ }, {
509
+ workspaceRoot: this._opt.pkgPath,
510
+ optimization: !this._opt.dev,
511
+ sourcemap: this._opt.dev ? 'inline' : false,
512
+ outputNames: {bundles: '[name]', media: 'media/[name]'},
513
+ includePaths: [],
514
+ externalDependencies: [],
515
+ target: this._browserTarget,
516
+ inlineStyleLanguage: 'scss',
517
+ preserveSymlinks: false,
518
+ tailwindConfiguration: undefined
519
+ }) as esbuild.Plugin,
520
+ nodeStdLibBrowserPlugin(nodeStdLibBrowser)
521
+ ]
522
+ }
247
523
  );
248
524
  }
249
525
 
250
- private async _getEsBuildOptionsAsync(): Promise<esbuild.BuildOptions> {
251
- const pkgNpmConf: INpmConfig = FsUtil.readJson(path.resolve(this._options.workspaceRoot, "package.json"));
252
-
253
- const {pluginOptions, styleOptions} = createCompilerPluginOptions(
254
- this._options,
255
- [
256
- 'chrome117.0', 'chrome116.0',
257
- 'edge117.0', 'edge116.0',
258
- 'firefox118.0', 'firefox115.0',
259
- 'ios17.0', 'ios16.6',
260
- 'ios16.5', 'ios16.4',
261
- 'ios16.3', 'ios16.2',
262
- 'ios16.1', 'ios16.0',
263
- 'safari17.0', 'safari16.6',
264
- 'safari16.5', 'safari16.4',
265
- 'safari16.3', 'safari16.2',
266
- 'safari16.1', 'safari16.0'
267
- ],
268
- this._sourceFileCache,
269
- );
526
+ private _getStyleContext(): BundlerContext {
527
+ const browserTarget = transformSupportedBrowsersToTargets(browserslist("defaults and fully supports es6-module"));
270
528
 
271
- return {
272
- absWorkingDir: this._options.workspaceRoot,
273
- bundle: true,
274
- keepNames: true,
275
- format: 'esm',
276
- assetNames: 'media/[name]',
277
- conditions: ['es2020', 'es2015', 'module'],
278
- resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
279
- metafile: true,
280
- legalComments: this._options.watch ? 'eof' : 'none',
281
- logLevel: 'silent',
282
- minifyIdentifiers: !this._options.watch,
283
- minifySyntax: !this._options.watch,
284
- minifyWhitespace: !this._options.watch,
285
- pure: ['forwardRef'],
286
- outdir: this._options.workspaceRoot,
287
- outExtension: undefined,
288
- sourcemap: this._options.watch,
289
- splitting: true,
290
- chunkNames: 'chunk-[hash]',
291
- tsconfig: this._options.tsconfig,
292
- external: [],
293
- write: false,
294
- preserveSymlinks: false,
295
- define: {
296
- ...!this._options.watch ? {ngDevMode: 'false'} : {},
297
- ngJitMode: 'false',
298
- global: 'global',
299
- process: 'process',
300
- Buffer: 'Buffer',
301
- 'process.env.SD_VERSION': JSON.stringify(pkgNpmConf.version),
302
- "process.env.NODE_ENV": JSON.stringify(this._options.watch ? "development" : "production")
303
- },
304
- platform: 'browser',
305
- mainFields: ['es2020', 'es2015', 'browser', 'module', 'main'],
306
- entryNames: '[name]',
307
- entryPoints: {
308
- ...this._options.entryPoints,
309
- polyfills: 'angular:polyfills'
310
- },
311
- target: [
312
- 'chrome117.0', 'chrome116.0',
313
- 'edge117.0', 'edge116.0',
314
- 'firefox118.0', 'firefox115.0',
315
- 'ios17.0', 'ios16.6',
316
- 'ios16.5', 'ios16.4',
317
- 'ios16.3', 'ios16.2',
318
- 'ios16.1', 'ios16.0',
319
- 'safari17.0', 'safari16.6',
320
- 'safari16.5', 'safari16.4',
321
- 'safari16.3', 'safari16.2',
322
- 'safari16.1', 'safari16.0'
323
- ],
324
- supported: {'async-await': false, 'object-rest-spread': false},
325
- loader: {
326
- ".png": "file",
327
- ".jpeg": "file",
328
- ".jpg": "file",
329
- ".jfif": "file",
330
- ".gif": "file",
331
- ".svg": "file",
332
- ".woff": "file",
333
- ".woff2": "file",
334
- ".ttf": "file",
335
- ".eot": "file",
336
- ".ico": "file",
337
- ".otf": "file",
338
- ".csv": "file",
339
- ".xlsx": "file",
340
- ".xls": "file",
341
- ".pptx": "file",
342
- ".ppt": "file",
343
- ".docx": "file",
344
- ".doc": "file",
345
- ".zip": "file",
346
- ".pfx": "file",
347
- ".pkl": "file"
529
+ const pluginFactory = new StylesheetPluginFactory(
530
+ {
531
+ sourcemap: this._opt.dev,
532
+ includePaths: []
348
533
  },
349
- inject: [PathUtil.posix(fileURLToPath(await import.meta.resolve!("node-stdlib-browser/helpers/esbuild/shim")))],
350
- plugins: [
351
- createVirtualModulePlugin({
352
- namespace: "angular:polyfills",
353
- loadContent: () => ({
354
- contents: `import "./src/polyfills.ts";`,
355
- loader: 'js',
356
- resolveDir: this._options.workspaceRoot
357
- })
358
- }) as esbuild.Plugin,
359
- createSourcemapIgnorelistPlugin(),
360
- createCompilerPlugin(
361
- pluginOptions,
362
- styleOptions
363
- ) as esbuild.Plugin,
364
- nodeStdLibBrowserPlugin(nodeStdLibBrowser)
365
- ]
366
- };
367
- }
368
-
369
- private _getOptions(opt: {
370
- dev: boolean,
371
- builderType: keyof ISdCliClientPackageConfig["builder"],
372
- pkgPath: string,
373
- cordovaPlatforms: string[] | undefined,
374
- outputPath: string,
375
- }): NormalizedApplicationBuildOptions {
376
- const mainFilePath = path.resolve(opt.pkgPath, "src/main.ts");
377
- const tsconfigFilePath = path.resolve(opt.pkgPath, "tsconfig.json");
378
- const indexHtmlFilePath = path.resolve(opt.pkgPath, "src/index.html");
379
- const swFilePath = path.resolve(opt.pkgPath, "ngsw-config.json");
380
-
381
- const cacheBasePath = path.resolve(opt.pkgPath, ".cache");
382
-
383
- const pkgName = path.basename(opt.pkgPath);
534
+ this._sourceFileCache.loadResultCache,
535
+ );
384
536
 
385
- return {
386
- advancedOptimizations: true,
387
- allowedCommonJsDependencies: [],
388
- baseHref: `/${pkgName}/`,
389
- cacheOptions: {
390
- enabled: true,
391
- basePath: cacheBasePath,
392
- path: path.resolve(cacheBasePath, opt.builderType)
393
- },
394
- crossOrigin: CrossOrigin.None,
395
- deleteOutputPath: true,
396
- externalDependencies: [],
397
- extractLicenses: !opt.dev,
398
- inlineStyleLanguage: 'scss',
399
- jit: false,
400
- stats: false,
401
- polyfills: ["./src/polyfills.ts"],
402
- poll: undefined,
403
- progress: true,
404
- externalPackages: opt.dev ? true : undefined,
405
- preserveSymlinks: false,
406
- stylePreprocessorOptions: {includePaths: []},
407
- subresourceIntegrity: false,
408
- serverEntryPoint: undefined,
409
- prerenderOptions: undefined,
410
- appShellOptions: undefined,
411
- ssrOptions: undefined,
412
- verbose: false,
413
- watch: opt.dev,
414
- workspaceRoot: opt.pkgPath,
415
- entryPoints: {
416
- main: mainFilePath,
417
- ...opt.builderType === "cordova" ? {
418
- "cordova-entry": path.resolve(path.dirname(fileURLToPath(import.meta.url)), `../../lib/cordova-entry.js`)
419
- } : {}
420
- },
421
- optimizationOptions: {
422
- scripts: !opt.dev,
423
- styles: {minify: !opt.dev, inlineCritical: !opt.dev},
424
- fonts: {inline: !opt.dev}
425
- },
426
- outputPath: opt.outputPath,
427
- outExtension: undefined,
428
- sourcemapOptions: {vendor: false, hidden: false, scripts: opt.dev, styles: opt.dev},
429
- tsconfig: tsconfigFilePath,
430
- projectRoot: opt.pkgPath,
431
- assets: [
432
- {input: 'src', glob: 'favicon.ico', output: ''},
433
- {input: 'src\\assets', glob: '**/*', output: 'assets'},
434
- ...opt.dev && opt.cordovaPlatforms ? opt.cordovaPlatforms.mapMany((platform) => [
435
- {
436
- input: `.cache\\cordova\\platforms\\${platform}\\platform_www\\plugins`,
437
- glob: '**/*',
438
- output: `cordova-${platform}/plugins`
439
- },
440
- {
441
- input: `.cache\\cordova\\platforms\\${platform}\\platform_www`,
442
- glob: 'cordova.js',
443
- output: `cordova-${platform}`
444
- },
445
- {
446
- input: `.cache\\cordova\\platforms\\${platform}\\platform_www`,
447
- glob: 'cordova_plugins.js',
448
- output: `cordova-${platform}`
449
- },
450
- {
451
- input: `.cache\\cordova\\platforms\\${platform}\\www`,
452
- glob: 'config.xml',
453
- output: `cordova-${platform}`
454
- },
455
- ]) : []
456
- ],
457
- outputNames: {bundles: '[name]', media: 'media/[name]'},
458
- fileReplacements: undefined,
459
- globalStyles: [{name: 'styles', files: ["src/styles.scss"], initial: true}],
460
- globalScripts: [],
461
- serviceWorker: FsUtil.exists(swFilePath) ? swFilePath : undefined,
462
- indexHtmlOptions: {
463
- input: indexHtmlFilePath,
464
- output: 'index.html',
465
- insertionOrder: [
466
- ['runtime', true],
467
- ['polyfills', true],
468
- ['styles', false],
469
- ['vendor', true],
470
- ['main', true],
471
- ...opt.builderType === "cordova" ? [
472
- ["cordova-entry", true] as Entrypoint
473
- ] : []
474
- ]
537
+ return new BundlerContext(
538
+ this._opt.pkgPath,
539
+ true,
540
+ {
541
+ absWorkingDir: this._opt.pkgPath,
542
+ bundle: true,
543
+ entryNames: '[name]',
544
+ assetNames: 'media/[name]',
545
+ logLevel: 'silent',
546
+ minify: !this._opt.dev,
547
+ metafile: true,
548
+ sourcemap: this._opt.dev,
549
+ outdir: this._opt.pkgPath,
550
+ write: false,
551
+ platform: 'browser',
552
+ target: browserTarget,
553
+ preserveSymlinks: false,
554
+ external: [],
555
+ conditions: ['style', 'sass'],
556
+ mainFields: ['style', 'sass'],
557
+ legalComments: !this._opt.dev ? "none" : "eof",
558
+ entryPoints: {styles: 'angular:styles/global;styles'},
559
+ plugins: [
560
+ createVirtualModulePlugin({
561
+ namespace: "angular:styles/global",
562
+ transformPath: (currPath) => currPath.split(';', 2)[1],
563
+ loadContent: () => ({
564
+ contents: `@import 'src/styles.scss';`,
565
+ loader: 'css',
566
+ resolveDir: this._opt.pkgPath
567
+ }),
568
+ }),
569
+ pluginFactory.create(SassStylesheetLanguage),
570
+ pluginFactory.create(CssStylesheetLanguage),
571
+ createCssResourcePlugin(this._sourceFileCache.loadResultCache),
572
+ ],
475
573
  },
476
- tailwindConfiguration: undefined
477
- };
574
+ () => true
575
+ );
478
576
  }
479
577
  }