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

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/README.md CHANGED
@@ -239,9 +239,9 @@ When bootstrapping the host (shell), Native Federation (`projects\shell\src\main
239
239
  import { initFederation } from '@angular-architects/native-federation';
240
240
 
241
241
  initFederation('/assets/federation.manifest.json')
242
- .catch((err) => console.error(err))
243
- .then((_) => import('./bootstrap'))
244
- .catch((err) => console.error(err));
242
+ .catch(err => console.error(err))
243
+ .then(_ => import('./bootstrap'))
244
+ .catch(err => console.error(err));
245
245
  ```
246
246
 
247
247
  > This file is generated by the schematic described above.
@@ -270,9 +270,9 @@ When bootstrapping your remote (`projects\mfe1\src\main.ts`), Native Federation
270
270
  import { initFederation } from '@angular-architects/native-federation';
271
271
 
272
272
  initFederation()
273
- .catch((err) => console.error(err))
274
- .then((_) => import('./bootstrap'))
275
- .catch((err) => console.error(err));
273
+ .catch(err => console.error(err))
274
+ .then(_ => import('./bootstrap'))
275
+ .catch(err => console.error(err));
276
276
  ```
277
277
 
278
278
  > Our `init` schematic shown above also generates this file.
@@ -301,7 +301,7 @@ export const APP_ROUTES: Routes = [
301
301
  // Add this route:
302
302
  {
303
303
  path: 'flights',
304
- loadComponent: () => loadRemoteModule('mfe1', './Component').then((m) => m.AppComponent),
304
+ loadComponent: () => loadRemoteModule('mfe1', './Component').then(m => m.AppComponent),
305
305
  },
306
306
 
307
307
  {
@@ -10,4 +10,4 @@
10
10
  "description": "migrating to v18"
11
11
  }
12
12
  }
13
- }
13
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-architects/native-federation-v4",
3
- "version": "20.3.2",
3
+ "version": "20.3.6",
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-RC3",
14
- "@softarc/native-federation-runtime": "4.0.0-RC3",
13
+ "@softarc/native-federation": "4.0.0-RC6",
14
+ "@softarc/native-federation-runtime": "4.0.0-RC6",
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,6 +1,7 @@
1
+ import './setup-builder-env-variables.js';
1
2
  import { type BuilderContext, type BuilderOutput } from '@angular-devkit/architect';
2
3
  import { type NfBuilderSchema } from './schema.js';
3
- export declare function runBuilder(nfOptions: NfBuilderSchema, context: BuilderContext): AsyncIterable<BuilderOutput>;
4
+ export declare function runBuilder(nfBuilderOptions: NfBuilderSchema, context: BuilderContext): AsyncIterable<BuilderOutput>;
4
5
  declare const _default: any;
5
6
  export default _default;
6
7
  //# sourceMappingURL=builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/builder.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAGnB,MAAM,2BAA2B,CAAC;AAkCnC,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAsCnD,wBAAuB,UAAU,CAC/B,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,cAAc,GACtB,aAAa,CAAC,aAAa,CAAC,CA+X9B;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;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,18 +1,19 @@
1
+ import './setup-builder-env-variables.js';
1
2
  import * as fs from 'fs';
2
3
  import * as mrmime from 'mrmime';
3
4
  import * as path from 'path';
4
5
  import { buildApplication } from '@angular/build';
5
- import { buildApplicationInternal, serveWithVite } from '@angular/build/private';
6
+ import { buildApplicationInternal, serveWithVite, SourceFileCache } from '@angular/build/private';
6
7
  import { createBuilder, targetFromTargetString, } from '@angular-devkit/architect';
7
8
  import { normalizeOptions } from '@angular-devkit/build-angular/src/builders/dev-server/options.js';
8
- import { buildForFederation, getExternals, loadFederationConfig, setBuildAdapter, } from '@softarc/native-federation';
9
- import { logger, setLogLevel, RebuildQueue, AbortedError, } from '@softarc/native-federation/internal';
10
- import { createAngularBuildAdapter, setMemResultHandler, } from '../../utils/angular-esbuild-adapter.js';
9
+ import { buildForFederation, rebuildForFederation, getExternals, loadFederationConfig, normalizeFederationOptions, setBuildAdapter, createFederationCache,
10
+ // type FederationCache,
11
+ } from '@softarc/native-federation';
12
+ import { logger, setLogLevel, RebuildQueue, AbortedError, getDefaultCachePath, } from '@softarc/native-federation/internal';
13
+ import { createAngularBuildAdapter } from '../../utils/angular-esbuild-adapter.js';
11
14
  import { existsSync, mkdirSync, rmSync } from 'fs';
12
15
  import { fstart } from '../../tools/fstart-as-data-url.js';
13
- import { EsBuildResult, MemResults, NgCliAssetResult } from '../../utils/mem-resuts.js';
14
16
  import { getI18nConfig, translateFederationArtifacts } from '../../utils/i18n.js';
15
- import { RebuildHubs } from '../../utils/rebuild-events.js';
16
17
  import { createSharedMappingsPlugin } from '../../utils/shared-mappings-plugin.js';
17
18
  import { updateScriptTags } from '../../utils/updateIndexHtml.js';
18
19
  import { federationBuildNotifier } from './federation-build-notifier.js';
@@ -27,7 +28,7 @@ process.stderr.write = function (chunk, encodingOrCallback, callback) {
27
28
  }
28
29
  return originalWrite(chunk, encodingOrCallback, callback);
29
30
  };
30
- function _buildApplication(options, context, pluginsOrExtensions) {
31
+ const createInternalAngularBuilder = (_) => (options, context, pluginsOrExtensions) => {
31
32
  let extensions;
32
33
  if (pluginsOrExtensions && Array.isArray(pluginsOrExtensions)) {
33
34
  extensions = {
@@ -37,10 +38,11 @@ function _buildApplication(options, context, pluginsOrExtensions) {
37
38
  else {
38
39
  extensions = pluginsOrExtensions;
39
40
  }
41
+ // options.codeBundleCache = nfOptions.federationCache.bundlerCache;
40
42
  return buildApplicationInternal(options, context, extensions);
41
- }
42
- export async function* runBuilder(nfOptions, context) {
43
- let target = targetFromTargetString(nfOptions.target);
43
+ };
44
+ export async function* runBuilder(nfBuilderOptions, context) {
45
+ let target = targetFromTargetString(nfBuilderOptions.target);
44
46
  let targetOptions = (await context.getTargetOptions(target));
45
47
  let builder = await context.getBuilderNameForTarget(target);
46
48
  if (builder === '@angular-devkit/build-angular:browser-esbuild') {
@@ -66,18 +68,17 @@ export async function* runBuilder(nfOptions, context) {
66
68
  /**
67
69
  * Explicitly defined as devServer or if the target contains "serve"
68
70
  */
69
- const runServer = typeof nfOptions.devServer !== 'undefined'
70
- ? !!nfOptions.devServer
71
+ const runServer = typeof nfBuilderOptions.devServer !== 'undefined'
72
+ ? !!nfBuilderOptions.devServer
71
73
  : target.target.includes('serve');
72
74
  let options = (await context.validateOptions(runServer
73
75
  ? {
74
76
  ...targetOptions,
75
- port: nfOptions.port || targetOptions['port'],
77
+ port: nfBuilderOptions.port || targetOptions['port'],
76
78
  }
77
79
  : targetOptions, builder));
78
80
  let serverOptions = null;
79
- const write = true;
80
- const watch = nfOptions.watch;
81
+ const watch = nfBuilderOptions.watch;
81
82
  if (options['buildTarget']) {
82
83
  serverOptions = await normalizeOptions(context, context.target.project, options);
83
84
  target = targetFromTargetString(options['buildTarget']);
@@ -86,14 +87,13 @@ export async function* runBuilder(nfOptions, context) {
86
87
  options = (await context.validateOptions(targetOptions, builder));
87
88
  }
88
89
  options.watch = watch;
89
- if (nfOptions.baseHref) {
90
- options.baseHref = nfOptions.baseHref;
90
+ if (nfBuilderOptions.baseHref) {
91
+ options.baseHref = nfBuilderOptions.baseHref;
91
92
  }
92
- if (nfOptions.outputPath) {
93
- options.outputPath = nfOptions.outputPath;
93
+ if (nfBuilderOptions.outputPath) {
94
+ options.outputPath = nfBuilderOptions.outputPath;
94
95
  }
95
- const rebuildEvents = new RebuildHubs();
96
- const adapter = createAngularBuildAdapter(options, context, rebuildEvents);
96
+ const adapter = createAngularBuildAdapter(options, context);
97
97
  setBuildAdapter(adapter);
98
98
  setLogLevel(options.verbose ? 'verbose' : 'info');
99
99
  if (!options.outputPath) {
@@ -118,22 +118,23 @@ export async function* runBuilder(nfOptions, context) {
118
118
  ? browserOutputPath
119
119
  : path.join(outputOptions.base, outputOptions.browser, localeFilter[0]);
120
120
  const entryPoint = path.join(path.dirname(options.tsConfig), 'src/main.ts');
121
- const fedOptions = {
121
+ const cachePath = getDefaultCachePath(context.workspaceRoot);
122
+ const nfOptions = normalizeFederationOptions({
122
123
  workspaceRoot: context.workspaceRoot,
123
124
  outputPath: browserOutputPath,
124
125
  federationConfig: inferConfigPath(options.tsConfig),
125
126
  tsConfig: options.tsConfig,
126
127
  verbose: options.verbose,
127
- watch: false, // options.watch,
128
- dev: !!nfOptions.dev,
129
- chunks: !nfOptions.chunks ? false : nfOptions.chunks,
128
+ watch: options.watch,
129
+ dev: !!nfBuilderOptions.dev,
130
+ chunks: !nfBuilderOptions.chunks ? false : nfBuilderOptions.chunks,
130
131
  entryPoint,
131
- buildNotifications: nfOptions.buildNotifications,
132
- cacheExternalArtifacts: nfOptions.cacheExternalArtifacts,
133
- };
134
- const activateSsr = nfOptions.ssr && !nfOptions.dev;
132
+ buildNotifications: nfBuilderOptions.buildNotifications,
133
+ cacheExternalArtifacts: nfBuilderOptions.cacheExternalArtifacts,
134
+ }, createFederationCache(cachePath, new SourceFileCache(cachePath)));
135
+ const activateSsr = nfBuilderOptions.ssr && !nfBuilderOptions.dev;
135
136
  const start = process.hrtime();
136
- const config = await loadFederationConfig(fedOptions);
137
+ const config = await loadFederationConfig(nfOptions);
137
138
  logger.measure(start, 'To load the federation config.');
138
139
  const externals = getExternals(config);
139
140
  const plugins = [
@@ -151,10 +152,10 @@ export async function* runBuilder(nfOptions, context) {
151
152
  if (activateSsr) {
152
153
  options.externalDependencies = externals;
153
154
  }
154
- const isLocalDevelopment = runServer && nfOptions.dev;
155
+ const isLocalDevelopment = runServer && nfBuilderOptions.dev;
155
156
  // Initialize SSE reloader only for local development
156
- if (isLocalDevelopment && nfOptions.buildNotifications?.enable) {
157
- federationBuildNotifier.initialize(nfOptions.buildNotifications.endpoint);
157
+ if (isLocalDevelopment && nfBuilderOptions.buildNotifications?.enable) {
158
+ federationBuildNotifier.initialize(nfBuilderOptions.buildNotifications.endpoint);
158
159
  }
159
160
  const middleware = [
160
161
  ...(isLocalDevelopment
@@ -164,7 +165,7 @@ export async function* runBuilder(nfOptions, context) {
164
165
  : []),
165
166
  (req, res, next) => {
166
167
  const url = removeBaseHref(req, options.baseHref);
167
- const fileName = path.join(fedOptions.workspaceRoot, devServerOutputPath, url);
168
+ const fileName = path.join(nfOptions.workspaceRoot, devServerOutputPath, url);
168
169
  const exists = fs.existsSync(fileName);
169
170
  if (url !== '/' && url !== '' && exists) {
170
171
  const lookup = mrmime.lookup;
@@ -186,26 +187,18 @@ export async function* runBuilder(nfOptions, context) {
186
187
  }
187
188
  },
188
189
  ];
189
- const memResults = new MemResults();
190
190
  let first = true;
191
191
  let lastResult;
192
- if (existsSync(fedOptions.outputPath)) {
193
- rmSync(fedOptions.outputPath, { recursive: true });
194
- }
195
- if (!existsSync(fedOptions.outputPath)) {
196
- mkdirSync(fedOptions.outputPath, { recursive: true });
192
+ if (existsSync(nfOptions.outputPath)) {
193
+ rmSync(nfOptions.outputPath, { recursive: true });
197
194
  }
198
- if (!write) {
199
- // todo: Hardcoded disabled?
200
- setMemResultHandler((outFiles, outDir) => {
201
- const fullOutDir = outDir ? path.join(fedOptions.workspaceRoot, outDir) : undefined;
202
- memResults.add(outFiles.map(f => new EsBuildResult(f, fullOutDir)));
203
- });
195
+ if (!existsSync(nfOptions.outputPath)) {
196
+ mkdirSync(nfOptions.outputPath, { recursive: true });
204
197
  }
205
198
  let federationResult;
206
199
  try {
207
200
  const start = process.hrtime();
208
- federationResult = await buildForFederation(config, fedOptions, externals);
201
+ federationResult = await buildForFederation(config, nfOptions, externals);
209
202
  logger.measure(start, 'To build the artifacts.');
210
203
  }
211
204
  catch (e) {
@@ -213,7 +206,7 @@ export async function* runBuilder(nfOptions, context) {
213
206
  process.exit(1);
214
207
  }
215
208
  if (activateSsr) {
216
- writeFstartScript(fedOptions);
209
+ writeFstartScript(nfOptions);
217
210
  }
218
211
  const hasLocales = i18n?.locales && Object.keys(i18n.locales).length > 0;
219
212
  if (hasLocales && localeFilter) {
@@ -224,38 +217,28 @@ export async function* runBuilder(nfOptions, context) {
224
217
  options.deleteOutputPath = false;
225
218
  const appBuilderName = '@angular/build:application';
226
219
  const builderRun = runServer
227
- ? serveWithVite(serverOptions, appBuilderName, _buildApplication, context, nfOptions.skipHtmlTransform ? {} : { indexHtml: transformIndexHtml(nfOptions) }, {
220
+ ? serveWithVite(serverOptions, appBuilderName, createInternalAngularBuilder(nfOptions), context, nfBuilderOptions.skipHtmlTransform
221
+ ? {}
222
+ : { indexHtml: transformIndexHtml(nfBuilderOptions) }, {
228
223
  buildPlugins: plugins,
229
224
  middleware,
230
225
  })
231
226
  : buildApplication(options, context, {
232
227
  codePlugins: plugins,
233
- indexHtmlTransformer: transformIndexHtml(nfOptions),
228
+ indexHtmlTransformer: transformIndexHtml(nfBuilderOptions),
234
229
  });
235
230
  const rebuildQueue = new RebuildQueue();
236
231
  try {
237
232
  for await (const output of builderRun) {
238
233
  lastResult = output;
239
- if (!write && output['outputFiles']) {
240
- memResults.add(output['outputFiles'].map((file) => new EsBuildResult(file)));
241
- }
242
- if (!write && output['assetFiles']) {
243
- memResults.add(output['assetFiles'].map((file) => new NgCliAssetResult(file)));
244
- }
245
- // if (write && !runServer && !nfOptions.skipHtmlTransform) {
246
- // updateIndexHtml(fedOptions, nfOptions);
247
- // }
248
- // if (!runServer) {
249
- // yield output;
250
- // }
251
- if (!first && (nfOptions.dev || watch)) {
234
+ if (!first && (nfBuilderOptions.dev || watch)) {
252
235
  rebuildQueue
253
236
  .enqueue(async (signal) => {
254
237
  if (signal?.aborted) {
255
238
  throw new AbortedError('Build canceled before starting');
256
239
  }
257
240
  await new Promise((resolve, reject) => {
258
- const timeout = setTimeout(resolve, Math.max(10, nfOptions.rebuildDelay));
241
+ const timeout = setTimeout(resolve, Math.max(10, nfBuilderOptions.rebuildDelay));
259
242
  if (signal) {
260
243
  const abortHandler = () => {
261
244
  clearTimeout(timeout);
@@ -268,11 +251,10 @@ export async function* runBuilder(nfOptions, context) {
268
251
  throw new AbortedError('[builder] Before federation build.');
269
252
  }
270
253
  const start = process.hrtime();
271
- federationResult = await buildForFederation(config, fedOptions, externals, {
272
- skipMappingsAndExposed: false,
273
- skipShared: true,
274
- signal,
275
- });
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);
276
258
  if (signal?.aborted) {
277
259
  throw new AbortedError('[builder] After federation build.');
278
260
  }
@@ -308,6 +290,7 @@ export async function* runBuilder(nfOptions, context) {
308
290
  }
309
291
  finally {
310
292
  rebuildQueue.dispose();
293
+ await adapter.dispose();
311
294
  if (isLocalDevelopment) {
312
295
  federationBuildNotifier.stopEventServer();
313
296
  }
@@ -321,8 +304,8 @@ function removeBaseHref(req, baseHref) {
321
304
  }
322
305
  return url;
323
306
  }
324
- function writeFstartScript(fedOptions) {
325
- const serverOutpath = path.join(fedOptions.outputPath, '../server');
307
+ function writeFstartScript(nfOptions) {
308
+ const serverOutpath = path.join(nfOptions.outputPath, '../server');
326
309
  const fstartPath = path.join(serverOutpath, 'fstart.mjs');
327
310
  const buffer = Buffer.from(fstart, 'base64');
328
311
  fs.mkdirSync(serverOutpath, { recursive: true });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup-builder-env-variables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-builder-env-variables.d.ts","sourceRoot":"","sources":["../../../../src/builders/build/setup-builder-env-variables.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Disables Angular's parallel caching and allows for
3
+ * a shared cache between the compilation steps which
4
+ * improves performance dramatically.
5
+ */
6
+ process.env['NG_BUILD_PARALLEL_TS'] = '0';
7
+ export {};
@@ -1,4 +1,4 @@
1
1
  export const externalsSkipList = new Set(['tslib']);
2
2
  export function filterExternals(deps) {
3
- return deps.filter((d) => !externalsSkipList.has(d));
3
+ return deps.filter(d => !externalsSkipList.has(d));
4
4
  }
@@ -1,10 +1,6 @@
1
1
  import { type NFBuildAdapter } from '@softarc/native-federation';
2
- import * as esbuild from 'esbuild';
3
2
  import type { BuilderContext } from '@angular-devkit/architect';
4
3
  import type { ApplicationBuilderOptions } from '@angular/build';
5
- import { type RebuildEvents } from './rebuild-events.js';
6
- export type MemResultHandler = (outfiles: esbuild.OutputFile[], outdir?: string) => void;
7
- export declare function setMemResultHandler(handler: MemResultHandler): void;
8
- export declare function createAngularBuildAdapter(builderOptions: ApplicationBuilderOptions, context: BuilderContext, rebuildRequested?: RebuildEvents): NFBuildAdapter;
4
+ export declare function createAngularBuildAdapter(builderOptions: ApplicationBuilderOptions, context: BuilderContext): NFBuildAdapter;
9
5
  export declare function loadEsmModule<T>(modulePath: string | URL): Promise<T>;
10
6
  //# 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,OAAO,MAAM,SAAS,CAAC;AAWnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAShE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAQhE,OAAO,EAAE,KAAK,aAAa,EAAe,MAAM,qBAAqB,CAAC;AAMtE,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAKzF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAEnE;AAED,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,EACvB,gBAAgB,GAAE,aAAiC,GAClD,cAAc,CA2FhB;AAkSD,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":"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"}
@@ -8,64 +8,110 @@ import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
10
10
  import { transformAsync } from '@babel/core';
11
- import { RebuildHubs } from './rebuild-events.js';
12
11
  import JSON5 from 'json5';
13
12
  import { isDeepStrictEqual } from 'node:util';
14
13
  import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js';
15
- let _memResultHandler;
16
- // Todo: figure out if still necessary
17
- export function setMemResultHandler(handler) {
18
- _memResultHandler = handler;
19
- }
20
- export function createAngularBuildAdapter(builderOptions, context, rebuildRequested = new RebuildHubs()) {
21
- return async (options) => {
22
- const { entryPoints, tsConfigPath, external, outdir, mappedPaths, kind, watch, dev, hash, chunks, platform, optimizedMappings, signal, } = options;
14
+ export function createAngularBuildAdapter(builderOptions, context) {
15
+ const contextCache = new Map();
16
+ const dispose = async (name) => {
17
+ if (name) {
18
+ if (!contextCache.has(name))
19
+ throw new Error(`Could not dispose of non-existing build '${name}'`);
20
+ const entry = contextCache.get(name);
21
+ await entry.ctx.dispose();
22
+ await entry.pluginDisposed;
23
+ contextCache.delete(name);
24
+ return;
25
+ }
26
+ // Dispose all if no specific build provided
27
+ const disposals = [];
28
+ for (const [, entry] of contextCache) {
29
+ disposals.push((async () => {
30
+ await entry.ctx.dispose();
31
+ await entry.pluginDisposed;
32
+ })());
33
+ }
34
+ contextCache.clear();
35
+ await Promise.all(disposals);
36
+ };
37
+ const setup = async (options) => {
38
+ const { entryPoints, tsConfigPath, external, outdir, mappedPaths, bundleName, isNodeModules, dev, chunks, hash, platform, optimizedMappings, cache, } = options;
23
39
  setNgServerMode();
24
- const files = await runEsbuild(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, watch, rebuildRequested, dev, kind, chunks, hash, undefined, undefined, undefined, platform, optimizedMappings, signal);
25
- if (kind === 'shared-package') {
26
- const scriptFiles = files.filter(f => f.endsWith('.js') || f.endsWith('.mjs'));
27
- for (const file of scriptFiles) {
28
- link(file, !!dev);
29
- }
40
+ if (contextCache.has(bundleName)) {
41
+ return;
30
42
  }
31
- return files.map(fileName => ({ fileName }));
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, {
45
+ ctx,
46
+ pluginDisposed,
47
+ outdir,
48
+ isNodeModules,
49
+ dev: !!dev,
50
+ name: bundleName,
51
+ entryPoints,
52
+ workspaceRoot: context.workspaceRoot,
53
+ });
32
54
  };
33
- async function link(outfile, dev) {
34
- const code = fs.readFileSync(outfile, 'utf-8');
55
+ const build = async (name, opts = {}) => {
56
+ const cached = contextCache.get(name);
57
+ if (!cached) {
58
+ throw new Error(`No context found for build "${name}". Call setup() first.`);
59
+ }
60
+ if (opts?.signal?.aborted) {
61
+ throw new AbortedError('[build] Aborted before rebuild');
62
+ }
35
63
  try {
36
- const linkerEsm = await loadEsmModule('@angular/compiler-cli/linker/babel');
37
- const linker = linkerEsm.default;
38
- const result = await transformAsync(code, {
39
- filename: outfile,
40
- compact: !dev,
41
- configFile: false,
42
- babelrc: false,
43
- minified: !dev,
44
- browserslistConfigFile: false,
45
- plugins: [linker],
46
- });
47
- if (!result)
48
- logger.warn(`File ${outfile} could not be linked.`);
49
- if (!result?.code) {
50
- logger.warn(`File ${outfile} seems to be empty.`);
51
- return;
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
+ }
52
71
  }
53
- fs.writeFileSync(outfile, result.code, 'utf-8');
72
+ return writtenFiles.map(fileName => ({ fileName }));
54
73
  }
55
- catch (e) {
56
- logger.error('error linking');
57
- if (fs.existsSync(`${outfile}.error`)) {
58
- fs.unlinkSync(`${outfile}.error`);
74
+ catch (error) {
75
+ if (opts?.signal?.aborted && error instanceof Error && error.message.includes('canceled')) {
76
+ throw new AbortedError('[build] ESBuild rebuild was canceled.');
59
77
  }
60
- fs.renameSync(outfile, `${outfile}.error`);
61
- throw e;
78
+ throw error;
62
79
  }
63
- }
80
+ };
81
+ return { setup, build, dispose };
64
82
  }
65
- async function runEsbuild(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, watch, rebuildRequested = new RebuildHubs(), dev, kind, chunks, hash = false, plugins = null, absWorkingDir = undefined, logLevel = 'warning', platform, optimizedMappings, signal) {
66
- if (signal?.aborted) {
67
- throw new AbortedError('[angular-esbuild-adapter] Before building');
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;
68
112
  }
113
+ }
114
+ async function createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, sourceFileCache, dev, isNodeModules, hash = false, chunks, platform, optimizedMappings) {
69
115
  const workspaceRoot = context.workspaceRoot;
70
116
  const projectMetadata = await context.getProjectMetadata(context.target.project);
71
117
  const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
@@ -107,7 +153,8 @@ async function runEsbuild(builderOptions, context, entryPoints, external, outdir
107
153
  jit: false,
108
154
  tailwindConfiguration,
109
155
  postcssConfiguration,
110
- }, target, undefined);
156
+ incremental: !isNodeModules,
157
+ }, target, sourceFileCache);
111
158
  const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
112
159
  const commonjsPlugin = commonjsPluginModule.default;
113
160
  pluginOptions.styleOptions.externalDependencies = [];
@@ -120,9 +167,8 @@ async function runEsbuild(builderOptions, context, entryPoints, external, outdir
120
167
  outdir,
121
168
  entryNames: hash ? '[name]-[hash]' : '[name]',
122
169
  write: false,
123
- absWorkingDir,
124
170
  external,
125
- logLevel,
171
+ logLevel: 'warning',
126
172
  bundle: true,
127
173
  sourcemap: sourcemapOptions.scripts,
128
174
  minify: !dev,
@@ -130,12 +176,12 @@ async function runEsbuild(builderOptions, context, entryPoints, external, outdir
130
176
  'async-await': false,
131
177
  'object-rest-spread': false,
132
178
  },
133
- splitting: chunks, //kind === 'mapping-or-exposed',
179
+ splitting: chunks,
134
180
  platform: platform ?? 'browser',
135
181
  format: 'esm',
136
182
  target: target,
137
- logLimit: kind === 'shared-package' ? 1 : 0,
138
- plugins: plugins || [
183
+ logLimit: isNodeModules ? 1 : 0,
184
+ plugins: [
139
185
  compilerPlugin,
140
186
  ...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
141
187
  commonjsPlugin(),
@@ -148,38 +194,7 @@ async function runEsbuild(builderOptions, context, entryPoints, external, outdir
148
194
  resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
149
195
  };
150
196
  const ctx = await esbuild.context(config);
151
- try {
152
- const abortHandler = async () => {
153
- await ctx.cancel();
154
- await ctx.dispose();
155
- await pluginDisposed;
156
- };
157
- if (signal) {
158
- signal.addEventListener('abort', abortHandler, { once: true });
159
- }
160
- const result = await ctx.rebuild();
161
- const memOnly = dev && kind === 'mapping-or-exposed' && !!_memResultHandler;
162
- const writtenFiles = writeResult(result, outdir, !!memOnly);
163
- if (watch) {
164
- // Also hardcoded disabled?
165
- registerForRebuilds(kind ?? 'shared-package', rebuildRequested, ctx, outdir, !!memOnly);
166
- }
167
- else {
168
- if (signal)
169
- signal.removeEventListener('abort', abortHandler);
170
- await ctx.dispose();
171
- await pluginDisposed;
172
- }
173
- return writtenFiles;
174
- }
175
- catch (error) {
176
- // ESBuild throws an error if the request is cancelled.
177
- // if it is, it's changed to an 'AbortedError'
178
- if (signal?.aborted && error instanceof Error && error.message.includes('canceled')) {
179
- throw new AbortedError('[runEsbuild] ESBuild was canceled.');
180
- }
181
- throw error;
182
- }
197
+ return { ctx, pluginDisposed };
183
198
  }
184
199
  async function getTailwindConfig(searchDirectories) {
185
200
  const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories);
@@ -237,32 +252,16 @@ function doesFileExistAndJsonEqual(path, content) {
237
252
  return false;
238
253
  }
239
254
  }
240
- function writeResult(result, outdir, memOnly) {
255
+ function writeResult(result, outdir) {
241
256
  const writtenFiles = [];
242
- if (memOnly) {
243
- _memResultHandler(result.outputFiles ?? [], outdir);
244
- }
245
257
  for (const outFile of result.outputFiles ?? []) {
246
258
  const fileName = path.basename(outFile.path);
247
259
  const filePath = path.join(outdir, fileName);
248
- if (!memOnly) {
249
- fs.writeFileSync(filePath, outFile.text);
250
- }
260
+ fs.writeFileSync(filePath, outFile.text);
251
261
  writtenFiles.push(filePath);
252
262
  }
253
- if (!memOnly) {
254
- // for (const asset of result.outputFiles)
255
- }
256
263
  return writtenFiles;
257
264
  }
258
- function registerForRebuilds(kind, rebuildRequested, ctx, outdir, memOnly) {
259
- if (kind !== 'shared-package') {
260
- rebuildRequested.rebuild.register(async () => {
261
- const result = await ctx.rebuild();
262
- writeResult(result, outdir, memOnly);
263
- });
264
- }
265
- }
266
265
  export function loadEsmModule(modulePath) {
267
266
  return new Function('modulePath', `return import(modulePath);`)(modulePath);
268
267
  }
@@ -1,4 +1,5 @@
1
- export declare function createCompilerPluginOptions(options: any, target: string[], sourceFileCache?: any): {
1
+ import { type SourceFileCache } from '@angular/build/private';
2
+ export declare function createCompilerPluginOptions(options: any, target: string[], sourceFileCache?: SourceFileCache): {
2
3
  pluginOptions: any[0];
3
4
  styleOptions: any[1];
4
5
  };
@@ -1 +1 @@
1
- {"version":3,"file":"create-compiler-options.d.ts","sourceRoot":"","sources":["../../../src/utils/create-compiler-options.ts"],"names":[],"mappings":"AAGA,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,GAAG,EACZ,MAAM,EAAE,MAAM,EAAE,EAChB,eAAe,CAAC,EAAE,GAAG,GACpB;IACD,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;CACtB,CA0DA"}
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"}
@@ -5,8 +5,7 @@ export function createCompilerPluginOptions(options, target, sourceFileCache) {
5
5
  return {
6
6
  // JS/TS options
7
7
  pluginOptions: {
8
- sourcemap: !!sourcemapOptions.scripts &&
9
- (sourcemapOptions.hidden ? 'external' : true),
8
+ sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
10
9
  thirdPartySourcemaps: sourcemapOptions.vendor,
11
10
  tsconfig,
12
11
  jit,
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/utils/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAKhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAO5F;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,cAAc,iBAgDjC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../src/utils/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAKhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,CAAC,CAAC;CAC3D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAO5F;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,EAC5B,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,cAAc,iBAiDjC"}
package/src/utils/i18n.js CHANGED
@@ -25,13 +25,14 @@ export async function translateFederationArtifacts(i18n, localize, outputPath, f
25
25
  const federationFiles = [
26
26
  ...federationResult.shared.map(s => s.outFileName),
27
27
  ...federationResult.exposes.map(e => e.outFileName),
28
+ ...Object.values(federationResult.chunks ?? {}).flat(),
28
29
  ];
29
30
  // Here, we use a glob with an exhaustive list i/o `"*.js"`
30
31
  // to improve performance
31
32
  const sourcePattern = '{' + federationFiles.join(',') + '}';
32
33
  const sourceLocalePath = path.join(outputPath, 'browser', sourceLocale);
33
34
  const localizeTranslate = path.resolve('node_modules/.bin/localize-translate');
34
- const cmd = `${localizeTranslate} -r ${sourceLocalePath} -s "${sourcePattern}" -t ${translationFiles} -o ${translationOutPath} --target-locales ${targetLocales} -l ${sourceLocale}`;
35
+ const cmd = `"${localizeTranslate}" -r "${sourceLocalePath}" -s "${sourcePattern}" -t ${translationFiles} -o "${translationOutPath}" --target-locales ${targetLocales} -l ${sourceLocale}`;
35
36
  ensureDistFolders(locales, outputPath);
36
37
  copyRemoteEntry(locales, outputPath, sourceLocalePath);
37
38
  logger.debug('Running: ' + cmd);
@@ -1,10 +0,0 @@
1
- export type EventHandler = () => Promise<void>;
2
- export interface EventSource {
3
- register(handler: EventHandler): void;
4
- }
5
- export declare class EventHub implements EventSource {
6
- private handlers;
7
- register(handler: EventHandler): void;
8
- emit(): Promise<void>;
9
- }
10
- //# sourceMappingURL=event-source.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-source.d.ts","sourceRoot":"","sources":["../../../src/utils/event-source.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;AAE/C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;CACvC;AAED,qBAAa,QAAS,YAAW,WAAW;IAC1C,OAAO,CAAC,QAAQ,CAAsB;IAEtC,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAI/B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5B"}
@@ -1,10 +0,0 @@
1
- export class EventHub {
2
- handlers = [];
3
- register(handler) {
4
- this.handlers.push(handler);
5
- }
6
- async emit() {
7
- const promises = this.handlers.map((h) => h());
8
- await Promise.all(promises);
9
- }
10
- }
@@ -1,8 +0,0 @@
1
- import { EventHub, type EventSource } from './event-source.js';
2
- export interface RebuildEvents {
3
- readonly rebuild: EventSource;
4
- }
5
- export declare class RebuildHubs implements RebuildEvents {
6
- readonly rebuild: EventHub;
7
- }
8
- //# sourceMappingURL=rebuild-events.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rebuild-events.d.ts","sourceRoot":"","sources":["../../../src/utils/rebuild-events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE/D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,qBAAa,WAAY,YAAW,aAAa;IAC/C,QAAQ,CAAC,OAAO,WAAkB;CACnC"}
@@ -1,4 +0,0 @@
1
- import { EventHub } from './event-source.js';
2
- export class RebuildHubs {
3
- rebuild = new EventHub();
4
- }