Skip to content

Commit f978cce

Browse files
committed
feat(nf): Updated to cache per bundle
1 parent a713a31 commit f978cce

3 files changed

Lines changed: 107 additions & 66 deletions

File tree

libs/native-federation-core/src/lib/core/build-for-federation.ts

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,7 @@ import { FederationOptions } from './federation-options';
1414
import { writeFederationInfo } from './write-federation-info';
1515
import { writeImportMap } from './write-import-map';
1616
import { logger } from '../utils/logger';
17-
import {
18-
copyCacheToDist,
19-
getCachedMetadata,
20-
getCachePath,
21-
getChecksum,
22-
purgeCacheFolder,
23-
storeCachedMetadata,
24-
} from './get-cache';
25-
import path from 'path';
17+
import { getCachePath } from './get-cache';
2618
import { normalizeFilename } from '../utils/normalize';
2719

2820
export interface BuildParams {
@@ -35,6 +27,8 @@ export const defaultBuildParams: BuildParams = {
3527
skipShared: false,
3628
};
3729

30+
const sharedPackageInfoCache: SharedInfo[] = [];
31+
3832
export async function buildForFederation(
3933
config: NormalizedFederationConfig,
4034
fedOptions: FederationOptions,
@@ -67,24 +61,16 @@ export async function buildForFederation(
6761
);
6862
}
6963

70-
const cacheFolder = getCachePath(
64+
const pathToCache = getCachePath(
7165
fedOptions.workspaceRoot,
7266
normalizeFilename(config.name)
7367
);
74-
const cacheChecksum = getChecksum(config.shared);
75-
76-
const sharedPackageInfoCache: SharedInfo[] = getCachedMetadata(
77-
cacheFolder,
78-
cacheChecksum
79-
);
8068

8169
if (!buildParams.skipShared && sharedPackageInfoCache.length > 0) {
8270
logger.info('Checksum matched, re-using cached externals.');
8371
}
8472

8573
if (!buildParams.skipShared && sharedPackageInfoCache.length === 0) {
86-
purgeCacheFolder(cacheFolder);
87-
8874
const { sharedBrowser, sharedServer, separateBrowser, separateServer } =
8975
splitShared(config.shared);
9076

@@ -96,7 +82,7 @@ export async function buildForFederation(
9682
fedOptions,
9783
externals,
9884
'browser',
99-
cacheFolder
85+
{ pathToCache, metaDataFile: 'meta-browser-shared.json' }
10086
);
10187

10288
logger.measure(
@@ -115,7 +101,7 @@ export async function buildForFederation(
115101
fedOptions,
116102
externals,
117103
'node',
118-
cacheFolder
104+
{ pathToCache, metaDataFile: 'meta-node-shared.json' }
119105
);
120106
logger.measure(
121107
start,
@@ -132,7 +118,7 @@ export async function buildForFederation(
132118
config,
133119
fedOptions,
134120
'browser',
135-
cacheFolder
121+
pathToCache
136122
);
137123
logger.measure(
138124
start,
@@ -149,20 +135,14 @@ export async function buildForFederation(
149135
config,
150136
fedOptions,
151137
'node',
152-
cacheFolder
138+
pathToCache
153139
);
154140
logger.measure(
155141
start,
156142
'[build artifacts] - To bundle all separate node externals'
157143
);
158144
sharedPackageInfoCache.push(...separatePackageInfoServer);
159145
}
160-
161-
copyCacheToDist(
162-
cacheFolder,
163-
path.join(fedOptions.workspaceRoot, fedOptions.outputPath)
164-
);
165-
storeCachedMetadata(cacheFolder, cacheChecksum, sharedPackageInfoCache);
166146
}
167147

168148
const sharedMappingInfo = !artefactInfo
@@ -208,7 +188,7 @@ async function bundleSeparate(
208188
config: NormalizedFederationConfig,
209189
fedOptions: FederationOptions,
210190
platform: 'node' | 'browser',
211-
dest: string
191+
pathToCache: string
212192
) {
213193
const bundlePromises = Object.entries(separateBrowser).map(
214194
async ([key, shared]) => {
@@ -222,7 +202,10 @@ async function bundleSeparate(
222202
fedOptions,
223203
filteredExternals,
224204
platform,
225-
dest
205+
{
206+
pathToCache,
207+
metaDataFile: `meta-${platform}-${normalizeFilename(key)}.json`,
208+
}
226209
);
227210
}
228211
);

libs/native-federation-core/src/lib/core/bundle-shared.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,48 @@ import {
1717
isSourceFile,
1818
rewriteChunkImports,
1919
} from '../utils/rewrite-chunk-imports';
20+
import {
21+
copyCacheToDist,
22+
getCachedMetadata,
23+
getChecksum,
24+
purgeCacheFolder,
25+
storeCachedMetadata,
26+
} from './get-cache';
2027

2128
export async function bundleShared(
2229
sharedBundles: Record<string, NormalizedSharedConfig>,
2330
config: NormalizedFederationConfig,
2431
fedOptions: FederationOptions,
2532
externals: string[],
2633
platform: 'browser' | 'node' = 'browser',
27-
dest: string
34+
cache: { pathToCache: string; metaDataFile: string }
2835
): Promise<Array<SharedInfo>> {
36+
const checksum = getChecksum(sharedBundles);
2937
const folder = fedOptions.packageJson
3038
? path.dirname(fedOptions.packageJson)
3139
: fedOptions.workspaceRoot;
3240

33-
fs.mkdirSync(dest, { recursive: true });
41+
fs.mkdirSync(cache.pathToCache, { recursive: true });
42+
43+
const sharedPackageInfoCache = getCachedMetadata(
44+
cache.pathToCache,
45+
cache.metaDataFile,
46+
checksum
47+
);
48+
49+
if (sharedPackageInfoCache) {
50+
logger.info(
51+
`Checksum of ${cache.metaDataFile} matched, Skipped artifact bundling`
52+
);
53+
copyCacheToDist(
54+
cache.pathToCache,
55+
cache.metaDataFile,
56+
path.join(fedOptions.workspaceRoot, fedOptions.outputPath)
57+
);
58+
return sharedPackageInfoCache;
59+
}
60+
61+
purgeCacheFolder(cache.pathToCache, cache.metaDataFile);
3462

3563
const inferredPackageInfos = Object.keys(sharedBundles)
3664
.filter((packageName) => !sharedBundles[packageName].packageInfo)
@@ -66,7 +94,7 @@ export async function bundleShared(
6694
path.join(fullOutputPath, ep.outName)
6795
);
6896
const entryPoints = allEntryPoints.filter(
69-
(ep) => !fs.existsSync(path.join(dest, ep.outName))
97+
(ep) => !fs.existsSync(path.join(cache.pathToCache, ep.outName))
7098
);
7199

72100
if (entryPoints.length > 0) {
@@ -93,7 +121,7 @@ export async function bundleShared(
93121
entryPoints,
94122
tsConfigPath: fedOptions.tsConfig,
95123
external: [...additionalExternals, ...externals],
96-
outdir: dest,
124+
outdir: cache.pathToCache,
97125
mappedPaths: config.sharedMappings,
98126
dev: fedOptions.dev,
99127
kind: 'shared-package',
@@ -103,9 +131,7 @@ export async function bundleShared(
103131
});
104132

105133
const cachedFiles = bundleResult.map((br) => path.basename(br.fileName));
106-
rewriteImports(cachedFiles, dest);
107-
108-
// copyCacheToOutput(cachedFiles, cachePath, fullOutputPath);
134+
rewriteImports(cachedFiles, cache.pathToCache);
109135
} catch (e) {
110136
logger.error('Error bundling shared npm package ');
111137
if (e instanceof Error) {
@@ -156,6 +182,18 @@ export async function bundleShared(
156182

157183
addChunksToResult(chunks, result, fedOptions.dev);
158184

185+
storeCachedMetadata(cache.pathToCache, cache.metaDataFile, {
186+
checksum,
187+
externals: result,
188+
files: bundleResult.map((r) => r.fileName.split('/').pop() ?? r.fileName),
189+
});
190+
191+
copyCacheToDist(
192+
cache.pathToCache,
193+
cache.metaDataFile,
194+
path.join(fedOptions.workspaceRoot, fedOptions.outputPath)
195+
);
196+
159197
return result;
160198
}
161199

libs/native-federation-core/src/lib/core/get-cache.ts

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import fs from 'fs';
33
import crypto from 'crypto';
44
import { NormalizedSharedConfig } from '../config/federation-config';
55
import { SharedInfo } from '@softarc/native-federation-runtime';
6+
import { logger } from '../utils/logger';
67

78
export const getCachePath = (workspaceRoot: string, project: string) =>
89
path.join(workspaceRoot, 'node_modules/.cache/native-federation', project);
@@ -26,60 +27,79 @@ export const getChecksum = (
2627

2728
export const getCachedMetadata = (
2829
pathToCache: string,
30+
file: string,
2931
checksum: string
30-
): SharedInfo[] => {
31-
const metadataFile = path.join(pathToCache, 'metadata.json');
32-
if (!fs.existsSync(metadataFile)) return [];
32+
): SharedInfo[] | false => {
33+
const metadataFile = path.join(pathToCache, file);
34+
if (!fs.existsSync(metadataFile)) return false;
3335

34-
const cachedResult: { checksum: string; externals: SharedInfo[] } =
35-
JSON.parse(fs.readFileSync(metadataFile, 'utf-8'));
36-
if (cachedResult.checksum !== checksum) return [];
36+
const cachedResult: {
37+
checksum: string;
38+
externals: SharedInfo[];
39+
files: string[];
40+
} = JSON.parse(fs.readFileSync(metadataFile, 'utf-8'));
41+
if (cachedResult.checksum !== checksum) return false;
3742
return cachedResult.externals;
3843
};
3944

4045
export const storeCachedMetadata = (
4146
pathToCache: string,
42-
checksum: string,
43-
externals: SharedInfo[]
47+
file: string,
48+
payload: { checksum: string; externals: SharedInfo[]; files: string[] }
4449
) => {
4550
fs.writeFileSync(
46-
path.join(pathToCache, 'metadata.json'),
47-
JSON.stringify({ checksum, externals }, undefined, 2),
51+
path.join(pathToCache, file),
52+
JSON.stringify(payload, undefined, 2),
4853
'utf-8'
4954
);
5055
};
5156

5257
export const copyCacheToDist = (
5358
pathToCache: string,
59+
file: string,
5460
fullOutputPath: string
5561
) => {
56-
fs.readdirSync(pathToCache).forEach((file) => {
57-
if (file === 'metadata.json') return;
62+
const metadataFile = path.join(pathToCache, file);
63+
if (!fs.existsSync(metadataFile))
64+
throw new Error(
65+
'Error copying artifacts to dist, metadata file could not be found.'
66+
);
67+
68+
const cachedResult: {
69+
checksum: string;
70+
externals: SharedInfo[];
71+
files: string[];
72+
} = JSON.parse(fs.readFileSync(metadataFile, 'utf-8'));
73+
74+
fs.mkdirSync(path.dirname(fullOutputPath), { recursive: true });
75+
76+
cachedResult.files.forEach((file) => {
5877
const cachedFile = path.join(pathToCache, file);
5978
const distFileName = path.join(fullOutputPath, file);
6079

6180
if (fs.existsSync(cachedFile)) {
6281
fs.copyFileSync(cachedFile, distFileName);
6382
}
64-
console.log(file);
6583
});
66-
fs.mkdirSync(path.dirname(fullOutputPath), { recursive: true });
6784
};
6885

69-
export const purgeCacheFolder = (pathToCache: string) => {
70-
if (!fs.existsSync(pathToCache)) return;
71-
72-
try {
73-
fs.rmSync(pathToCache, { recursive: true, force: true });
74-
} catch (error) {
75-
// Fallback for older Node.js versions or if rmSync fails
76-
try {
77-
fs.rmdirSync(pathToCache, { recursive: true });
78-
} catch (fallbackError) {
79-
console.warn(
80-
`Failed to purge cache folder: ${pathToCache}`,
81-
fallbackError
82-
);
83-
}
86+
export const purgeCacheFolder = (pathToCache: string, file: string) => {
87+
const metadataFile = path.join(pathToCache, file);
88+
if (!fs.existsSync(metadataFile)) {
89+
logger.warn(
90+
`Could not purge cache, metadata file '${file}' could not be found.`
91+
);
8492
}
93+
94+
const cachedResult: {
95+
checksum: string;
96+
externals: SharedInfo[];
97+
files: string[];
98+
} = JSON.parse(fs.readFileSync(metadataFile, 'utf-8'));
99+
100+
cachedResult.files.forEach((file) => {
101+
const cachedFile = path.join(pathToCache, file);
102+
103+
if (fs.existsSync(cachedFile)) fs.unlinkSync(cachedFile);
104+
});
85105
};

0 commit comments

Comments
 (0)