@softarc/native-federation 4.4.0 → 4.4.1

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.
@@ -0,0 +1,8 @@
1
+ import type { ArtifactInfo, FederationInfo } from '../../domain/core/federation-info.contract.js';
2
+ import type { NormalizedFederationConfig } from '../../domain/config/federation-config.contract.js';
3
+ import type { NormalizedFederationOptions } from '../../domain/core/federation-options.contract.js';
4
+ /**
5
+ * Derives the `remoteEntry.json` payload from the populated federation cache. Shared by the initial
6
+ * build and the watch rebuild.
7
+ */
8
+ export declare function assembleFederationInfo(config: NormalizedFederationConfig, fedOptions: NormalizedFederationOptions, artifactInfo: ArtifactInfo): FederationInfo;
@@ -0,0 +1,34 @@
1
+ import { densifyExternals } from "../output/densify-externals.js";
2
+ function assembleFederationInfo(config, fedOptions, artifactInfo) {
3
+ const federationCache = fedOptions.federationCache;
4
+ const sharedExternals = applyShareScope(
5
+ [...federationCache.externals, ...artifactInfo.mappings],
6
+ config.shareScope
7
+ );
8
+ const federationInfo = {
9
+ name: config.name,
10
+ shared: config.features.denseExternals ? densifyExternals(sharedExternals) : sharedExternals,
11
+ exposes: artifactInfo.exposes,
12
+ buildNotificationsEndpoint: fedOptions.buildNotifications?.enable && fedOptions.dev ? fedOptions.buildNotifications?.endpoint : void 0
13
+ };
14
+ if (federationCache.chunks) {
15
+ federationInfo.chunks = federationCache.chunks;
16
+ }
17
+ if (artifactInfo.chunks) {
18
+ federationInfo.chunks = { ...federationInfo.chunks ?? {}, ...artifactInfo.chunks };
19
+ }
20
+ if (config.features.integrityHashes) {
21
+ federationInfo.integrity = {
22
+ ...federationCache.integrity ?? {},
23
+ ...artifactInfo.integrity ?? {}
24
+ };
25
+ }
26
+ return federationInfo;
27
+ }
28
+ function applyShareScope(externals, shareScope) {
29
+ if (!shareScope) return externals;
30
+ return externals.map((external) => external.shareScope ? external : { ...external, shareScope });
31
+ }
32
+ export {
33
+ assembleFederationInfo
34
+ };
@@ -1,22 +1,12 @@
1
- import {
2
- bundleExposedAndMappings,
3
- describeExposed,
4
- describeSharedMappings
5
- } from "./bundle-exposed-and-mappings.js";
1
+ import { bundleExposedAndMappings } from "./bundle-exposed-and-mappings.js";
6
2
  import { bundleShared } from "./bundle-shared.js";
7
- import { densifyExternals } from "../output/densify-externals.js";
8
- import { writeFederationInfo } from "../output/write-federation-info.js";
9
- import { writeImportMap } from "../output/write-import-map.js";
3
+ import { assembleFederationInfo } from "./assemble-federation-info.js";
4
+ import { writeFederationOutputs } from "../output/write-federation-outputs.js";
10
5
  import { logger } from "../../utils/logger.js";
11
6
  import { AbortedError } from "../../utils/errors.js";
12
7
  import { addExternalsToCache } from "../cache/federation-cache.js";
13
8
  import { planSharedBundles } from "./shared-bundle-plan.js";
14
- import path from "path";
15
9
  async function buildForFederation(config, fedOptions, externals, signal) {
16
- fedOptions.federationCache.cachePath = path.join(
17
- fedOptions.federationCache.cachePath,
18
- fedOptions.projectName
19
- );
20
10
  logger.info("Building federation artifacts");
21
11
  logger.notice("Skip packages you don't want to share in your federation config");
22
12
  await executeSharedBundlePlans(planSharedBundles(config, externals), config, fedOptions, signal);
@@ -31,36 +21,8 @@ async function buildForFederation(config, fedOptions, externals, signal) {
31
21
  logger.measure(start, "Step 3) Bundling all internal libraries and exposed modules.");
32
22
  if (signal?.aborted)
33
23
  throw new AbortedError("[buildForFederation] After exposed-and-mappings bundle");
34
- const exposedInfo = !artifactInfo ? describeExposed(config, fedOptions) : artifactInfo.exposes;
35
- const sharedMappingInfo = !artifactInfo ? describeSharedMappings(config, fedOptions) : artifactInfo.mappings;
36
- const sharedExternals = [...fedOptions.federationCache.externals, ...sharedMappingInfo];
37
- if (config?.shareScope) {
38
- Object.values(sharedExternals).forEach((external) => {
39
- if (!external.shareScope) external.shareScope = config.shareScope;
40
- });
41
- }
42
- const shared = config.features.denseExternals ? densifyExternals(sharedExternals) : sharedExternals;
43
- const buildNotificationsEndpoint = fedOptions.buildNotifications?.enable && fedOptions.dev ? fedOptions.buildNotifications?.endpoint : void 0;
44
- const federationInfo = {
45
- name: config.name,
46
- shared,
47
- exposes: exposedInfo,
48
- buildNotificationsEndpoint
49
- };
50
- if (fedOptions.federationCache.chunks) {
51
- federationInfo.chunks = fedOptions.federationCache.chunks;
52
- }
53
- if (artifactInfo?.chunks) {
54
- federationInfo.chunks = { ...federationInfo.chunks ?? {}, ...artifactInfo?.chunks };
55
- }
56
- if (config.features.integrityHashes) {
57
- federationInfo.integrity = {
58
- ...fedOptions.federationCache.integrity ?? {},
59
- ...artifactInfo?.integrity ?? {}
60
- };
61
- }
62
- writeFederationInfo(federationInfo, fedOptions);
63
- writeImportMap(fedOptions.federationCache, fedOptions, federationInfo.integrity);
24
+ const federationInfo = assembleFederationInfo(config, fedOptions, artifactInfo);
25
+ writeFederationOutputs(federationInfo, fedOptions);
64
26
  return federationInfo;
65
27
  }
66
28
  async function executeSharedBundlePlans(plans, config, fedOptions, signal) {
@@ -75,7 +37,7 @@ async function executeSharedBundlePlans(plans, config, fedOptions, signal) {
75
37
  logger.measure(start, `Step 2.1) Bundling '${plan.bundleName}' externals`);
76
38
  addExternalsToCache(fedOptions.federationCache, info);
77
39
  if (signal?.aborted)
78
- throw new AbortedError(`[buildForFederation] After ${plan.bundleName} bundle`);
40
+ throw new AbortedError(`[executeSharedBundlePlans] After ${plan.bundleName} bundle`);
79
41
  }
80
42
  const separatePlans = plans.filter((p) => p.kind === "separate");
81
43
  if (separatePlans.length > 0) {
@@ -91,7 +53,7 @@ async function executeSharedBundlePlans(plans, config, fedOptions, signal) {
91
53
  );
92
54
  logger.measure(start, "Step 2.2) Bundling all separate external packages");
93
55
  for (const info of results) addExternalsToCache(fedOptions.federationCache, info);
94
- if (signal?.aborted) throw new AbortedError("[buildForFederation] After separate bundle");
56
+ if (signal?.aborted) throw new AbortedError("[executeSharedBundlePlans] After separate bundle");
95
57
  }
96
58
  }
97
59
  export {
@@ -1,4 +1,4 @@
1
- import type { ArtifactInfo, ExposesInfo, SharedInfo } from '../../domain/core/federation-info.contract.js';
1
+ import type { ArtifactInfo } from '../../domain/core/federation-info.contract.js';
2
2
  import type { FileReaderPort } from '../../domain/utils/io-port.contract.js';
3
3
  import type { NormalizedFederationConfig } from '../../domain/config/federation-config.contract.js';
4
4
  import { type NormalizedFederationOptions } from '../../domain/core/federation-options.contract.js';
@@ -7,7 +7,5 @@ export declare function bundleExposedAndMappings(config: NormalizedFederationCon
7
7
  export declare function bundleExposedAndMappingsCore(deps: {
8
8
  adapter: NFBuildAdapter;
9
9
  }, config: NormalizedFederationConfig, fedOptions: NormalizedFederationOptions, externals: string[], modifiedFiles?: string[], signal?: AbortSignal): Promise<ArtifactInfo>;
10
- export declare function describeExposed(config: NormalizedFederationConfig, options: NormalizedFederationOptions): Array<ExposesInfo>;
11
- export declare function describeSharedMappings(config: NormalizedFederationConfig, fedOptions: NormalizedFederationOptions): Array<SharedInfo>;
12
10
  export declare function getMappingVersionCore(io: FileReaderPort, fileName: string, workspaceRoot: string): string;
13
11
  export declare function getMappingVersion(fileName: string, workspaceRoot: string): string;
@@ -115,29 +115,6 @@ async function bundleExposedAndMappingsCore(deps, config, fedOptions, externals,
115
115
  const integrity = config.features.integrityHashes ? computeIntegrityMap([...entryFiles, ...chunkPaths], "") : void 0;
116
116
  return { mappings: sharedResult, exposes: exposedResult, chunks: exportedChunks, integrity };
117
117
  }
118
- function describeExposed(config, options) {
119
- const result = [];
120
- for (const key in config.exposes) {
121
- const expose = config.exposes[key];
122
- const localPath = normalize(path.normalize(path.join(options.workspaceRoot, expose.file)));
123
- result.push({
124
- key,
125
- outFileName: "",
126
- ...expose.element && { element: expose.element },
127
- dev: !options.dev ? void 0 : {
128
- entryPoint: localPath
129
- }
130
- });
131
- }
132
- return result;
133
- }
134
- function describeSharedMappings(config, fedOptions) {
135
- const result = [];
136
- for (const [mappedPath, mappedImport] of Object.entries(config.sharedMappings)) {
137
- result.push(toSharedMappingInfo(mappedPath, mappedImport, "", config, fedOptions));
138
- }
139
- return result;
140
- }
141
118
  function toSharedMappingInfo(mappedPath, mappedImport, outFileName, config, fedOptions) {
142
119
  const mappingVersion = config.features.mappingVersion ? getMappingVersion(mappedPath, fedOptions.workspaceRoot) : "";
143
120
  const mappingConfig = resolveMappingConfig(
@@ -184,8 +161,6 @@ function getMappingVersion(fileName, workspaceRoot) {
184
161
  export {
185
162
  bundleExposedAndMappings,
186
163
  bundleExposedAndMappingsCore,
187
- describeExposed,
188
- describeSharedMappings,
189
164
  getMappingVersion,
190
165
  getMappingVersionCore
191
166
  };
@@ -1,10 +1,6 @@
1
- import {
2
- bundleExposedAndMappings,
3
- describeExposed,
4
- describeSharedMappings
5
- } from "./bundle-exposed-and-mappings.js";
6
- import { writeFederationInfo } from "../output/write-federation-info.js";
7
- import { writeImportMap } from "../output/write-import-map.js";
1
+ import { bundleExposedAndMappings } from "./bundle-exposed-and-mappings.js";
2
+ import { assembleFederationInfo } from "./assemble-federation-info.js";
3
+ import { writeFederationOutputs } from "../output/write-federation-outputs.js";
8
4
  import { logger } from "../../utils/logger.js";
9
5
  import { AbortedError } from "../../utils/errors.js";
10
6
  import { planSharedBundles } from "./shared-bundle-plan.js";
@@ -14,7 +10,6 @@ import { cacheEntryCore, getFilename } from "../cache/cache-persistence.js";
14
10
  import { nodeIo } from "../../utils/io/node-io-adapter.js";
15
11
  import { sharedPackageJsonRepository } from "../../utils/package/package-info.js";
16
12
  async function rebuildForFederation(config, fedOptions, externals, modifiedFiles, signal) {
17
- const federationCache = fedOptions.federationCache;
18
13
  await rebuildAffectedExternals(config, fedOptions, externals, modifiedFiles, signal);
19
14
  logger.info(`Re-bundling all internal libraries and exposed modules..'`);
20
15
  const start = process.hrtime();
@@ -27,31 +22,9 @@ async function rebuildForFederation(config, fedOptions, externals, modifiedFiles
27
22
  );
28
23
  logger.measure(start, "To re-bundle all internal libraries and exposed modules.");
29
24
  if (signal?.aborted)
30
- throw new AbortedError("[buildForFederation] After exposed-and-mappings bundle");
31
- const exposedInfo = !artifactInfo ? describeExposed(config, fedOptions) : artifactInfo.exposes;
32
- const sharedMappingInfo = !artifactInfo ? describeSharedMappings(config, fedOptions) : artifactInfo.mappings;
33
- const sharedExternals = [...federationCache.externals, ...sharedMappingInfo];
34
- const buildNotificationsEndpoint = fedOptions.buildNotifications?.enable && fedOptions.dev ? fedOptions.buildNotifications?.endpoint : void 0;
35
- const federationInfo = {
36
- name: config.name,
37
- shared: sharedExternals,
38
- exposes: exposedInfo,
39
- buildNotificationsEndpoint
40
- };
41
- if (federationCache.chunks) {
42
- federationInfo.chunks = federationCache.chunks;
43
- }
44
- if (artifactInfo?.chunks) {
45
- federationInfo.chunks = { ...federationInfo.chunks ?? {}, ...artifactInfo?.chunks };
46
- }
47
- if (config.features.integrityHashes) {
48
- federationInfo.integrity = {
49
- ...federationCache.integrity ?? {},
50
- ...artifactInfo?.integrity ?? {}
51
- };
52
- }
53
- writeFederationInfo(federationInfo, fedOptions);
54
- writeImportMap(federationCache, fedOptions, federationInfo.integrity);
25
+ throw new AbortedError("[rebuildForFederation] After exposed-and-mappings bundle");
26
+ const federationInfo = assembleFederationInfo(config, fedOptions, artifactInfo);
27
+ writeFederationOutputs(federationInfo, fedOptions);
55
28
  return federationInfo;
56
29
  }
57
30
  async function rebuildAffectedExternals(config, fedOptions, externals, modifiedFiles, signal, io = nodeIo, repo = sharedPackageJsonRepository) {
@@ -23,13 +23,19 @@ async function normalizeFederationOptionsCore(deps, options, cache) {
23
23
  throw new Error("Expected " + fullConfigPath);
24
24
  }
25
25
  let config = await deps.loadConfig(fullConfigPath);
26
- const federationCache = cache ?? createFederationCache(
26
+ const projectName = resolveProjectName(options.projectName ?? config.name);
27
+ const suppliedCache = cache ?? createFederationCache(
27
28
  getDefaultCachePath(options.workspaceRoot)
28
29
  );
30
+ const federationCache = {
31
+ ...suppliedCache,
32
+ cachePath: path.join(suppliedCache.cachePath, projectName),
33
+ externals: [...suppliedCache.externals]
34
+ };
29
35
  const normalizedOptions = {
30
36
  ...options,
31
37
  entryPoints: options.entryPoints ?? Object.values(config.exposes ?? {}).map((e) => e.file),
32
- projectName: resolveProjectName(options.projectName ?? config.name),
38
+ projectName,
33
39
  cacheExternalArtifacts: options.cacheExternalArtifacts ?? true,
34
40
  federationCache
35
41
  };
@@ -0,0 +1,7 @@
1
+ import type { FederationInfo } from '../../domain/core/federation-info.contract.js';
2
+ import type { NormalizedFederationOptions } from '../../domain/core/federation-options.contract.js';
3
+ /**
4
+ * The import map is built from the flat federation cache rather than `federationInfo.shared`: a
5
+ * dense group has no import-map representation, every specifier needs its own entry.
6
+ */
7
+ export declare function writeFederationOutputs(federationInfo: FederationInfo, fedOptions: NormalizedFederationOptions): void;
@@ -0,0 +1,9 @@
1
+ import { writeFederationInfo } from "./write-federation-info.js";
2
+ import { writeImportMap } from "./write-import-map.js";
3
+ function writeFederationOutputs(federationInfo, fedOptions) {
4
+ writeFederationInfo(federationInfo, fedOptions);
5
+ writeImportMap(fedOptions.federationCache, fedOptions, federationInfo.integrity);
6
+ }
7
+ export {
8
+ writeFederationOutputs
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softarc/native-federation",
3
- "version": "4.4.0",
3
+ "version": "4.4.1",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "packageManager": "pnpm@11.18.0",