@simplysm/sd-cli 11.0.8 → 11.0.11

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 (64) 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.d.ts +21 -0
  4. package/dist/build-tools/SdCliCordova.js +182 -0
  5. package/dist/build-tools/SdCliCordova.js.map +1 -0
  6. package/dist/build-tools/SdCliNgRoutesFileGenerator.d.ts +4 -0
  7. package/dist/build-tools/SdCliNgRoutesFileGenerator.js +64 -0
  8. package/dist/build-tools/SdCliNgRoutesFileGenerator.js.map +1 -0
  9. package/dist/build-tools/SdLinter.js +8 -1
  10. package/dist/build-tools/SdLinter.js.map +1 -1
  11. package/dist/build-tools/SdNgBundler.d.ts +16 -5
  12. package/dist/build-tools/SdNgBundler.js +280 -179
  13. package/dist/build-tools/SdNgBundler.js.map +1 -1
  14. package/dist/build-tools/SdTsBundler.d.ts +6 -5
  15. package/dist/build-tools/SdTsBundler.js +78 -80
  16. package/dist/build-tools/SdTsBundler.js.map +1 -1
  17. package/dist/build-tools/SdTsCompiler.d.ts +1 -0
  18. package/dist/build-tools/SdTsCompiler.js +5 -1
  19. package/dist/build-tools/SdTsCompiler.js.map +1 -1
  20. package/dist/builders/SdCliClientBuilder.d.ts +1 -0
  21. package/dist/builders/SdCliClientBuilder.js +62 -27
  22. package/dist/builders/SdCliClientBuilder.js.map +1 -1
  23. package/dist/builders/SdCliServerBuilder.d.ts +6 -2
  24. package/dist/builders/SdCliServerBuilder.js +107 -141
  25. package/dist/builders/SdCliServerBuilder.js.map +1 -1
  26. package/dist/builders/SdCliTsLibBuilder.d.ts +6 -3
  27. package/dist/builders/SdCliTsLibBuilder.js +42 -45
  28. package/dist/builders/SdCliTsLibBuilder.js.map +1 -1
  29. package/dist/commons.d.ts +22 -2
  30. package/dist/entry/SdCliElectron.js +3 -3
  31. package/dist/entry/SdCliElectron.js.map +1 -1
  32. package/dist/entry/SdCliProject.d.ts +0 -3
  33. package/dist/entry/SdCliProject.js +10 -33
  34. package/dist/entry/SdCliProject.js.map +1 -1
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.js +4 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/sd-cli.js +27 -21
  39. package/dist/sd-cli.js.map +1 -1
  40. package/dist/utils/SdMemoryLoadResultCache.d.ts +9 -0
  41. package/dist/utils/SdMemoryLoadResultCache.js +39 -0
  42. package/dist/utils/SdMemoryLoadResultCache.js.map +1 -0
  43. package/dist/utils/SdSourceFileCache.d.ts +5 -0
  44. package/dist/utils/SdSourceFileCache.js +9 -0
  45. package/dist/utils/SdSourceFileCache.js.map +1 -0
  46. package/lib/cordova-entry.js +22 -0
  47. package/package.json +19 -16
  48. package/src/build-cluster.ts +26 -36
  49. package/src/build-tools/SdCliCordova.ts +240 -0
  50. package/src/build-tools/SdCliNgRoutesFileGenerator.ts +80 -0
  51. package/src/build-tools/SdLinter.ts +12 -1
  52. package/src/build-tools/SdNgBundler.ts +428 -288
  53. package/src/build-tools/SdTsBundler.ts +86 -86
  54. package/src/build-tools/SdTsCompiler.ts +6 -1
  55. package/src/builders/SdCliClientBuilder.ts +76 -34
  56. package/src/builders/SdCliServerBuilder.ts +64 -63
  57. package/src/builders/SdCliTsLibBuilder.ts +58 -50
  58. package/src/commons.ts +24 -2
  59. package/src/entry/SdCliElectron.ts +3 -3
  60. package/src/entry/SdCliProject.ts +12 -41
  61. package/src/index.ts +4 -0
  62. package/src/sd-cli.ts +31 -21
  63. package/src/utils/SdMemoryLoadResultCache.ts +44 -0
  64. 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 {
@@ -18,24 +12,61 @@ 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
14
  import {INpmConfig, ISdCliPackageBuildResult} from "../commons";
21
- import {generateIndexHtml} from "@angular-devkit/build-angular/src/tools/esbuild/index-html-generator";
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";
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";
26
35
 
27
36
  export class SdNgBundler {
28
- private readonly _logger = Logger.get(["simplysm", "sd-cli", "SdNgEsbuildBuilder"]);
29
-
30
- private readonly _sourceFileCache = new SourceFileCache();
31
- private readonly _options: NormalizedApplicationBuildOptions;
37
+ private readonly _sourceFileCache = new SdSourceFileCache();
32
38
 
33
39
  private _contexts: BundlerContext[] | undefined;
34
40
 
35
41
  private readonly _outputCache = new Map<string, string | number>();
36
42
 
37
- public constructor(private readonly _opt: { dev: boolean, builderType: string, pkgPath: string }) {
38
- this._options = this._getOptions(_opt);
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;
61
+ }) {
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}/` : ``;
39
70
  }
40
71
 
41
72
  public removeCache(filePaths: string[]): void {
@@ -62,45 +93,46 @@ export class SdNgBundler {
62
93
  line: warn.location?.line,
63
94
  char: warn.location?.column,
64
95
  code: undefined,
65
- severity: "warning" as const,
96
+ severity: "warning",
66
97
  message: warn.text.replace(/^(NG|TS)[0-9]+: /, ""),
67
- type: "build" as const
98
+ type: "build"
68
99
  })),
69
100
  ...bundlingResult.errors?.map((err) => ({
70
101
  filePath: err.location?.file !== undefined ? path.resolve(this._opt.pkgPath, err.location.file) : undefined,
71
102
  line: err.location?.line,
72
103
  char: err.location?.column !== undefined ? err.location.column + 1 : undefined,
73
104
  code: undefined,
74
- severity: "error" as const,
105
+ severity: "error",
75
106
  message: err.text.replace(/^[^:]*: /, ""),
76
- type: "build" as const
107
+ type: "build"
77
108
  })) ?? []
78
- ];
109
+ ] as ISdCliPackageBuildResult[];
79
110
  const watchFilePaths = [
80
111
  ...this._sourceFileCache.keys(),
81
- ...this._sourceFileCache.babelFileCache.keys()
82
- ].map((item) => path.resolve(item));
112
+ ...this._sourceFileCache.babelFileCache.keys(),
113
+ ...this._sourceFileCache.loadResultCache.fileDependencies.keys()
114
+ ].map((item) => path.resolve(item)).distinct();
115
+
83
116
  let affectedSourceFilePaths = watchFilePaths.filter((item) => PathUtil.isChildPath(item, this._opt.pkgPath));
117
+
84
118
  if (bundlingResult.errors) {
85
- return {
86
- filePaths: watchFilePaths,
87
- affectedFilePaths: affectedSourceFilePaths,
88
- results
89
- };
119
+ // TODO: 제대로 deps를 적용해야함.. 코드 분석 필요
120
+ this._depsMap = this._depsMap ?? new Map<string, Set<string>>();
90
121
  }
91
-
92
- const depsMap = new Map<string, Set<string>>();
93
- for (const entry of Object.entries(bundlingResult.metafile.inputs)) {
94
- for (const imp of entry[1].imports) {
95
- const deps = depsMap.getOrCreate(path.resolve(this._opt.pkgPath, imp.path), new Set<string>());
96
- deps.add(path.resolve(this._opt.pkgPath, 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
+ }
97
129
  }
98
130
  }
99
131
 
100
132
  const searchAffectedFiles = (filePath: string, prev?: Set<string>): Set<string> => {
101
133
  const result = new Set<string>(prev);
102
134
 
103
- const importerPaths = depsMap.get(filePath);
135
+ const importerPaths = this._depsMap!.get(filePath);
104
136
  if (!importerPaths) return result;
105
137
 
106
138
  for (const importerPath of importerPaths) {
@@ -121,65 +153,96 @@ export class SdNgBundler {
121
153
  affectedSourceFilePaths = Array.from(affectedFilePathSet.values()).filter((item) => PathUtil.isChildPath(item, this._opt.pkgPath));
122
154
  }
123
155
 
156
+ if (bundlingResult.errors) {
157
+ return {
158
+ filePaths: watchFilePaths,
159
+ affectedFilePaths: affectedSourceFilePaths,
160
+ results
161
+ };
162
+ }
163
+
124
164
  const executionResult = new ExecutionResult(this._contexts, this._sourceFileCache);
125
165
  executionResult.outputFiles.push(...bundlingResult.outputFiles);
126
166
 
127
- //-- index
128
- if (this._options.indexHtmlOptions) {
129
- const genIndexHtmlResult = await generateIndexHtml(
130
- bundlingResult.initialFiles,
131
- executionResult,
132
- this._options
133
- );
134
- if (genIndexHtmlResult.warnings.length > 0) {
135
- this._logger.warn(...genIndexHtmlResult.warnings);
136
- }
137
- if (genIndexHtmlResult.errors.length > 0) {
138
- this._logger.warn(...genIndexHtmlResult.errors);
139
- }
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
+ // }
140
182
 
141
- 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
+ });
142
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);
143
211
 
144
212
  //-- copy assets
145
- if (this._options.assets) {
146
- executionResult.assetFiles.push(...(await copyAssets(this._options.assets!, [], this._options.workspaceRoot)));
147
- }
213
+ executionResult.assetFiles.push(...(await this._copyAssetsAsync()));
148
214
 
149
215
  //-- extract 3rdpartylicenses
150
- if (this._options.extractLicenses) {
151
- 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));
152
218
  }
153
219
 
154
220
  //-- service worker
155
- if (this._options.serviceWorker !== undefined) {
221
+ if (FsUtil.exists(this._swConfFilePath)) {
156
222
  try {
157
- const serviceWorkerResult = await augmentAppWithServiceWorkerEsbuild(
158
- this._options.workspaceRoot,
159
- this._options.serviceWorker,
160
- this._options.baseHref ?? '/',
223
+ const serviceWorkerResult = await this._genServiceWorkerAsync(
161
224
  executionResult.outputFiles,
162
225
  executionResult.assetFiles
163
226
  );
164
227
  executionResult.addOutputFile('ngsw.json', serviceWorkerResult.manifest);
165
228
  executionResult.assetFiles.push(...serviceWorkerResult.assetFiles);
166
229
  }
167
- catch (error) {
168
- this._logger.error(error instanceof Error ? error.message : `${error}`);
169
-
170
- return {
171
- filePaths: watchFilePaths,
172
- affectedFilePaths: affectedSourceFilePaths,
173
- results
174
- };
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
+ });
175
240
  }
176
241
  }
177
242
 
178
243
  //-- write
179
-
180
- const distPath = path.resolve(this._options.outputPath, "dist", ...(this._opt.builderType === "web" ? [] : [this._opt.builderType]));
181
244
  for (const outputFile of executionResult.outputFiles) {
182
- const distFilePath = path.resolve(distPath, outputFile.path);
245
+ const distFilePath = path.resolve(this._opt.outputPath, outputFile.path);
183
246
 
184
247
  const prev = this._outputCache.get(distFilePath);
185
248
  if (prev !== Buffer.from(outputFile.contents).toString("base64")) {
@@ -191,7 +254,7 @@ export class SdNgBundler {
191
254
  const prev = this._outputCache.get(assetFile.source);
192
255
  const curr = FsUtil.lstat(assetFile.source).mtime.getTime();
193
256
  if (prev !== curr) {
194
- await FsUtil.copyAsync(assetFile.source, path.resolve(distPath, assetFile.destination));
257
+ await FsUtil.copyAsync(assetFile.source, path.resolve(this._opt.outputPath, assetFile.destination));
195
258
  this._outputCache.set(assetFile.source, curr);
196
259
  }
197
260
  }
@@ -203,235 +266,312 @@ export class SdNgBundler {
203
266
  };
204
267
  }
205
268
 
206
- private async _getAppContextAsync(): Promise<BundlerContext> {
207
- 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
+ }
208
279
 
209
- return new BundlerContext(
210
- this._options.workspaceRoot,
211
- true,
212
- esbuildOption
213
- );
214
- }
280
+ throw new Error(`Output file does not exist: ${relFilePath}`);
281
+ };
215
282
 
216
- private _getStyleContext(): BundlerContext {
217
- const esbuildOptions = createGlobalStylesBundleOptions(
218
- this._options,
219
- [
220
- 'chrome117.0', 'chrome116.0',
221
- 'edge117.0', 'edge116.0',
222
- 'firefox118.0', 'firefox115.0',
223
- 'ios17.0', 'ios16.6',
224
- 'ios16.5', 'ios16.4',
225
- 'ios16.3', 'ios16.2',
226
- 'ios16.1', 'ios16.0',
227
- 'safari17.0', 'safari16.6',
228
- 'safari16.5', 'safari16.4',
229
- 'safari16.3', 'safari16.2',
230
- '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
+ ] : []
231
294
  ],
232
- true,
233
- 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
234
408
  );
409
+ }
235
410
 
411
+ private async _getAppContextAsync(): Promise<BundlerContext> {
236
412
  return new BundlerContext(
237
- this._options.workspaceRoot,
413
+ this._opt.pkgPath,
238
414
  true,
239
- esbuildOptions!,
240
- () => 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
+ }
241
523
  );
242
524
  }
243
525
 
244
- private async _getEsBuildOptionsAsync(): Promise<esbuild.BuildOptions> {
245
- const pkgNpmConf: INpmConfig = FsUtil.readJson(path.resolve(this._options.workspaceRoot, "package.json"));
246
-
247
- const {pluginOptions, styleOptions} = createCompilerPluginOptions(
248
- this._options,
249
- [
250
- 'chrome117.0', 'chrome116.0',
251
- 'edge117.0', 'edge116.0',
252
- 'firefox118.0', 'firefox115.0',
253
- 'ios17.0', 'ios16.6',
254
- 'ios16.5', 'ios16.4',
255
- 'ios16.3', 'ios16.2',
256
- 'ios16.1', 'ios16.0',
257
- 'safari17.0', 'safari16.6',
258
- 'safari16.5', 'safari16.4',
259
- 'safari16.3', 'safari16.2',
260
- 'safari16.1', 'safari16.0'
261
- ],
262
- this._sourceFileCache,
263
- );
526
+ private _getStyleContext(): BundlerContext {
527
+ const browserTarget = transformSupportedBrowsersToTargets(browserslist("defaults and fully supports es6-module"));
264
528
 
265
- return {
266
- absWorkingDir: this._options.workspaceRoot,
267
- bundle: true,
268
- keepNames: true,
269
- format: 'esm',
270
- assetNames: 'media/[name]',
271
- conditions: ['es2020', 'es2015', 'module'],
272
- resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
273
- metafile: true,
274
- legalComments: this._options.watch ? 'eof' : 'none',
275
- logLevel: 'silent',
276
- minifyIdentifiers: !this._options.watch,
277
- minifySyntax: !this._options.watch,
278
- minifyWhitespace: !this._options.watch,
279
- pure: ['forwardRef'],
280
- outdir: this._options.outputPath,
281
- outExtension: undefined,
282
- sourcemap: this._options.watch,
283
- splitting: true,
284
- chunkNames: 'chunk-[hash]',
285
- tsconfig: this._options.tsconfig,
286
- external: [],
287
- write: false,
288
- preserveSymlinks: false,
289
- define: {
290
- ...!this._options.watch ? {ngDevMode: 'false'} : {},
291
- ngJitMode: 'false',
292
- global: 'global',
293
- process: 'process',
294
- Buffer: 'Buffer',
295
- 'process.env.SD_VERSION': JSON.stringify(pkgNpmConf.version),
296
- "process.env.NODE_ENV": JSON.stringify(this._options.watch ? "development" : "production")
297
- },
298
- platform: 'browser',
299
- mainFields: ['es2020', 'es2015', 'browser', 'module', 'main'],
300
- entryNames: '[name]',
301
- entryPoints: {
302
- ...this._options.entryPoints,
303
- polyfills: 'angular:polyfills'
304
- },
305
- target: [
306
- 'chrome117.0', 'chrome116.0',
307
- 'edge117.0', 'edge116.0',
308
- 'firefox118.0', 'firefox115.0',
309
- 'ios17.0', 'ios16.6',
310
- 'ios16.5', 'ios16.4',
311
- 'ios16.3', 'ios16.2',
312
- 'ios16.1', 'ios16.0',
313
- 'safari17.0', 'safari16.6',
314
- 'safari16.5', 'safari16.4',
315
- 'safari16.3', 'safari16.2',
316
- 'safari16.1', 'safari16.0'
317
- ],
318
- supported: {'async-await': false, 'object-rest-spread': false},
319
- loader: {
320
- ".png": "file",
321
- ".jpeg": "file",
322
- ".jpg": "file",
323
- ".jfif": "file",
324
- ".gif": "file",
325
- ".svg": "file",
326
- ".woff": "file",
327
- ".woff2": "file",
328
- ".ttf": "file",
329
- ".eot": "file",
330
- ".ico": "file",
331
- ".otf": "file",
332
- ".csv": "file",
333
- ".xlsx": "file",
334
- ".xls": "file",
335
- ".pptx": "file",
336
- ".ppt": "file",
337
- ".docx": "file",
338
- ".doc": "file",
339
- ".zip": "file",
340
- ".pfx": "file",
341
- ".pkl": "file"
529
+ const pluginFactory = new StylesheetPluginFactory(
530
+ {
531
+ sourcemap: this._opt.dev,
532
+ includePaths: []
342
533
  },
343
- inject: [PathUtil.posix(fileURLToPath(await import.meta.resolve!("node-stdlib-browser/helpers/esbuild/shim")))],
344
- plugins: [
345
- createVirtualModulePlugin({
346
- namespace: "angular:polyfills",
347
- loadContent: () => ({
348
- contents: `import "./src/polyfills.ts";`,
349
- loader: 'js',
350
- resolveDir: this._options.workspaceRoot
351
- })
352
- }) as esbuild.Plugin,
353
- createSourcemapIgnorelistPlugin(),
354
- createCompilerPlugin(
355
- pluginOptions,
356
- styleOptions
357
- ) as esbuild.Plugin,
358
- nodeStdLibBrowserPlugin(nodeStdLibBrowser)
359
- ]
360
- };
361
- }
362
-
363
- private _getOptions(opt: { dev: boolean, builderType: string, pkgPath: string }): NormalizedApplicationBuildOptions {
364
- const mainFilePath = path.resolve(opt.pkgPath, "src/main.ts");
365
- const tsconfigFilePath = path.resolve(opt.pkgPath, "tsconfig.json");
366
- const indexHtmlFilePath = path.resolve(opt.pkgPath, "src/index.html");
367
- const swFilePath = path.resolve(opt.pkgPath, "ngsw-config.json");
368
-
369
- const cacheBasePath = path.resolve(opt.pkgPath, ".cache");
370
-
371
- const pkgName = path.basename(opt.pkgPath);
534
+ this._sourceFileCache.loadResultCache,
535
+ );
372
536
 
373
- return {
374
- advancedOptimizations: true,
375
- allowedCommonJsDependencies: [],
376
- baseHref: `/${pkgName}/`,
377
- cacheOptions: {
378
- enabled: true,
379
- basePath: cacheBasePath,
380
- path: path.resolve(cacheBasePath, opt.builderType)
381
- },
382
- crossOrigin: CrossOrigin.None,
383
- deleteOutputPath: true,
384
- externalDependencies: [],
385
- extractLicenses: !opt.dev,
386
- inlineStyleLanguage: 'scss',
387
- jit: false,
388
- stats: false,
389
- polyfills: ["./src/polyfills.ts"],
390
- poll: undefined,
391
- progress: true,
392
- externalPackages: opt.dev ? true : undefined,
393
- preserveSymlinks: false,
394
- stylePreprocessorOptions: {includePaths: []},
395
- subresourceIntegrity: false,
396
- serverEntryPoint: undefined,
397
- prerenderOptions: undefined,
398
- appShellOptions: undefined,
399
- ssrOptions: undefined,
400
- verbose: false,
401
- watch: opt.dev,
402
- workspaceRoot: opt.pkgPath,
403
- entryPoints: {main: mainFilePath},
404
- optimizationOptions: {
405
- scripts: !opt.dev,
406
- styles: {minify: !opt.dev, inlineCritical: !opt.dev},
407
- fonts: {inline: !opt.dev}
408
- },
409
- outputPath: opt.pkgPath,
410
- outExtension: undefined,
411
- sourcemapOptions: {vendor: false, hidden: false, scripts: opt.dev, styles: opt.dev},
412
- tsconfig: tsconfigFilePath,
413
- projectRoot: opt.pkgPath,
414
- assets: [
415
- {glob: 'favicon.ico', input: 'src', output: ''},
416
- {glob: '**/*', input: 'src\\assets', output: 'assets'}
417
- ],
418
- outputNames: {bundles: '[name]', media: 'media/[name]'},
419
- fileReplacements: undefined,
420
- globalStyles: [{name: 'styles', files: ["src/styles.scss"], initial: true}],
421
- globalScripts: [],
422
- serviceWorker: FsUtil.exists(swFilePath) ? swFilePath : undefined,
423
- indexHtmlOptions: {
424
- input: indexHtmlFilePath,
425
- output: 'index.html',
426
- insertionOrder: [
427
- ['runtime', true],
428
- ['polyfills', true],
429
- ['styles', false],
430
- ['vendor', true],
431
- ['main', true]
432
- ]
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
+ ],
433
573
  },
434
- tailwindConfiguration: undefined
435
- };
574
+ () => true
575
+ );
436
576
  }
437
577
  }