@softarc/native-federation 4.0.0-RC1 → 4.0.0-RC10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/package.json +2 -2
  2. package/src/config.d.ts +0 -1
  3. package/src/domain.d.ts +0 -1
  4. package/src/index.d.ts +3 -2
  5. package/src/index.js +3 -1
  6. package/src/internal.d.ts +5 -4
  7. package/src/internal.js +3 -1
  8. package/src/lib/config/configuration-context.d.ts +0 -1
  9. package/src/lib/config/default-skip-list.d.ts +0 -1
  10. package/src/lib/config/default-skip-list.js +3 -15
  11. package/src/lib/config/remove-unused-deps.d.ts +3 -0
  12. package/src/lib/config/remove-unused-deps.js +10 -0
  13. package/src/lib/config/share-utils.d.ts +0 -2
  14. package/src/lib/config/share-utils.js +7 -13
  15. package/src/lib/config/with-native-federation.d.ts +0 -1
  16. package/src/lib/config/with-native-federation.js +41 -59
  17. package/src/lib/core/build-adapter.d.ts +0 -1
  18. package/src/lib/core/build-adapter.js +5 -5
  19. package/src/lib/core/build-for-federation.d.ts +2 -5
  20. package/src/lib/core/build-for-federation.js +68 -59
  21. package/src/lib/core/bundle-exposed-and-mappings.d.ts +5 -6
  22. package/src/lib/core/bundle-exposed-and-mappings.js +56 -28
  23. package/src/lib/core/bundle-shared.d.ts +8 -5
  24. package/src/lib/core/bundle-shared.js +41 -18
  25. package/src/lib/core/default-external-list.d.ts +0 -1
  26. package/src/lib/core/default-external-list.js +1 -4
  27. package/src/lib/core/federation-builder.d.ts +6 -2
  28. package/src/lib/core/federation-builder.js +19 -8
  29. package/src/lib/core/federation-cache.d.ts +8 -0
  30. package/src/lib/core/federation-cache.js +11 -0
  31. package/src/lib/core/get-externals.d.ts +0 -1
  32. package/src/lib/core/get-externals.js +1 -1
  33. package/src/lib/core/normalize-options.d.ts +12 -0
  34. package/src/lib/core/normalize-options.js +57 -0
  35. package/src/lib/core/rebuild-for-federation.d.ts +4 -0
  36. package/src/lib/core/rebuild-for-federation.js +37 -0
  37. package/src/lib/core/write-federation-info.d.ts +0 -1
  38. package/src/lib/core/write-import-map.d.ts +5 -3
  39. package/src/lib/core/write-import-map.js +10 -1
  40. package/src/lib/domain/config/external-config.contract.d.ts +5 -2
  41. package/src/lib/domain/config/federation-config.contract.d.ts +10 -3
  42. package/src/lib/domain/config/index.d.ts +0 -1
  43. package/src/lib/domain/config/skip-list.contract.d.ts +0 -1
  44. package/src/lib/domain/config/with-native-federation.contract.d.ts +2 -0
  45. package/src/lib/domain/core/build-adapter.contract.d.ts +23 -11
  46. package/src/lib/domain/core/build-notification-options.contract.d.ts +0 -1
  47. package/src/lib/domain/core/chunk.d.ts +2 -0
  48. package/src/lib/domain/core/chunk.js +8 -0
  49. package/src/lib/domain/core/federation-cache.contract.d.ts +7 -0
  50. package/src/lib/domain/core/federation-cache.contract.js +1 -0
  51. package/src/lib/domain/core/federation-info.contract.d.ts +6 -2
  52. package/src/lib/domain/core/federation-options.contract.d.ts +8 -2
  53. package/src/lib/domain/core/index.d.ts +5 -5
  54. package/src/lib/domain/core/index.js +1 -0
  55. package/src/lib/domain/utils/index.d.ts +1 -2
  56. package/src/lib/domain/utils/keyvaluepair.contract.d.ts +0 -1
  57. package/src/lib/domain/utils/mapped-path.contract.d.ts +1 -5
  58. package/src/lib/domain/utils/mapped-path.contract.js +4 -0
  59. package/src/lib/domain/utils/used-dependencies.contract.d.ts +5 -0
  60. package/src/lib/domain/utils/used-dependencies.contract.js +1 -0
  61. package/src/lib/utils/build-result-map.d.ts +1 -1
  62. package/src/lib/utils/build-result-map.js +9 -2
  63. package/src/lib/utils/{bundle-caching.d.ts → cache-persistence.d.ts} +4 -3
  64. package/src/lib/utils/{bundle-caching.js → cache-persistence.js} +2 -2
  65. package/src/lib/utils/errors.d.ts +0 -1
  66. package/src/lib/utils/get-external-imports.d.ts +0 -1
  67. package/src/lib/utils/get-used-dependencies.d.ts +7 -0
  68. package/src/lib/utils/get-used-dependencies.js +123 -0
  69. package/src/lib/utils/hash-file.d.ts +0 -1
  70. package/src/lib/utils/logger.d.ts +0 -1
  71. package/src/lib/utils/mapped-paths.d.ts +7 -8
  72. package/src/lib/utils/mapped-paths.js +14 -12
  73. package/src/lib/utils/normalize.d.ts +0 -1
  74. package/src/lib/utils/package-info.d.ts +0 -1
  75. package/src/lib/utils/rebuild-queue.d.ts +14 -2
  76. package/src/lib/utils/rebuild-queue.js +32 -12
  77. package/src/lib/utils/resolve-glob.d.ts +0 -1
  78. package/src/lib/utils/resolve-glob.js +4 -4
  79. package/src/lib/utils/resolve-wildcard-keys.d.ts +29 -3
  80. package/src/lib/utils/resolve-wildcard-keys.js +105 -38
  81. package/src/lib/utils/rewrite-chunk-imports.d.ts +0 -3
  82. package/src/lib/utils/rewrite-chunk-imports.js +3 -10
  83. package/src/config.d.ts.map +0 -1
  84. package/src/domain.d.ts.map +0 -1
  85. package/src/index.d.ts.map +0 -1
  86. package/src/internal.d.ts.map +0 -1
  87. package/src/lib/config/configuration-context.d.ts.map +0 -1
  88. package/src/lib/config/default-skip-list.d.ts.map +0 -1
  89. package/src/lib/config/share-utils.d.ts.map +0 -1
  90. package/src/lib/config/with-native-federation.d.ts.map +0 -1
  91. package/src/lib/core/build-adapter.d.ts.map +0 -1
  92. package/src/lib/core/build-for-federation.d.ts.map +0 -1
  93. package/src/lib/core/bundle-exposed-and-mappings.d.ts.map +0 -1
  94. package/src/lib/core/bundle-shared.d.ts.map +0 -1
  95. package/src/lib/core/default-external-list.d.ts.map +0 -1
  96. package/src/lib/core/default-server-deps-list.d.ts +0 -3
  97. package/src/lib/core/default-server-deps-list.d.ts.map +0 -1
  98. package/src/lib/core/default-server-deps-list.js +0 -6
  99. package/src/lib/core/federation-builder.d.ts.map +0 -1
  100. package/src/lib/core/get-externals.d.ts.map +0 -1
  101. package/src/lib/core/load-federation-config.d.ts +0 -4
  102. package/src/lib/core/load-federation-config.d.ts.map +0 -1
  103. package/src/lib/core/load-federation-config.js +0 -18
  104. package/src/lib/core/remove-unused-deps.d.ts +0 -3
  105. package/src/lib/core/remove-unused-deps.d.ts.map +0 -1
  106. package/src/lib/core/remove-unused-deps.js +0 -88
  107. package/src/lib/core/write-federation-info.d.ts.map +0 -1
  108. package/src/lib/core/write-import-map.d.ts.map +0 -1
  109. package/src/lib/domain/config/external-config.contract.d.ts.map +0 -1
  110. package/src/lib/domain/config/federation-config.contract.d.ts.map +0 -1
  111. package/src/lib/domain/config/index.d.ts.map +0 -1
  112. package/src/lib/domain/config/skip-list.contract.d.ts.map +0 -1
  113. package/src/lib/domain/core/build-adapter.contract.d.ts.map +0 -1
  114. package/src/lib/domain/core/build-notification-options.contract.d.ts.map +0 -1
  115. package/src/lib/domain/core/build-params.contract.d.ts +0 -6
  116. package/src/lib/domain/core/build-params.contract.d.ts.map +0 -1
  117. package/src/lib/domain/core/federation-info.contract.d.ts.map +0 -1
  118. package/src/lib/domain/core/federation-options.contract.d.ts.map +0 -1
  119. package/src/lib/domain/core/index.d.ts.map +0 -1
  120. package/src/lib/domain/utils/index.d.ts.map +0 -1
  121. package/src/lib/domain/utils/keyvaluepair.contract.d.ts.map +0 -1
  122. package/src/lib/domain/utils/mapped-path.contract.d.ts.map +0 -1
  123. package/src/lib/utils/build-result-map.d.ts.map +0 -1
  124. package/src/lib/utils/build-utils.d.ts +0 -3
  125. package/src/lib/utils/build-utils.d.ts.map +0 -1
  126. package/src/lib/utils/build-utils.js +0 -5
  127. package/src/lib/utils/bundle-caching.d.ts.map +0 -1
  128. package/src/lib/utils/errors.d.ts.map +0 -1
  129. package/src/lib/utils/get-external-imports.d.ts.map +0 -1
  130. package/src/lib/utils/hash-file.d.ts.map +0 -1
  131. package/src/lib/utils/logger.d.ts.map +0 -1
  132. package/src/lib/utils/mapped-paths.d.ts.map +0 -1
  133. package/src/lib/utils/normalize.d.ts.map +0 -1
  134. package/src/lib/utils/package-info.d.ts.map +0 -1
  135. package/src/lib/utils/rebuild-queue.d.ts.map +0 -1
  136. package/src/lib/utils/resolve-glob.d.ts.map +0 -1
  137. package/src/lib/utils/resolve-wildcard-keys.d.ts.map +0 -1
  138. package/src/lib/utils/rewrite-chunk-imports.d.ts.map +0 -1
  139. /package/src/lib/domain/{core/build-params.contract.js → config/with-native-federation.contract.js} +0 -0
@@ -1,19 +1,21 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { createBuildResultMap, lookupInResultMap } from '../utils/build-result-map.js';
4
- import { bundle } from '../utils/build-utils.js';
3
+ import { createBuildResultMap, popFromResultMap } from '../utils/build-result-map.js';
5
4
  import { logger } from '../utils/logger.js';
6
5
  import { normalize } from '../utils/normalize.js';
7
6
  import { AbortedError } from '../utils/errors.js';
8
- export async function bundleExposedAndMappings(config, fedOptions, externals, signal) {
7
+ import { rewriteChunkImports } from '../utils/rewrite-chunk-imports.js';
8
+ import { getBuildAdapter } from './build-adapter.js';
9
+ export async function bundleExposedAndMappings(config, fedOptions, externals, modifiedFiles, signal) {
9
10
  if (signal?.aborted) {
10
11
  throw new AbortedError('[bundle-exposed-and-mappings] Aborted before bundling');
11
12
  }
12
- const shared = config.sharedMappings.map(sm => {
13
- const entryPoint = sm.path;
14
- const tmp = sm.key.replace(/[^A-Za-z0-9]/g, '_');
15
- const outFilePath = tmp + '.js';
16
- return { fileName: entryPoint, outName: outFilePath, key: sm.key };
13
+ const shared = Object.entries(config.sharedMappings).map(([entryPoint, mappedImport]) => {
14
+ return {
15
+ fileName: entryPoint,
16
+ outName: mappedImport.replace(/[^A-Za-z0-9]/g, '_') + '.js',
17
+ key: mappedImport,
18
+ };
17
19
  });
18
20
  const exposes = Object.entries(config.exposes).map(([key, entry]) => {
19
21
  const outFilePath = key + '.js';
@@ -21,21 +23,27 @@ export async function bundleExposedAndMappings(config, fedOptions, externals, si
21
23
  });
22
24
  const entryPoints = [...shared, ...exposes];
23
25
  const hash = !fedOptions.dev;
24
- logger.info('Building federation artefacts');
25
26
  let result;
26
27
  try {
27
- result = await bundle({
28
- entryPoints,
29
- outdir: fedOptions.outputPath,
30
- tsConfigPath: fedOptions.tsConfig,
31
- external: externals,
32
- dev: !!fedOptions.dev,
33
- watch: fedOptions.watch,
34
- mappedPaths: config.sharedMappings,
35
- kind: 'mapping-or-exposed',
36
- hash,
37
- optimizedMappings: config.features.ignoreUnusedDeps,
28
+ if (!modifiedFiles) {
29
+ await getBuildAdapter().setup('mapping-or-exposed', {
30
+ entryPoints,
31
+ outdir: fedOptions.outputPath,
32
+ tsConfigPath: fedOptions.tsConfig,
33
+ external: externals,
34
+ dev: !!fedOptions.dev,
35
+ watch: fedOptions.watch,
36
+ mappedPaths: config.sharedMappings,
37
+ chunks: config.chunks,
38
+ hash,
39
+ optimizedMappings: config.features.ignoreUnusedDeps,
40
+ isMappingOrExposed: true,
41
+ cache: fedOptions.federationCache,
42
+ });
43
+ }
44
+ result = await getBuildAdapter().build('mapping-or-exposed', {
38
45
  signal,
46
+ modifiedFiles,
39
47
  });
40
48
  if (signal?.aborted) {
41
49
  throw new AbortedError('[bundle-exposed-and-mappings] Aborted after bundle');
@@ -43,16 +51,19 @@ export async function bundleExposedAndMappings(config, fedOptions, externals, si
43
51
  }
44
52
  catch (error) {
45
53
  if (!(error instanceof AbortedError)) {
46
- logger.error('Error building federation artefacts');
54
+ logger.error('Error building federation artifacts');
47
55
  }
48
56
  throw error;
49
57
  }
50
58
  const resultMap = createBuildResultMap(result, hash);
51
59
  const sharedResult = [];
60
+ const entryFiles = [];
61
+ // Pick shared-mappings
52
62
  for (const item of shared) {
63
+ const distEntryFile = popFromResultMap(resultMap, item.outName);
53
64
  sharedResult.push({
54
65
  packageName: item.key,
55
- outFileName: lookupInResultMap(resultMap, item.outName),
66
+ outFileName: path.basename(distEntryFile),
56
67
  requiredVersion: '',
57
68
  singleton: true,
58
69
  strictVersion: false,
@@ -63,20 +74,37 @@ export async function bundleExposedAndMappings(config, fedOptions, externals, si
63
74
  entryPoint: normalize(path.normalize(item.fileName)),
64
75
  },
65
76
  });
77
+ entryFiles.push(distEntryFile);
66
78
  }
67
79
  const exposedResult = [];
80
+ // Pick exposed-modules
68
81
  for (const item of exposes) {
82
+ const distEntryFile = popFromResultMap(resultMap, item.outName);
69
83
  exposedResult.push({
70
84
  key: item.key,
71
- outFileName: lookupInResultMap(resultMap, item.outName),
85
+ outFileName: path.basename(distEntryFile),
72
86
  dev: !fedOptions.dev
73
87
  ? undefined
74
88
  : {
75
89
  entryPoint: normalize(path.join(fedOptions.workspaceRoot, item.fileName)),
76
90
  },
77
91
  });
92
+ entryFiles.push(distEntryFile);
93
+ }
94
+ // Remove .map files
95
+ Object.keys(resultMap)
96
+ .filter(f => f.endsWith('.map'))
97
+ .forEach(f => popFromResultMap(resultMap, f));
98
+ // Process remaining chunks and lazy loaded internal modules
99
+ let exportedChunks = undefined;
100
+ if (config.chunks && config.features.denseChunking) {
101
+ for (const entryFile of entryFiles)
102
+ rewriteChunkImports(entryFile);
103
+ exportedChunks = {
104
+ ['mapping-or-exposed']: Object.values(resultMap).map(chunk => path.basename(chunk)),
105
+ };
78
106
  }
79
- return { mappings: sharedResult, exposes: exposedResult };
107
+ return { mappings: sharedResult, exposes: exposedResult, chunks: exportedChunks };
80
108
  }
81
109
  export function describeExposed(config, options) {
82
110
  const result = [];
@@ -96,18 +124,18 @@ export function describeExposed(config, options) {
96
124
  }
97
125
  export function describeSharedMappings(config, fedOptions) {
98
126
  const result = [];
99
- for (const m of config.sharedMappings) {
127
+ for (const [mappedPath, mappedImport] of Object.entries(config.sharedMappings)) {
100
128
  result.push({
101
- packageName: m.key,
129
+ packageName: mappedImport,
102
130
  outFileName: '',
103
131
  requiredVersion: '',
104
132
  singleton: true,
105
133
  strictVersion: false,
106
- version: config.features.mappingVersion ? getMappingVersion(m.path) : '',
134
+ version: config.features.mappingVersion ? getMappingVersion(mappedPath) : '',
107
135
  dev: !fedOptions.dev
108
136
  ? undefined
109
137
  : {
110
- entryPoint: normalize(path.normalize(m.path)),
138
+ entryPoint: normalize(path.normalize(mappedPath)),
111
139
  },
112
140
  });
113
141
  }
@@ -1,9 +1,12 @@
1
1
  import type { NormalizedFederationConfig } from '../domain/config/federation-config.contract.js';
2
2
  import type { SharedInfo } from '../domain/core/federation-info.contract.js';
3
- import { type FederationOptions } from '../domain/core/federation-options.contract.js';
3
+ import { type NormalizedFederationOptions } from '../domain/core/federation-options.contract.js';
4
4
  import type { NormalizedExternalConfig } from '../domain/config/external-config.contract.js';
5
- export declare function bundleShared(sharedBundles: Record<string, NormalizedExternalConfig>, config: NormalizedFederationConfig, fedOptions: FederationOptions, externals: string[], platform: "browser" | "node" | undefined, cacheOptions: {
6
- pathToCache: string;
5
+ export declare function bundleShared(sharedBundles: Record<string, NormalizedExternalConfig>, config: NormalizedFederationConfig, fedOptions: NormalizedFederationOptions, externals: string[], buildOptions: {
6
+ platform: 'browser' | 'node';
7
7
  bundleName: string;
8
- }): Promise<Array<SharedInfo>>;
9
- //# sourceMappingURL=bundle-shared.d.ts.map
8
+ chunks: boolean;
9
+ }): Promise<{
10
+ externals: SharedInfo[];
11
+ chunks?: Record<string, string[]>;
12
+ }>;
@@ -1,25 +1,26 @@
1
1
  import * as path from 'path';
2
2
  import * as fs from 'fs';
3
- import { bundle } from '../utils/build-utils.js';
4
3
  import { getPackageInfo } from '../utils/package-info.js';
5
4
  import { logger } from '../utils/logger.js';
6
5
  import crypto from 'crypto';
7
6
  import { DEFAULT_EXTERNAL_LIST } from './default-external-list.js';
8
- import { deriveInternalName, isSourceFile, rewriteChunkImports, } from '../utils/rewrite-chunk-imports.js';
9
- import { cacheEntry, getChecksum, getFilename } from './../utils/bundle-caching.js';
7
+ import { isSourceFile, rewriteChunkImports } from '../utils/rewrite-chunk-imports.js';
8
+ import { toChunkImport } from '../domain/core/chunk.js';
9
+ import { cacheEntry, getChecksum, getFilename } from '../utils/cache-persistence.js';
10
10
  import { fileURLToPath } from 'url';
11
- export async function bundleShared(sharedBundles, config, fedOptions, externals, platform = 'browser', cacheOptions) {
11
+ import { getBuildAdapter } from './build-adapter.js';
12
+ export async function bundleShared(sharedBundles, config, fedOptions, externals, buildOptions) {
12
13
  const checksum = getChecksum(sharedBundles, fedOptions.dev ? '1' : '0');
13
14
  const folder = fedOptions.packageJson
14
15
  ? path.dirname(fedOptions.packageJson)
15
16
  : fedOptions.workspaceRoot;
16
- const bundleCache = cacheEntry(cacheOptions.pathToCache, getFilename(cacheOptions.bundleName, fedOptions.dev));
17
+ const bundleCache = cacheEntry(fedOptions.federationCache.cachePath, getFilename(buildOptions.bundleName, fedOptions.dev));
17
18
  if (fedOptions?.cacheExternalArtifacts) {
18
19
  const cacheMetadata = bundleCache.getMetadata(checksum);
19
20
  if (cacheMetadata) {
20
- logger.debug(`Checksum of ${cacheOptions.bundleName} matched, Skipped artifact bundling`);
21
+ logger.debug(`Checksum of ${buildOptions.bundleName} matched, Skipped artifact bundling`);
21
22
  bundleCache.copyFiles(path.join(fedOptions.workspaceRoot, fedOptions.outputPath));
22
- return cacheMetadata.externals;
23
+ return { externals: cacheMetadata.externals, chunks: cacheMetadata.chunks };
23
24
  }
24
25
  }
25
26
  bundleCache.clear();
@@ -45,27 +46,31 @@ export async function bundleShared(sharedBundles, config, fedOptions, externals,
45
46
  });
46
47
  const fullOutputPath = path.join(fedOptions.workspaceRoot, fedOptions.outputPath);
47
48
  const expectedResults = allEntryPoints.map(ep => path.join(fullOutputPath, ep.outName));
48
- const entryPoints = allEntryPoints.filter(ep => !fs.existsSync(path.join(cacheOptions.pathToCache, ep.outName)));
49
+ const entryPoints = allEntryPoints.filter(ep => !fs.existsSync(path.join(fedOptions.federationCache.cachePath, ep.outName)));
49
50
  // If we build for the browser and don't remote unused deps from the shared config,
50
51
  // we need to exclude typical node libs to avoid compilation issues
51
- const useDefaultExternalList = platform === 'browser' && !config.features.ignoreUnusedDeps;
52
+ const useDefaultExternalList = buildOptions.platform === 'browser' && !config.features.ignoreUnusedDeps;
52
53
  const additionalExternals = useDefaultExternalList ? DEFAULT_EXTERNAL_LIST : [];
53
54
  let bundleResult = null;
54
55
  try {
55
- bundleResult = await bundle({
56
+ await getBuildAdapter().setup(buildOptions.bundleName, {
56
57
  entryPoints,
57
58
  tsConfigPath: fedOptions.tsConfig,
58
59
  external: [...additionalExternals, ...externals],
59
- outdir: cacheOptions.pathToCache,
60
+ outdir: fedOptions.federationCache.cachePath,
60
61
  mappedPaths: config.sharedMappings,
61
62
  dev: fedOptions.dev,
62
- kind: 'shared-package',
63
+ isMappingOrExposed: false,
63
64
  hash: false,
64
- platform,
65
+ chunks: buildOptions.chunks,
66
+ platform: buildOptions.platform,
65
67
  optimizedMappings: config.features.ignoreUnusedDeps,
68
+ cache: fedOptions.federationCache,
66
69
  });
70
+ bundleResult = await getBuildAdapter().build(buildOptions.bundleName);
71
+ await getBuildAdapter().dispose(buildOptions.bundleName);
67
72
  const cachedFiles = bundleResult.map(br => path.basename(br.fileName));
68
- rewriteImports(cachedFiles, cacheOptions.pathToCache);
73
+ rewriteImports(cachedFiles, fedOptions.federationCache.cachePath);
69
74
  }
70
75
  catch (e) {
71
76
  logger.error('Error bundling shared npm package ');
@@ -89,17 +94,31 @@ export async function bundleShared(sharedBundles, config, fedOptions, externals,
89
94
  }
90
95
  const outFileNames = [...expectedResults];
91
96
  const result = buildResult(packageInfos, sharedBundles, outFileNames);
92
- // TODO: Decide whether/when to add .map files
93
97
  const chunks = bundleResult.filter(br => !br.fileName.endsWith('.map') &&
94
98
  !result.find(r => r.outFileName === path.basename(br.fileName)));
95
- addChunksToResult(chunks, result);
99
+ /**
100
+ * Chunking
101
+ */
102
+ let exportedChunks = undefined;
103
+ if (buildOptions.chunks && config.features.denseChunking) {
104
+ result.forEach(external => {
105
+ external.bundle = buildOptions.bundleName;
106
+ });
107
+ if (chunks.length > 0) {
108
+ exportedChunks = { [buildOptions.bundleName]: getChunkFileNames(chunks) };
109
+ }
110
+ }
111
+ else {
112
+ addChunksToResult(chunks, result);
113
+ }
96
114
  bundleCache.persist({
97
115
  checksum,
98
116
  externals: result,
99
117
  files: bundleResult.map(r => r.fileName.split(path.sep).pop() ?? r.fileName),
118
+ chunks: exportedChunks,
100
119
  });
101
120
  bundleCache.copyFiles(path.join(fedOptions.workspaceRoot, fedOptions.outputPath));
102
- return result;
121
+ return { externals: result, chunks: exportedChunks };
103
122
  }
104
123
  function rewriteImports(cachedFiles, cachePath) {
105
124
  const newSourceFiles = cachedFiles.filter(cf => isSourceFile(cf));
@@ -124,6 +143,7 @@ function buildResult(packageInfos, sharedBundles, outFileNames) {
124
143
  singleton: shared?.singleton,
125
144
  strictVersion: shared?.strictVersion,
126
145
  version: pi.version,
146
+ ...(shared?.shareScope && { shareScope: shared.shareScope }),
127
147
  // TODO: Decide whether/when we need debug infos
128
148
  // dev: !fedOptions.dev
129
149
  // ? undefined
@@ -133,6 +153,9 @@ function buildResult(packageInfos, sharedBundles, outFileNames) {
133
153
  };
134
154
  });
135
155
  }
156
+ function getChunkFileNames(chunks) {
157
+ return chunks.map(chunk => path.basename(chunk.fileName));
158
+ }
136
159
  function addChunksToResult(chunks, result) {
137
160
  for (const item of chunks) {
138
161
  const fileName = path.basename(item.fileName);
@@ -149,7 +172,7 @@ function addChunksToResult(chunks, result) {
149
172
  // take care of singleton and strictVersion.
150
173
  version: '0.0.0',
151
174
  requiredVersion: '0.0.0',
152
- packageName: deriveInternalName(fileName),
175
+ packageName: toChunkImport(fileName),
153
176
  outFileName: fileName,
154
177
  // dev: dev
155
178
  // ? undefined
@@ -1,2 +1 @@
1
1
  export declare const DEFAULT_EXTERNAL_LIST: string[];
2
- //# sourceMappingURL=default-external-list.d.ts.map
@@ -26,7 +26,4 @@ const NODE_PACKAGES = [
26
26
  'vm',
27
27
  'zlib',
28
28
  ];
29
- export const DEFAULT_EXTERNAL_LIST = NODE_PACKAGES.flatMap((p) => [
30
- p,
31
- 'node:' + p,
32
- ]);
29
+ export const DEFAULT_EXTERNAL_LIST = NODE_PACKAGES.flatMap(p => [p, 'node:' + p]);
@@ -7,13 +7,17 @@ export interface BuildHelperParams {
7
7
  adapter: NFBuildAdapter;
8
8
  }
9
9
  declare function init(params: BuildHelperParams): Promise<void>;
10
- declare function build(buildParams?: import("../../domain.js").BuildParams): Promise<void>;
10
+ declare function build(opts?: {
11
+ modifiedFiles?: string[];
12
+ signal?: AbortSignal;
13
+ }): Promise<void>;
14
+ declare function close(): Promise<void>;
11
15
  export declare const federationBuilder: {
12
16
  init: typeof init;
13
17
  build: typeof build;
18
+ close: typeof close;
14
19
  readonly federationInfo: FederationInfo;
15
20
  readonly externals: string[];
16
21
  readonly config: NormalizedFederationConfig;
17
22
  };
18
23
  export {};
19
- //# sourceMappingURL=federation-builder.d.ts.map
@@ -1,27 +1,38 @@
1
1
  import { getConfigContext, usePackageJson, useWorkspace } from '../config/configuration-context.js';
2
- import { setBuildAdapter } from './build-adapter.js';
3
- import { buildForFederation, defaultBuildParams } from './build-for-federation.js';
2
+ import { getBuildAdapter, setBuildAdapter } from './build-adapter.js';
3
+ import { buildForFederation } from './build-for-federation.js';
4
4
  import { getExternals } from './get-externals.js';
5
- import { loadFederationConfig } from './load-federation-config.js';
5
+ import { normalizeFederationOptions } from './normalize-options.js';
6
+ import { rebuildForFederation } from './rebuild-for-federation.js';
6
7
  let externals = [];
7
8
  let config;
8
- let fedOptions;
9
+ let options;
9
10
  let fedInfo;
10
11
  async function init(params) {
11
12
  setBuildAdapter(params.adapter);
12
- fedOptions = params.options;
13
13
  useWorkspace(params.options.workspaceRoot);
14
14
  usePackageJson(params.options.packageJson);
15
- config = await loadFederationConfig(fedOptions);
16
15
  params.options.workspaceRoot = getConfigContext().workspaceRoot ?? params.options.workspaceRoot;
16
+ const normalized = await normalizeFederationOptions(params.options);
17
+ options = normalized.options;
18
+ config = normalized.config;
17
19
  externals = getExternals(config);
18
20
  }
19
- async function build(buildParams = defaultBuildParams) {
20
- fedInfo = await buildForFederation(config, fedOptions, externals, buildParams);
21
+ async function build(opts = {}) {
22
+ if (!fedInfo) {
23
+ fedInfo = await buildForFederation(config, options, externals, opts.signal);
24
+ }
25
+ else {
26
+ fedInfo = await rebuildForFederation(config, options, externals, opts.modifiedFiles ?? [], opts.signal);
27
+ }
28
+ }
29
+ async function close() {
30
+ return getBuildAdapter().dispose();
21
31
  }
22
32
  export const federationBuilder = {
23
33
  init,
24
34
  build,
35
+ close,
25
36
  get federationInfo() {
26
37
  return fedInfo;
27
38
  },
@@ -0,0 +1,8 @@
1
+ import type { FederationCache } from '../domain/core/federation-cache.contract.js';
2
+ import type { ChunkInfo, SharedInfo } from '../domain/core/federation-info.contract.js';
3
+ export declare function createFederationCache(cachePath: string): FederationCache<undefined>;
4
+ export declare function createFederationCache<TBundlerCache>(cachePath: string, bundlerCache: TBundlerCache): FederationCache<TBundlerCache>;
5
+ export declare function addExternalsToCache(cache: FederationCache, { externals, chunks }: {
6
+ externals: SharedInfo[];
7
+ chunks?: ChunkInfo;
8
+ }): void;
@@ -0,0 +1,11 @@
1
+ export function createFederationCache(cachePath, bundlerCache) {
2
+ return { externals: [], cachePath, bundlerCache };
3
+ }
4
+ export function addExternalsToCache(cache, { externals, chunks }) {
5
+ cache.externals.push(...externals);
6
+ if (chunks) {
7
+ if (!cache.chunks)
8
+ cache.chunks = {};
9
+ cache.chunks = { ...cache.chunks, ...chunks };
10
+ }
11
+ }
@@ -1,3 +1,2 @@
1
1
  import type { NormalizedFederationConfig } from '../domain/config/federation-config.contract.js';
2
2
  export declare function getExternals(config: NormalizedFederationConfig): string[];
3
- //# sourceMappingURL=get-externals.d.ts.map
@@ -1,6 +1,6 @@
1
1
  export function getExternals(config) {
2
2
  const shared = Object.keys(config.shared);
3
- const sharedMappings = config.sharedMappings.map(m => m.key);
3
+ const sharedMappings = Object.values(config.sharedMappings);
4
4
  const externals = [...shared, ...sharedMappings, ...config.externals];
5
5
  return externals;
6
6
  }
@@ -0,0 +1,12 @@
1
+ import type { NormalizedFederationConfig } from '../domain/config/federation-config.contract.js';
2
+ import type { FederationOptions, NormalizedFederationOptions } from '../domain/core/federation-options.contract.js';
3
+ import { type FederationCache } from '../../domain.js';
4
+ export declare function normalizeFederationOptions(options: FederationOptions): Promise<{
5
+ config: NormalizedFederationConfig;
6
+ options: NormalizedFederationOptions<undefined>;
7
+ }>;
8
+ export declare function normalizeFederationOptions<TBundlerCache>(options: FederationOptions, cache: FederationCache<TBundlerCache>): Promise<{
9
+ config: NormalizedFederationConfig;
10
+ options: NormalizedFederationOptions<TBundlerCache>;
11
+ }>;
12
+ export declare function resolveProjectName(name?: string): string;
@@ -0,0 +1,57 @@
1
+ import * as path from 'path';
2
+ import * as fs from 'fs';
3
+ import { pathToFileURL } from 'url';
4
+ import { removeUnusedDeps } from '../config/remove-unused-deps.js';
5
+ import { createFederationCache } from './federation-cache.js';
6
+ import { getDefaultCachePath } from '../utils/cache-persistence.js';
7
+ import { getUsedDependenciesFactory } from '../utils/get-used-dependencies.js';
8
+ import { logger } from '../utils/logger.js';
9
+ import { normalizePackageName } from '../utils/normalize.js';
10
+ export async function normalizeFederationOptions(options, cache) {
11
+ /**
12
+ * Step 1: normalizing config
13
+ */
14
+ const fullConfigPath = path.join(options.workspaceRoot, options.federationConfig);
15
+ const getUsedDeps = getUsedDependenciesFactory(options.workspaceRoot, options.entryPoints);
16
+ if (!fs.existsSync(fullConfigPath)) {
17
+ throw new Error('Expected ' + fullConfigPath);
18
+ }
19
+ let config = (await import(pathToFileURL(fullConfigPath).href))
20
+ ?.default;
21
+ /**
22
+ * Step 2: normalizing options
23
+ */
24
+ const federationCache = cache ??
25
+ createFederationCache(getDefaultCachePath(options.workspaceRoot));
26
+ const normalizedOptions = {
27
+ ...options,
28
+ entryPoints: options.entryPoints ?? Object.values(config.exposes ?? {}),
29
+ projectName: resolveProjectName(options.projectName ?? config.name),
30
+ federationCache,
31
+ };
32
+ /**
33
+ * Step 3: Remove unused deps
34
+ */
35
+ if (config.features.ignoreUnusedDeps) {
36
+ config = removeUnusedDeps(getUsedDeps(config), config);
37
+ logger.info('Removed unused dependencies.');
38
+ logger.debug('This can be disabled per dependency/external using the "includeSecondaries: {keepAll: true}" property. Or in general by disabling the "ignoreUnusedDeps" feature. ');
39
+ }
40
+ else {
41
+ const withWildcard = Object.keys(config.sharedMappings).some(m => m.includes('*'));
42
+ if (withWildcard) {
43
+ logger.warn('Sharing mapped paths with wildcards (*) is only supported with ignoreUnusedDeps feature.');
44
+ config.sharedMappings = Object.entries(config.sharedMappings)
45
+ .filter(([_path]) => !_path.includes('*'))
46
+ .reduce((acc, [_path, _import]) => ({ ...acc, [_path]: _import }), {});
47
+ }
48
+ }
49
+ return { config, options: normalizedOptions };
50
+ }
51
+ export function resolveProjectName(name) {
52
+ if (!name || name.length < 1) {
53
+ logger.warn("Project name in 'federation.config.js' is empty, defaulting to 'shell' cache folder (could collide with other projects in the workspace).");
54
+ return 'shell';
55
+ }
56
+ return normalizePackageName(name);
57
+ }
@@ -0,0 +1,4 @@
1
+ import type { FederationInfo } from '../domain/core/federation-info.contract.js';
2
+ import type { NormalizedFederationOptions } from '../domain/core/federation-options.contract.js';
3
+ import type { NormalizedFederationConfig } from '../domain/config/federation-config.contract.js';
4
+ export declare function rebuildForFederation(config: NormalizedFederationConfig, fedOptions: NormalizedFederationOptions, externals: string[], modifiedFiles: string[], signal?: AbortSignal): Promise<FederationInfo>;
@@ -0,0 +1,37 @@
1
+ import { bundleExposedAndMappings, describeExposed, describeSharedMappings, } from './bundle-exposed-and-mappings.js';
2
+ import { writeFederationInfo } from './write-federation-info.js';
3
+ import { writeImportMap } from './write-import-map.js';
4
+ import { logger } from '../utils/logger.js';
5
+ import { AbortedError } from '../utils/errors.js';
6
+ export async function rebuildForFederation(config, fedOptions, externals, modifiedFiles, signal) {
7
+ const federationCache = fedOptions.federationCache;
8
+ logger.info(`Re-bundling all internal libraries and exposed modules..'`);
9
+ const start = process.hrtime();
10
+ const artifactInfo = await bundleExposedAndMappings(config, fedOptions, externals, modifiedFiles, signal);
11
+ logger.measure(start, 'To re-bundle all internal libraries and exposed modules.');
12
+ if (signal?.aborted)
13
+ throw new AbortedError('[buildForFederation] After exposed-and-mappings bundle');
14
+ const exposedInfo = !artifactInfo ? describeExposed(config, fedOptions) : artifactInfo.exposes;
15
+ const sharedMappingInfo = !artifactInfo
16
+ ? describeSharedMappings(config, fedOptions)
17
+ : artifactInfo.mappings;
18
+ const sharedExternals = [...federationCache.externals, ...sharedMappingInfo];
19
+ const buildNotificationsEndpoint = fedOptions.buildNotifications?.enable && fedOptions.dev
20
+ ? fedOptions.buildNotifications?.endpoint
21
+ : undefined;
22
+ const federationInfo = {
23
+ name: config.name,
24
+ shared: sharedExternals,
25
+ exposes: exposedInfo,
26
+ buildNotificationsEndpoint,
27
+ };
28
+ if (federationCache.chunks) {
29
+ federationInfo.chunks = federationCache.chunks;
30
+ }
31
+ if (artifactInfo?.chunks) {
32
+ federationInfo.chunks = { ...(federationInfo.chunks ?? {}), ...artifactInfo?.chunks };
33
+ }
34
+ writeFederationInfo(federationInfo, fedOptions);
35
+ writeImportMap(federationCache, fedOptions);
36
+ return federationInfo;
37
+ }
@@ -1,4 +1,3 @@
1
1
  import type { FederationInfo } from '../domain/core/federation-info.contract.js';
2
2
  import type { FederationOptions } from '../domain/core/federation-options.contract.js';
3
3
  export declare function writeFederationInfo(federationInfo: FederationInfo, fedOptions: FederationOptions): void;
4
- //# sourceMappingURL=write-federation-info.d.ts.map
@@ -1,4 +1,6 @@
1
- import type { SharedInfo } from '../domain/core/federation-info.contract.js';
1
+ import type { ChunkInfo, SharedInfo } from '../domain/core/federation-info.contract.js';
2
2
  import type { FederationOptions } from '../domain/core/federation-options.contract.js';
3
- export declare function writeImportMap(sharedInfo: SharedInfo[], fedOption: FederationOptions): void;
4
- //# sourceMappingURL=write-import-map.d.ts.map
3
+ export declare function writeImportMap(sharedInfo: {
4
+ externals: SharedInfo[];
5
+ chunks?: ChunkInfo;
6
+ }, fedOption: FederationOptions): void;
@@ -1,12 +1,21 @@
1
1
  import * as path from 'path';
2
2
  import * as fs from 'fs';
3
+ import { toChunkImport } from '../domain/core/chunk.js';
3
4
  export function writeImportMap(sharedInfo, fedOption) {
4
- const imports = sharedInfo.reduce((acc, cur) => {
5
+ const imports = sharedInfo.externals.reduce((acc, cur) => {
5
6
  return {
6
7
  ...acc,
7
8
  [cur.packageName]: cur.outFileName,
8
9
  };
9
10
  }, {});
11
+ if (sharedInfo.chunks) {
12
+ Object.values(sharedInfo.chunks).forEach(c => {
13
+ c.forEach(e => {
14
+ const key = toChunkImport(e);
15
+ imports[key] = e;
16
+ });
17
+ });
18
+ }
10
19
  const importMap = { imports };
11
20
  const importMapPath = path.join(fedOption.workspaceRoot, fedOption.outputPath, 'importmap.json');
12
21
  fs.writeFileSync(importMapPath, JSON.stringify(importMap, null, 2));
@@ -5,7 +5,9 @@ export interface ExternalConfig {
5
5
  version?: string;
6
6
  includeSecondaries?: boolean;
7
7
  platform?: 'browser' | 'node';
8
- build?: 'default' | 'separate';
8
+ build?: 'separate' | 'package';
9
+ chunks?: boolean;
10
+ shareScope?: string;
9
11
  packageInfo?: {
10
12
  entryPoint: string;
11
13
  version?: string;
@@ -18,6 +20,8 @@ export interface NormalizedExternalConfig {
18
20
  requiredVersion: string;
19
21
  version?: string;
20
22
  includeSecondaries?: boolean;
23
+ shareScope?: string;
24
+ chunks: boolean;
21
25
  platform: 'browser' | 'node';
22
26
  build: 'default' | 'separate' | 'package';
23
27
  packageInfo?: {
@@ -37,4 +41,3 @@ export type ShareAllExternalsOptions = ExternalConfig & {
37
41
  includeSecondaries?: IncludeSecondariesOptions;
38
42
  };
39
43
  export type ShareExternalsOptions = Record<string, ShareAllExternalsOptions>;
40
- //# sourceMappingURL=external-config.contract.d.ts.map
@@ -1,28 +1,35 @@
1
1
  import type { PreparedSkipList, SkipList } from './skip-list.contract.js';
2
- import type { MappedPath } from '../utils/mapped-path.contract.js';
2
+ import type { PathToImport } from '../utils/mapped-path.contract.js';
3
3
  import type { NormalizedSharedExternalsConfig, SharedExternalsConfig } from './external-config.contract.js';
4
4
  export interface FederationConfig {
5
5
  name?: string;
6
6
  exposes?: Record<string, string>;
7
7
  shared?: SharedExternalsConfig;
8
+ platform?: 'browser' | 'node';
8
9
  sharedMappings?: Array<string>;
10
+ chunks?: boolean;
9
11
  skip?: SkipList;
10
12
  externals?: string[];
13
+ shareScope?: string;
11
14
  features?: {
12
15
  mappingVersion?: boolean;
13
16
  ignoreUnusedDeps?: boolean;
17
+ denseChunking?: boolean;
14
18
  };
15
19
  }
16
20
  export interface NormalizedFederationConfig {
21
+ $type: 'classic';
17
22
  name: string;
18
23
  exposes: Record<string, string>;
19
24
  shared: NormalizedSharedExternalsConfig;
20
- sharedMappings: Array<MappedPath>;
25
+ sharedMappings: PathToImport;
21
26
  skip: PreparedSkipList;
27
+ chunks: boolean;
22
28
  externals: string[];
29
+ shareScope?: string;
23
30
  features: {
24
31
  mappingVersion: boolean;
25
32
  ignoreUnusedDeps: boolean;
33
+ denseChunking: boolean;
26
34
  };
27
35
  }
28
- //# sourceMappingURL=federation-config.contract.d.ts.map