@angular-architects/native-federation-v4 20.3.6 → 20.3.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-architects/native-federation-v4",
3
- "version": "20.3.6",
3
+ "version": "20.3.7",
4
4
  "generators": "./collection.json",
5
5
  "builders": "./builders.json",
6
6
  "schematics": "./collection.json",
@@ -10,8 +10,8 @@
10
10
  "url": "http://www.angulararchitects.io"
11
11
  },
12
12
  "dependencies": {
13
- "@softarc/native-federation": "4.0.0-RC6",
14
- "@softarc/native-federation-runtime": "4.0.0-RC6",
13
+ "@softarc/native-federation": "4.0.0-RC8",
14
+ "@softarc/native-federation-runtime": "4.0.0-RC8",
15
15
  "@angular-devkit/architect": "^0.2003.1",
16
16
  "@angular-devkit/build-angular": "~20.3.1",
17
17
  "@angular-devkit/core": "~20.3.1",
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/builder.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAS1C,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAGnB,MAAM,2BAA2B,CAAC;AAiCnC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAyCnD,wBAAuB,UAAU,CAC/B,gBAAgB,EAAE,eAAe,EACjC,OAAO,EAAE,cAAc,GACtB,aAAa,CAAC,aAAa,CAAC,CAuW9B;wBA6C2C,GAAG;AAA/C,wBAAgD"}
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/builder.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAS1C,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAGnB,MAAM,2BAA2B,CAAC;AAgCnC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AA2CnD,wBAAuB,UAAU,CAC/B,gBAAgB,EAAE,eAAe,EACjC,OAAO,EAAE,cAAc,GACtB,aAAa,CAAC,aAAa,CAAC,CAkY9B;wBA6C2C,GAAG;AAA/C,wBAAgD"}
@@ -6,9 +6,7 @@ import { buildApplication } from '@angular/build';
6
6
  import { buildApplicationInternal, serveWithVite, SourceFileCache } from '@angular/build/private';
7
7
  import { createBuilder, targetFromTargetString, } from '@angular-devkit/architect';
8
8
  import { normalizeOptions } from '@angular-devkit/build-angular/src/builders/dev-server/options.js';
9
- import { buildForFederation, rebuildForFederation, getExternals, loadFederationConfig, normalizeFederationOptions, setBuildAdapter, createFederationCache,
10
- // type FederationCache,
11
- } from '@softarc/native-federation';
9
+ import { buildForFederation, rebuildForFederation, getExternals, loadFederationConfig, normalizeFederationOptions, setBuildAdapter, createFederationCache, } from '@softarc/native-federation';
12
10
  import { logger, setLogLevel, RebuildQueue, AbortedError, getDefaultCachePath, } from '@softarc/native-federation/internal';
13
11
  import { createAngularBuildAdapter } from '../../utils/angular-esbuild-adapter.js';
14
12
  import { existsSync, mkdirSync, rmSync } from 'fs';
@@ -38,6 +36,7 @@ const createInternalAngularBuilder = (_) => (options, context, pluginsOrExtensio
38
36
  else {
39
37
  extensions = pluginsOrExtensions;
40
38
  }
39
+ // Todo: share cache with Angular builder: https://github.com/angular/angular-cli/pull/32527
41
40
  // options.codeBundleCache = nfOptions.federationCache.bundlerCache;
42
41
  return buildApplicationInternal(options, context, extensions);
43
42
  };
@@ -117,7 +116,7 @@ export async function* runBuilder(nfBuilderOptions, context) {
117
116
  const devServerOutputPath = !differentDevServerOutputPath
118
117
  ? browserOutputPath
119
118
  : path.join(outputOptions.base, outputOptions.browser, localeFilter[0]);
120
- const entryPoint = path.join(path.dirname(options.tsConfig), 'src/main.ts');
119
+ const entryPoint = nfBuilderOptions.entryPoint ?? path.join(path.dirname(options.tsConfig), 'src/main.ts');
121
120
  const cachePath = getDefaultCachePath(context.workspaceRoot);
122
121
  const nfOptions = normalizeFederationOptions({
123
122
  workspaceRoot: context.workspaceRoot,
@@ -188,7 +187,6 @@ export async function* runBuilder(nfBuilderOptions, context) {
188
187
  },
189
188
  ];
190
189
  let first = true;
191
- let lastResult;
192
190
  if (existsSync(nfOptions.outputPath)) {
193
191
  rmSync(nfOptions.outputPath, { recursive: true });
194
192
  }
@@ -228,62 +226,85 @@ export async function* runBuilder(nfBuilderOptions, context) {
228
226
  indexHtmlTransformer: transformIndexHtml(nfBuilderOptions),
229
227
  });
230
228
  const rebuildQueue = new RebuildQueue();
229
+ const builderIterator = builderRun[Symbol.asyncIterator]();
230
+ let ngBuildStatus = { success: false };
231
231
  try {
232
- for await (const output of builderRun) {
233
- lastResult = output;
234
- if (!first && (nfBuilderOptions.dev || watch)) {
235
- rebuildQueue
236
- .enqueue(async (signal) => {
237
- if (signal?.aborted) {
238
- throw new AbortedError('Build canceled before starting');
239
- }
240
- await new Promise((resolve, reject) => {
241
- const timeout = setTimeout(resolve, Math.max(10, nfBuilderOptions.rebuildDelay));
242
- if (signal) {
243
- const abortHandler = () => {
244
- clearTimeout(timeout);
245
- reject(new AbortedError('[builder] During delay.'));
246
- };
247
- signal.addEventListener('abort', abortHandler, { once: true });
232
+ let buildResult = await builderIterator.next();
233
+ while (!buildResult.done) {
234
+ if (buildResult.value)
235
+ ngBuildStatus = buildResult.value;
236
+ if (!ngBuildStatus.success) {
237
+ logger.warn('Skipping federation artifacts because Angular build failed.');
238
+ buildResult = await builderIterator.next();
239
+ }
240
+ else if (!first && (nfBuilderOptions.dev || watch)) {
241
+ const nextOutputPromise = builderIterator.next();
242
+ const trackResult = await rebuildQueue.track(async (signal) => {
243
+ try {
244
+ if (signal?.aborted) {
245
+ throw new AbortedError('Build canceled before starting');
248
246
  }
249
- });
250
- if (signal?.aborted) {
251
- throw new AbortedError('[builder] Before federation build.');
252
- }
253
- const start = process.hrtime();
254
- // Invalidate all source files, Angular doesn't provide a way to give the invalidated files yet.
255
- const keys = new Set([...nfOptions.federationCache.bundlerCache.keys()].filter(k => !k.includes('node_modules')));
256
- nfOptions.federationCache.bundlerCache.invalidate(keys);
257
- federationResult = await rebuildForFederation(config, nfOptions, externals, [], signal);
258
- if (signal?.aborted) {
259
- throw new AbortedError('[builder] After federation build.');
260
- }
261
- if (hasLocales && localeFilter) {
262
- translateFederationArtifacts(i18n, localeFilter, outputOptions.base, federationResult);
263
- }
264
- if (signal?.aborted) {
265
- throw new AbortedError('[builder] After federation translations.');
266
- }
267
- logger.info('Done!');
268
- if (isLocalDevelopment) {
269
- federationBuildNotifier.broadcastBuildCompletion();
270
- }
271
- logger.measure(start, 'To rebuild the federation artifacts.');
272
- })
273
- .catch(error => {
274
- if (error instanceof AbortedError) {
275
- logger.verbose('Rebuild was canceled. Cancellation point: ' + error?.message);
276
- federationBuildNotifier.broadcastBuildCancellation();
247
+ await new Promise((resolve, reject) => {
248
+ const timeout = setTimeout(resolve, Math.max(10, nfBuilderOptions.rebuildDelay));
249
+ if (signal) {
250
+ const abortHandler = () => {
251
+ clearTimeout(timeout);
252
+ reject(new AbortedError('[builder] During delay.'));
253
+ };
254
+ signal.addEventListener('abort', abortHandler, { once: true });
255
+ }
256
+ });
257
+ if (signal?.aborted) {
258
+ throw new AbortedError('[builder] Before federation build.');
259
+ }
260
+ const start = process.hrtime();
261
+ // Todo: Invalidate all source files, Angular doesn't provide a way to give the invalidated files yet.
262
+ // ref: https://github.com/angular/angular-cli/pull/32527
263
+ const keys = [...nfOptions.federationCache.bundlerCache.keys()].filter(k => !k.includes('node_modules'));
264
+ federationResult = await rebuildForFederation(config, nfOptions, externals, keys, signal);
265
+ if (signal?.aborted) {
266
+ throw new AbortedError('[builder] After federation build.');
267
+ }
268
+ if (hasLocales && localeFilter) {
269
+ translateFederationArtifacts(i18n, localeFilter, outputOptions.base, federationResult);
270
+ }
271
+ if (signal?.aborted) {
272
+ throw new AbortedError('[builder] After federation translations.');
273
+ }
274
+ logger.info('Done!');
275
+ if (isLocalDevelopment) {
276
+ federationBuildNotifier.broadcastBuildCompletion();
277
+ }
278
+ logger.measure(start, 'To rebuild the federation artifacts.');
279
+ return { success: true };
277
280
  }
278
- else {
281
+ catch (error) {
282
+ if (error instanceof AbortedError) {
283
+ logger.verbose('Rebuild was canceled. Cancellation point: ' + error?.message);
284
+ federationBuildNotifier.broadcastBuildCancellation();
285
+ return { success: false, cancelled: true };
286
+ }
279
287
  logger.error('Federation rebuild failed!');
280
288
  if (options.verbose)
281
289
  console.error(error);
282
290
  if (isLocalDevelopment) {
283
291
  federationBuildNotifier.broadcastBuildError(error);
284
292
  }
293
+ return { success: false };
285
294
  }
286
- });
295
+ }, nextOutputPromise);
296
+ if (trackResult.type === 'completed') {
297
+ if (!trackResult.result.cancelled) {
298
+ yield { success: trackResult.result.success };
299
+ }
300
+ buildResult = await nextOutputPromise;
301
+ }
302
+ else {
303
+ buildResult = trackResult.value;
304
+ }
305
+ }
306
+ else {
307
+ buildResult = await builderIterator.next();
287
308
  }
288
309
  first = false;
289
310
  }
@@ -295,7 +316,7 @@ export async function* runBuilder(nfBuilderOptions, context) {
295
316
  federationBuildNotifier.stopEventServer();
296
317
  }
297
318
  }
298
- yield lastResult || { success: false };
319
+ yield ngBuildStatus;
299
320
  }
300
321
  function removeBaseHref(req, baseHref) {
301
322
  let url = req.url ?? '';
@@ -18,5 +18,6 @@ export interface NfBuilderSchema extends JsonObject {
18
18
  ssr: boolean;
19
19
  devServer?: boolean;
20
20
  chunks?: { enable: boolean; dense: true };
21
+ entryPoint?: string;
21
22
  cacheExternalArtifacts?: boolean;
22
23
  } // eslint-disable-line
@@ -23,6 +23,9 @@
23
23
  "type": "number",
24
24
  "default": 0
25
25
  },
26
+ "entryPoint": {
27
+ "type": "string"
28
+ },
26
29
  "open": {
27
30
  "type": "boolean",
28
31
  "default": true,
@@ -3,5 +3,7 @@
3
3
  * a shared cache between the compilation steps which
4
4
  * improves performance dramatically.
5
5
  */
6
- process.env['NG_BUILD_PARALLEL_TS'] = '0';
6
+ if (!process.env['NG_BUILD_PARALLEL_TS']) {
7
+ process.env['NG_BUILD_PARALLEL_TS'] = '0';
8
+ }
7
9
  export {};
@@ -0,0 +1,12 @@
1
+ import * as esbuild from 'esbuild';
2
+ import { type SourceFileCache } from '@angular/build/private';
3
+ import type { BuilderContext } from '@angular-devkit/architect';
4
+ import type { ApplicationBuilderOptions } from '@angular/build';
5
+ import type { EntryPoint, FederationCache } from '@softarc/native-federation';
6
+ import type { MappedPath } from '@softarc/native-federation/internal';
7
+ export interface AngularBundleResult {
8
+ ctx: esbuild.BuildContext;
9
+ pluginDisposed: Promise<void>;
10
+ }
11
+ export declare function createAngularEsbuildContext(builderOptions: ApplicationBuilderOptions, context: BuilderContext, entryPoints: EntryPoint[], external: string[], outdir: string, tsConfigPath: string, mappedPaths: MappedPath[], cache: FederationCache<SourceFileCache>, dev?: boolean, hash?: boolean, chunks?: boolean, platform?: 'browser' | 'node', optimizedMappings?: boolean): Promise<AngularBundleResult>;
12
+ //# sourceMappingURL=angular-bundler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"angular-bundler.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-bundler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAOnC,OAAO,EAML,KAAK,eAAe,EAErB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAOtE,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,wBAAsB,2BAA2B,CAC/C,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,EAAE,eAAe,CAAC,eAAe,CAAC,EACvC,GAAG,CAAC,EAAE,OAAO,EACb,IAAI,GAAE,OAAe,EACrB,MAAM,CAAC,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,EAC7B,iBAAiB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC,mBAAmB,CAAC,CAkI9B"}
@@ -0,0 +1,167 @@
1
+ import * as esbuild from 'esbuild';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { createRequire } from 'node:module';
5
+ import { isDeepStrictEqual } from 'node:util';
6
+ import JSON5 from 'json5';
7
+ import { transformSupportedBrowsersToTargets, getSupportedBrowsers, generateSearchDirectories, findTailwindConfiguration, loadPostcssConfiguration } from '@angular/build/private';
8
+ import { normalizeOptimization, normalizeSourceMaps, } from '@angular-devkit/build-angular/src/utils/index.js';
9
+ import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
10
+ import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js';
11
+ export async function createAngularEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, hash = false, chunks, platform, optimizedMappings) {
12
+ const workspaceRoot = context.workspaceRoot;
13
+ const projectMetadata = await context.getProjectMetadata(context.target.project);
14
+ const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
15
+ const browsers = getSupportedBrowsers(projectRoot, context.logger);
16
+ const target = transformSupportedBrowsersToTargets(browsers);
17
+ const optimizationOptions = normalizeOptimization(builderOptions.optimization);
18
+ const sourcemapOptions = normalizeSourceMaps(builderOptions.sourceMap);
19
+ const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]);
20
+ const postcssConfiguration = await loadPostcssConfiguration(searchDirectories);
21
+ const tailwindConfiguration = postcssConfiguration
22
+ ? undefined
23
+ : await getTailwindConfig(searchDirectories);
24
+ const outputNames = {
25
+ bundles: '[name]',
26
+ media: 'media/[name]',
27
+ };
28
+ let fileReplacements;
29
+ if (builderOptions.fileReplacements) {
30
+ for (const replacement of builderOptions.fileReplacements) {
31
+ fileReplacements ??= {};
32
+ fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
33
+ }
34
+ }
35
+ tsConfigPath = createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings);
36
+ const pluginOptions = {
37
+ sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
38
+ thirdPartySourcemaps: sourcemapOptions.vendor,
39
+ tsconfig: tsConfigPath,
40
+ jit: false,
41
+ advancedOptimizations: !dev,
42
+ fileReplacements,
43
+ sourceFileCache: cache.bundlerCache,
44
+ loadResultCache: cache.bundlerCache.loadResultCache,
45
+ incremental: true,
46
+ includeTestMetadata: !optimizationOptions.scripts,
47
+ };
48
+ const stylesheetBundlerOptions = {
49
+ workspaceRoot,
50
+ inlineFonts: !!optimizationOptions.fonts.inline,
51
+ optimization: !!optimizationOptions.styles.minify,
52
+ sourcemap:
53
+ // Hidden component stylesheet sourcemaps are inaccessible which is effectively
54
+ // the same as being disabled. Disabling has the advantage of avoiding the overhead
55
+ // of sourcemap processing.
56
+ sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
57
+ outputNames,
58
+ includePaths: builderOptions.stylePreprocessorOptions?.includePaths,
59
+ sass: builderOptions?.stylePreprocessorOptions?.sass,
60
+ externalDependencies: external,
61
+ target,
62
+ inlineStyleLanguage: builderOptions.inlineStyleLanguage ?? 'css',
63
+ preserveSymlinks: builderOptions.preserveSymlinks,
64
+ tailwindConfiguration,
65
+ postcssConfiguration,
66
+ cacheOptions: {
67
+ enabled: true,
68
+ basePath: cache.cachePath,
69
+ path: cache.cachePath,
70
+ },
71
+ };
72
+ const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
73
+ const commonjsPlugin = commonjsPluginModule.default;
74
+ stylesheetBundlerOptions.externalDependencies = [];
75
+ const [compilerPlugin, pluginDisposed] = createAwaitableCompilerPlugin(pluginOptions, stylesheetBundlerOptions);
76
+ const config = {
77
+ entryPoints: entryPoints.map(ep => ({
78
+ in: ep.fileName,
79
+ out: path.parse(ep.outName).name,
80
+ })),
81
+ outdir,
82
+ entryNames: hash ? '[name]-[hash]' : '[name]',
83
+ write: false,
84
+ external,
85
+ logLevel: 'warning',
86
+ bundle: true,
87
+ sourcemap: sourcemapOptions.scripts,
88
+ minify: !dev,
89
+ supported: {
90
+ 'async-await': false,
91
+ 'object-rest-spread': false,
92
+ },
93
+ splitting: chunks,
94
+ platform: platform ?? 'browser',
95
+ format: 'esm',
96
+ target: target,
97
+ logLimit: 0,
98
+ plugins: [
99
+ compilerPlugin,
100
+ ...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
101
+ commonjsPlugin(),
102
+ ],
103
+ define: {
104
+ ...(!dev ? { ngDevMode: 'false' } : {}),
105
+ ngJitMode: 'false',
106
+ },
107
+ ...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
108
+ resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
109
+ };
110
+ const ctx = await esbuild.context(config);
111
+ return { ctx, pluginDisposed };
112
+ }
113
+ async function getTailwindConfig(searchDirectories) {
114
+ const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories);
115
+ if (!tailwindConfigurationPath) {
116
+ return undefined;
117
+ }
118
+ return {
119
+ file: tailwindConfigurationPath,
120
+ package: createRequire(tailwindConfigurationPath).resolve('tailwindcss'),
121
+ };
122
+ }
123
+ /**
124
+ * Creates a tsconfig.federation.json that includes the federation entry points.
125
+ */
126
+ function createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings) {
127
+ const fullTsConfigPath = path.join(workspaceRoot, tsConfigPath);
128
+ const tsconfigDir = path.dirname(fullTsConfigPath);
129
+ const tsconfigAsString = fs.readFileSync(fullTsConfigPath, 'utf-8');
130
+ const tsconfig = JSON5.parse(tsconfigAsString);
131
+ tsconfig.files = entryPoints
132
+ .filter(ep => ep.fileName.startsWith('.'))
133
+ .map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
134
+ if (optimizedMappings) {
135
+ const filtered = entryPoints
136
+ .filter(ep => !ep.fileName.startsWith('.'))
137
+ .map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
138
+ if (!tsconfig.include) {
139
+ tsconfig.include = [];
140
+ }
141
+ for (const ep of filtered) {
142
+ if (!tsconfig.include.includes(ep)) {
143
+ tsconfig.include.push(ep);
144
+ }
145
+ }
146
+ }
147
+ const content = JSON5.stringify(tsconfig, null, 2);
148
+ const tsconfigFedPath = path.join(tsconfigDir, 'tsconfig.federation.json');
149
+ if (!doesFileExistAndJsonEqual(tsconfigFedPath, content)) {
150
+ fs.writeFileSync(tsconfigFedPath, JSON.stringify(tsconfig, null, 2));
151
+ }
152
+ return tsconfigFedPath;
153
+ }
154
+ function doesFileExistAndJsonEqual(filePath, content) {
155
+ if (!fs.existsSync(filePath)) {
156
+ return false;
157
+ }
158
+ try {
159
+ const currentContent = fs.readFileSync(filePath, 'utf-8');
160
+ const currentJson = JSON5.parse(currentContent);
161
+ const newJson = JSON5.parse(content);
162
+ return isDeepStrictEqual(currentJson, newJson);
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ }
@@ -1,6 +1,10 @@
1
1
  import { type NFBuildAdapter } from '@softarc/native-federation';
2
+ import * as esbuild from 'esbuild';
2
3
  import type { BuilderContext } from '@angular-devkit/architect';
3
4
  import type { ApplicationBuilderOptions } from '@angular/build';
5
+ export interface EsbuildContextResult {
6
+ ctx: esbuild.BuildContext;
7
+ pluginDisposed: Promise<void>;
8
+ }
4
9
  export declare function createAngularBuildAdapter(builderOptions: ApplicationBuilderOptions, context: BuilderContext): NFBuildAdapter;
5
- export declare function loadEsmModule<T>(modulePath: string | URL): Promise<T>;
6
10
  //# sourceMappingURL=angular-esbuild-adapter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,4BAA4B,CAAC;AAepC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAShE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAuBhE,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,GACtB,cAAc,CAwHhB;AAoQD,wBAAgB,aAAa,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAErE"}
1
+ {"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AA+FD,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,GACtB,cAAc,CAqHhB"}
@@ -1,74 +1,101 @@
1
- import { logger, AbortedError } from '@softarc/native-federation/internal';
2
- import * as esbuild from 'esbuild';
3
- import { transformSupportedBrowsersToTargets, getSupportedBrowsers, generateSearchDirectories, findTailwindConfiguration, loadPostcssConfiguration, } from '@angular/build/private';
4
- import { createCompilerPluginOptions } from './create-compiler-options.js';
5
- import { normalizeOptimization, normalizeSourceMaps, } from '@angular-devkit/build-angular/src/utils/index.js';
6
- import { createRequire } from 'node:module';
7
1
  import * as fs from 'fs';
8
2
  import * as path from 'path';
9
- import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
10
- import { transformAsync } from '@babel/core';
11
- import JSON5 from 'json5';
12
- import { isDeepStrictEqual } from 'node:util';
13
- import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js';
3
+ import { AbortedError } from '@softarc/native-federation/internal';
4
+ import * as esbuild from 'esbuild';
5
+ import { createAngularEsbuildContext } from './angular-bundler.js';
6
+ import { createNodeModulesEsbuildContext } from './node-modules-bundler.js';
7
+ async function createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, isNodeModules, hash = false, chunks, platform, optimizedMappings) {
8
+ if (isNodeModules) {
9
+ return createNodeModulesEsbuildContext(builderOptions, context, entryPoints, external, outdir, mappedPaths, cache, dev, hash, chunks, platform);
10
+ }
11
+ return createAngularEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, hash, chunks, platform, optimizedMappings);
12
+ }
13
+ function writeResult(result, outdir) {
14
+ const writtenFiles = [];
15
+ for (const outFile of result.outputFiles ?? []) {
16
+ const fileName = path.basename(outFile.path);
17
+ const filePath = path.join(outdir, fileName);
18
+ fs.writeFileSync(filePath, outFile.text);
19
+ writtenFiles.push(filePath);
20
+ }
21
+ return writtenFiles;
22
+ }
23
+ /**
24
+ * Patches @angular/core to infer ngServerMode at runtime.
25
+ * Usually, ngServerMode is set during bundling. However, we need to infer this
26
+ * value at runtime as we are using the same shared bundle for @angular/core
27
+ * on the server and in the browser.
28
+ */
29
+ function setNgServerMode() {
30
+ const fileToPatch = 'node_modules/@angular/core/fesm2022/core.mjs';
31
+ const lineToAdd = `if (typeof globalThis.ngServerMode ==='undefined') globalThis.ngServerMode = (typeof window === 'undefined') ? true : false;`;
32
+ try {
33
+ if (fs.existsSync(fileToPatch)) {
34
+ let content = fs.readFileSync(fileToPatch, 'utf-8');
35
+ if (!content.includes(lineToAdd)) {
36
+ content = lineToAdd + '\n' + content;
37
+ fs.writeFileSync(fileToPatch, content);
38
+ }
39
+ }
40
+ }
41
+ catch {
42
+ console.error('Error patching file ', fileToPatch, '\nIs it write-protected?');
43
+ }
44
+ }
14
45
  export function createAngularBuildAdapter(builderOptions, context) {
15
- const contextCache = new Map();
46
+ const bundleContextCache = new Map();
16
47
  const dispose = async (name) => {
17
48
  if (name) {
18
- if (!contextCache.has(name))
49
+ if (!bundleContextCache.has(name))
19
50
  throw new Error(`Could not dispose of non-existing build '${name}'`);
20
- const entry = contextCache.get(name);
51
+ const entry = bundleContextCache.get(name);
21
52
  await entry.ctx.dispose();
22
53
  await entry.pluginDisposed;
23
- contextCache.delete(name);
54
+ bundleContextCache.delete(name);
24
55
  return;
25
56
  }
26
- // Dispose all if no specific build provided
27
57
  const disposals = [];
28
- for (const [, entry] of contextCache) {
58
+ for (const [, entry] of bundleContextCache) {
29
59
  disposals.push((async () => {
30
60
  await entry.ctx.dispose();
31
61
  await entry.pluginDisposed;
32
62
  })());
33
63
  }
34
- contextCache.clear();
64
+ bundleContextCache.clear();
35
65
  await Promise.all(disposals);
66
+ await esbuild.stop();
36
67
  };
37
68
  const setup = async (options) => {
38
69
  const { entryPoints, tsConfigPath, external, outdir, mappedPaths, bundleName, isNodeModules, dev, chunks, hash, platform, optimizedMappings, cache, } = options;
39
70
  setNgServerMode();
40
- if (contextCache.has(bundleName)) {
71
+ if (bundleContextCache.has(bundleName)) {
41
72
  return;
42
73
  }
43
- const { ctx, pluginDisposed } = await createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache.bundlerCache, dev, isNodeModules, hash, chunks, platform, optimizedMappings);
44
- contextCache.set(bundleName, {
74
+ const { ctx, pluginDisposed } = await createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, isNodeModules, hash, chunks, platform, optimizedMappings);
75
+ bundleContextCache.set(bundleName, {
45
76
  ctx,
46
77
  pluginDisposed,
47
78
  outdir,
79
+ cache,
48
80
  isNodeModules,
49
81
  dev: !!dev,
50
82
  name: bundleName,
51
- entryPoints,
52
- workspaceRoot: context.workspaceRoot,
53
83
  });
54
84
  };
55
85
  const build = async (name, opts = {}) => {
56
- const cached = contextCache.get(name);
57
- if (!cached) {
86
+ const bundleContext = bundleContextCache.get(name);
87
+ if (!bundleContext) {
58
88
  throw new Error(`No context found for build "${name}". Call setup() first.`);
59
89
  }
60
90
  if (opts?.signal?.aborted) {
61
91
  throw new AbortedError('[build] Aborted before rebuild');
62
92
  }
63
93
  try {
64
- const result = await cached.ctx.rebuild();
65
- const writtenFiles = writeResult(result, cached.outdir);
66
- if (cached.isNodeModules) {
67
- const scriptFiles = writtenFiles.filter(f => f.endsWith('.js') || f.endsWith('.mjs'));
68
- for (const file of scriptFiles) {
69
- await link(file, cached.dev);
70
- }
94
+ if (opts.files) {
95
+ bundleContext.cache.bundlerCache.invalidate(new Set(opts.files));
71
96
  }
97
+ const result = await bundleContext.ctx.rebuild();
98
+ const writtenFiles = writeResult(result, bundleContext.outdir);
72
99
  return writtenFiles.map(fileName => ({ fileName }));
73
100
  }
74
101
  catch (error) {
@@ -80,209 +107,3 @@ export function createAngularBuildAdapter(builderOptions, context) {
80
107
  };
81
108
  return { setup, build, dispose };
82
109
  }
83
- async function link(outfile, dev) {
84
- const code = fs.readFileSync(outfile, 'utf-8');
85
- try {
86
- const linkerEsm = await loadEsmModule('@angular/compiler-cli/linker/babel');
87
- const linker = linkerEsm.default;
88
- const result = await transformAsync(code, {
89
- filename: outfile,
90
- compact: !dev,
91
- configFile: false,
92
- babelrc: false,
93
- minified: !dev,
94
- browserslistConfigFile: false,
95
- plugins: [linker],
96
- });
97
- if (!result)
98
- logger.warn(`File ${outfile} could not be linked.`);
99
- if (!result?.code) {
100
- logger.warn(`File ${outfile} seems to be empty.`);
101
- return;
102
- }
103
- fs.writeFileSync(outfile, result.code, 'utf-8');
104
- }
105
- catch (e) {
106
- logger.error('error linking');
107
- if (fs.existsSync(`${outfile}.error`)) {
108
- fs.unlinkSync(`${outfile}.error`);
109
- }
110
- fs.renameSync(outfile, `${outfile}.error`);
111
- throw e;
112
- }
113
- }
114
- async function createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, sourceFileCache, dev, isNodeModules, hash = false, chunks, platform, optimizedMappings) {
115
- const workspaceRoot = context.workspaceRoot;
116
- const projectMetadata = await context.getProjectMetadata(context.target.project);
117
- const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
118
- const browsers = getSupportedBrowsers(projectRoot, context.logger);
119
- const target = transformSupportedBrowsersToTargets(browsers);
120
- const optimizationOptions = normalizeOptimization(builderOptions.optimization);
121
- const sourcemapOptions = normalizeSourceMaps(builderOptions.sourceMap);
122
- const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]);
123
- const postcssConfiguration = await loadPostcssConfiguration(searchDirectories);
124
- const tailwindConfiguration = postcssConfiguration
125
- ? undefined
126
- : await getTailwindConfig(searchDirectories);
127
- const outputNames = {
128
- bundles: '[name]',
129
- media: 'media/[name]',
130
- };
131
- let fileReplacements;
132
- if (builderOptions.fileReplacements) {
133
- for (const replacement of builderOptions.fileReplacements) {
134
- fileReplacements ??= {};
135
- fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
136
- }
137
- }
138
- if (!optimizedMappings) {
139
- tsConfigPath = createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints);
140
- }
141
- const pluginOptions = createCompilerPluginOptions({
142
- workspaceRoot,
143
- optimizationOptions,
144
- sourcemapOptions,
145
- tsconfig: tsConfigPath,
146
- outputNames,
147
- fileReplacements,
148
- externalDependencies: external,
149
- preserveSymlinks: builderOptions.preserveSymlinks,
150
- stylePreprocessorOptions: builderOptions.stylePreprocessorOptions,
151
- advancedOptimizations: !dev,
152
- inlineStyleLanguage: builderOptions.inlineStyleLanguage,
153
- jit: false,
154
- tailwindConfiguration,
155
- postcssConfiguration,
156
- incremental: !isNodeModules,
157
- }, target, sourceFileCache);
158
- const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
159
- const commonjsPlugin = commonjsPluginModule.default;
160
- pluginOptions.styleOptions.externalDependencies = [];
161
- const [compilerPlugin, pluginDisposed] = createAwaitableCompilerPlugin(pluginOptions.pluginOptions, pluginOptions.styleOptions);
162
- const config = {
163
- entryPoints: entryPoints.map(ep => ({
164
- in: ep.fileName,
165
- out: path.parse(ep.outName).name,
166
- })),
167
- outdir,
168
- entryNames: hash ? '[name]-[hash]' : '[name]',
169
- write: false,
170
- external,
171
- logLevel: 'warning',
172
- bundle: true,
173
- sourcemap: sourcemapOptions.scripts,
174
- minify: !dev,
175
- supported: {
176
- 'async-await': false,
177
- 'object-rest-spread': false,
178
- },
179
- splitting: chunks,
180
- platform: platform ?? 'browser',
181
- format: 'esm',
182
- target: target,
183
- logLimit: isNodeModules ? 1 : 0,
184
- plugins: [
185
- compilerPlugin,
186
- ...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
187
- commonjsPlugin(),
188
- ],
189
- define: {
190
- ...(!dev ? { ngDevMode: 'false' } : {}),
191
- ngJitMode: 'false',
192
- },
193
- ...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
194
- resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
195
- };
196
- const ctx = await esbuild.context(config);
197
- return { ctx, pluginDisposed };
198
- }
199
- async function getTailwindConfig(searchDirectories) {
200
- const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories);
201
- if (!tailwindConfigurationPath) {
202
- return undefined;
203
- }
204
- return {
205
- file: tailwindConfigurationPath,
206
- package: createRequire(tailwindConfigurationPath).resolve('tailwindcss'),
207
- };
208
- }
209
- function createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints) {
210
- const fullTsConfigPath = path.join(workspaceRoot, tsConfigPath);
211
- const tsconfigDir = path.dirname(fullTsConfigPath);
212
- const filtered = entryPoints
213
- .filter(ep => !ep.fileName.includes('/node_modules/') && !ep.fileName.startsWith('.'))
214
- .map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
215
- const tsconfigAsString = fs.readFileSync(fullTsConfigPath, 'utf-8');
216
- const tsconfig = JSON5.parse(tsconfigAsString);
217
- if (!tsconfig.include) {
218
- tsconfig.include = [];
219
- }
220
- for (const ep of filtered) {
221
- if (!tsconfig.include.includes(ep)) {
222
- tsconfig.include.push(ep);
223
- }
224
- }
225
- const content = JSON5.stringify(tsconfig, null, 2);
226
- const tsconfigFedPath = path.join(tsconfigDir, 'tsconfig.federation.json');
227
- if (!doesFileExistAndJsonEqual(tsconfigFedPath, content)) {
228
- fs.writeFileSync(tsconfigFedPath, JSON.stringify(tsconfig, null, 2));
229
- }
230
- tsConfigPath = tsconfigFedPath;
231
- return tsConfigPath;
232
- }
233
- /**
234
- * Checks if a file exists and if its content is equal to the provided content.
235
- * If the file does not exist, it returns false.
236
- * If the file or its content is invalid JSON, it returns false.
237
- * @param {string} path - The path to the file
238
- * @param {string} content - The content to compare with
239
- * @returns {boolean} - Returns true if the file exists and its content is equal to the provided content
240
- */
241
- function doesFileExistAndJsonEqual(path, content) {
242
- if (!fs.existsSync(path)) {
243
- return false;
244
- }
245
- try {
246
- const currentContent = fs.readFileSync(path, 'utf-8');
247
- const currentJson = JSON5.parse(currentContent);
248
- const newJson = JSON5.parse(content);
249
- return isDeepStrictEqual(currentJson, newJson);
250
- }
251
- catch {
252
- return false;
253
- }
254
- }
255
- function writeResult(result, outdir) {
256
- const writtenFiles = [];
257
- for (const outFile of result.outputFiles ?? []) {
258
- const fileName = path.basename(outFile.path);
259
- const filePath = path.join(outdir, fileName);
260
- fs.writeFileSync(filePath, outFile.text);
261
- writtenFiles.push(filePath);
262
- }
263
- return writtenFiles;
264
- }
265
- export function loadEsmModule(modulePath) {
266
- return new Function('modulePath', `return import(modulePath);`)(modulePath);
267
- }
268
- //
269
- // Usually, ngServerMode is set during bundling. However, we need to infer this
270
- // value at runtime as we are using the same shared bundle for @angular/core
271
- // on the server and in the browser.
272
- //
273
- function setNgServerMode() {
274
- const fileToPatch = 'node_modules/@angular/core/fesm2022/core.mjs';
275
- const lineToAdd = `if (typeof globalThis.ngServerMode ==='undefined') globalThis.ngServerMode = (typeof window === 'undefined') ? true : false;`;
276
- try {
277
- if (fs.existsSync(fileToPatch)) {
278
- let content = fs.readFileSync(fileToPatch, 'utf-8');
279
- if (!content.includes(lineToAdd)) {
280
- content = lineToAdd + '\n' + content;
281
- fs.writeFileSync(fileToPatch, content);
282
- }
283
- }
284
- }
285
- catch {
286
- console.error('Error patching file ', fileToPatch, '\nIs it write-protected?');
287
- }
288
- }
@@ -0,0 +1,12 @@
1
+ import * as esbuild from 'esbuild';
2
+ import { type SourceFileCache } from '@angular/build/private';
3
+ import type { BuilderContext } from '@angular-devkit/architect';
4
+ import type { ApplicationBuilderOptions } from '@angular/build';
5
+ import type { EntryPoint, FederationCache } from '@softarc/native-federation';
6
+ import type { MappedPath } from '@softarc/native-federation/internal';
7
+ export interface NodeModulesBundleResult {
8
+ ctx: esbuild.BuildContext;
9
+ pluginDisposed: Promise<void>;
10
+ }
11
+ export declare function createNodeModulesEsbuildContext(builderOptions: ApplicationBuilderOptions, context: BuilderContext, entryPoints: EntryPoint[], external: string[], outdir: string, mappedPaths: MappedPath[], _cache: FederationCache<SourceFileCache>, dev?: boolean, hash?: boolean, chunks?: boolean, platform?: 'browser' | 'node'): Promise<NodeModulesBundleResult>;
12
+ //# sourceMappingURL=node-modules-bundler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-modules-bundler.d.ts","sourceRoot":"","sources":["../../../src/utils/node-modules-bundler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAInC,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAwDtE,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAID,wBAAsB,+BAA+B,CACnD,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,EACzB,MAAM,EAAE,eAAe,CAAC,eAAe,CAAC,EACxC,GAAG,CAAC,EAAE,OAAO,EACb,IAAI,GAAE,OAAe,EACrB,MAAM,CAAC,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAyElC"}
@@ -0,0 +1,101 @@
1
+ import * as esbuild from 'esbuild';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { transformSupportedBrowsersToTargets, getSupportedBrowsers, JavaScriptTransformer, } from '@angular/build/private';
5
+ import { normalizeSourceMaps } from '@angular-devkit/build-angular/src/utils/index.js';
6
+ import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
7
+ const LINKER_DECLARATION_PREFIX = 'ɵɵngDeclare';
8
+ /**
9
+ * Excludes @angular/core and @angular/compiler which define the declarations
10
+ * and would cause false positives.
11
+ */
12
+ function requiresLinking(filePath, source) {
13
+ if (/[\\/]@angular[\\/](?:compiler|core)[\\/]/.test(filePath)) {
14
+ return false;
15
+ }
16
+ return source.includes(LINKER_DECLARATION_PREFIX);
17
+ }
18
+ /**
19
+ * Creates an esbuild plugin that applies the Angular linker to partially compiled
20
+ * Angular libraries like a design system.
21
+ *
22
+ * Uses Angular's JavaScriptTransformer which handles linking internally.
23
+ */
24
+ function createAngularLinkerPlugin(jsTransformer, advancedOptimizations) {
25
+ return {
26
+ name: 'angular-linker',
27
+ setup(build) {
28
+ build.onLoad({ filter: /\.m?js$/ }, async (args) => {
29
+ const contents = await fs.promises.readFile(args.path, 'utf-8');
30
+ const needsLinking = requiresLinking(args.path, contents);
31
+ if (!needsLinking && !advancedOptimizations) {
32
+ return null;
33
+ }
34
+ const result = await jsTransformer.transformData(args.path, contents, !needsLinking, undefined);
35
+ return {
36
+ contents: Buffer.from(result).toString('utf-8'),
37
+ loader: 'js',
38
+ };
39
+ });
40
+ },
41
+ };
42
+ }
43
+ export async function createNodeModulesEsbuildContext(builderOptions, context, entryPoints, external, outdir, mappedPaths, _cache, dev, hash = false, chunks, platform) {
44
+ const workspaceRoot = context.workspaceRoot;
45
+ const projectMetadata = await context.getProjectMetadata(context.target.project);
46
+ const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
47
+ const browsers = getSupportedBrowsers(projectRoot, context.logger);
48
+ const target = transformSupportedBrowsersToTargets(browsers);
49
+ const sourcemapOptions = normalizeSourceMaps(builderOptions.sourceMap);
50
+ const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
51
+ const commonjsPlugin = commonjsPluginModule.default;
52
+ // Create JavaScriptTransformer for handling Angular partial compilation linking
53
+ const advancedOptimizations = !dev;
54
+ const jsTransformer = new JavaScriptTransformer({
55
+ sourcemap: !!sourcemapOptions.scripts,
56
+ thirdPartySourcemaps: false,
57
+ advancedOptimizations,
58
+ jit: false,
59
+ }, 1);
60
+ const config = {
61
+ entryPoints: entryPoints.map(ep => ({
62
+ in: ep.fileName,
63
+ out: path.parse(ep.outName).name,
64
+ })),
65
+ outdir,
66
+ entryNames: hash ? '[name]-[hash]' : '[name]',
67
+ write: false,
68
+ external,
69
+ logLevel: 'warning',
70
+ bundle: true,
71
+ sourcemap: sourcemapOptions.scripts,
72
+ minify: !dev,
73
+ supported: {
74
+ 'async-await': false,
75
+ 'object-rest-spread': false,
76
+ },
77
+ splitting: chunks,
78
+ platform: platform ?? 'browser',
79
+ format: 'esm',
80
+ target: target,
81
+ logLimit: 1,
82
+ plugins: [
83
+ createAngularLinkerPlugin(jsTransformer, advancedOptimizations),
84
+ ...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
85
+ commonjsPlugin(),
86
+ ],
87
+ define: {
88
+ ...(!dev ? { ngDevMode: 'false' } : {}),
89
+ ngJitMode: 'false',
90
+ },
91
+ ...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
92
+ resolveExtensions: ['.mjs', '.js', '.cjs'],
93
+ };
94
+ const ctx = await esbuild.context(config);
95
+ const originalDispose = ctx.dispose.bind(ctx);
96
+ ctx.dispose = async () => {
97
+ await originalDispose();
98
+ await jsTransformer.close();
99
+ };
100
+ return { ctx, pluginDisposed: Promise.resolve() };
101
+ }
@@ -1,6 +0,0 @@
1
- import { type SourceFileCache } from '@angular/build/private';
2
- export declare function createCompilerPluginOptions(options: any, target: string[], sourceFileCache?: SourceFileCache): {
3
- pluginOptions: any[0];
4
- styleOptions: any[1];
5
- };
6
- //# sourceMappingURL=create-compiler-options.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create-compiler-options.d.ts","sourceRoot":"","sources":["../../../src/utils/create-compiler-options.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,eAAe,CAAC,EAAE,eAAe,GAChC;IACD,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;CACtB,CAwDA"}
@@ -1,41 +0,0 @@
1
- // Taken from https://github.com/angular/angular-cli/blob/main/packages/angular/build/src/tools/esbuild/compiler-plugin-options.ts
2
- // Currently, this type cannot be accessed from the outside
3
- export function createCompilerPluginOptions(options, target, sourceFileCache) {
4
- const { workspaceRoot, optimizationOptions, sourcemapOptions, tsconfig, outputNames, fileReplacements, externalDependencies, preserveSymlinks, stylePreprocessorOptions, advancedOptimizations, inlineStyleLanguage, jit, cacheOptions, tailwindConfiguration, postcssConfiguration, publicPath, } = options;
5
- return {
6
- // JS/TS options
7
- pluginOptions: {
8
- sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
9
- thirdPartySourcemaps: sourcemapOptions.vendor,
10
- tsconfig,
11
- jit,
12
- advancedOptimizations,
13
- fileReplacements,
14
- sourceFileCache,
15
- loadResultCache: sourceFileCache?.loadResultCache,
16
- incremental: !!options.watch,
17
- },
18
- // Component stylesheet options
19
- styleOptions: {
20
- workspaceRoot,
21
- inlineFonts: !!optimizationOptions.fonts.inline,
22
- optimization: !!optimizationOptions.styles.minify,
23
- sourcemap:
24
- // Hidden component stylesheet sourcemaps are inaccessible which is effectively
25
- // the same as being disabled. Disabling has the advantage of avoiding the overhead
26
- // of sourcemap processing.
27
- sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
28
- outputNames,
29
- includePaths: stylePreprocessorOptions?.includePaths,
30
- sass: stylePreprocessorOptions?.sass,
31
- externalDependencies,
32
- target,
33
- inlineStyleLanguage,
34
- preserveSymlinks,
35
- tailwindConfiguration,
36
- postcssConfiguration,
37
- cacheOptions,
38
- publicPath,
39
- },
40
- };
41
- }
@@ -1,29 +0,0 @@
1
- import type { OutputFile } from 'esbuild';
2
- export interface BuildResult {
3
- fileName: string;
4
- get(): Uint8Array | Buffer;
5
- }
6
- export declare class EsBuildResult implements BuildResult {
7
- private outputFile;
8
- private fullOutDir?;
9
- get fileName(): string;
10
- constructor(outputFile: OutputFile, fullOutDir?: string | undefined);
11
- get(): Uint8Array;
12
- }
13
- export interface NgCliAssetFile {
14
- source: string;
15
- destination: string;
16
- }
17
- export declare class NgCliAssetResult implements BuildResult {
18
- get fileName(): string;
19
- private file;
20
- constructor(assetFile: NgCliAssetFile);
21
- get(): Buffer;
22
- }
23
- export declare class MemResults {
24
- private map;
25
- add(result: BuildResult[]): void;
26
- get(fileName: string): BuildResult | undefined;
27
- getFileNames(): string[];
28
- }
29
- //# sourceMappingURL=mem-resuts.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mem-resuts.d.ts","sourceRoot":"","sources":["../../../src/utils/mem-resuts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,IAAI,UAAU,GAAG,MAAM,CAAC;CAC5B;AAED,qBAAa,aAAc,YAAW,WAAW;IASnC,OAAO,CAAC,UAAU;IAAc,OAAO,CAAC,UAAU,CAAC;IAR/D,IAAI,QAAQ,WAMX;gBAEmB,UAAU,EAAE,UAAU,EAAU,UAAU,CAAC,EAAE,MAAM,YAAA;IAEvE,GAAG,IAAI,UAAU;CAGlB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,OAAO,CAAC,IAAI,CAAiB;gBAEjB,SAAS,EAAE,cAAc;IAIrC,GAAG,IAAI,MAAM;CAGd;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAkC;IAEtC,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI;IAMhC,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAI9C,YAAY,IAAI,MAAM,EAAE;CAGhC"}
@@ -1,50 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- export class EsBuildResult {
4
- outputFile;
5
- fullOutDir;
6
- get fileName() {
7
- if (this.fullOutDir) {
8
- return unify(path.relative(this.fullOutDir, this.outputFile.path));
9
- }
10
- else {
11
- return unify(this.outputFile.path);
12
- }
13
- }
14
- constructor(outputFile, fullOutDir) {
15
- this.outputFile = outputFile;
16
- this.fullOutDir = fullOutDir;
17
- }
18
- get() {
19
- return this.outputFile.contents;
20
- }
21
- }
22
- export class NgCliAssetResult {
23
- get fileName() {
24
- return unify(this.file.destination);
25
- }
26
- file;
27
- constructor(assetFile) {
28
- this.file = assetFile;
29
- }
30
- get() {
31
- return fs.readFileSync(this.file.source);
32
- }
33
- }
34
- export class MemResults {
35
- map = new Map();
36
- add(result) {
37
- for (const file of result) {
38
- this.map.set(file.fileName, file);
39
- }
40
- }
41
- get(fileName) {
42
- return this.map.get(fileName);
43
- }
44
- getFileNames() {
45
- return [...this.map.keys()];
46
- }
47
- }
48
- function unify(path) {
49
- return path?.replace(/\\/g, '/');
50
- }