Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions libs/mf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,50 @@ shared: share({
})
```

### glob exports

Since v21 it's also possible to resolve Glob exports by enabling the `globResolve` property:

```typescript
shared: share({
"@primeng/themes/aura": {
singleton: true,
strictVersion: true,
requiredVersion: "auto",
includeSecondaries: {resolveGlob: true}
},
[...]
})
```

This is disabled by default since it will create a bundle of every valid exported file it finds, **Only use this feature in combination with `ignoreUnusedDeps` flag**. If you want to specifically skip certain parts of the glob export, you can also use the wildcard in the skip section:

```typescript
shared: share({
"@primeng/themes/aura": {
singleton: true,
strictVersion: true,
requiredVersion: "auto",
includeSecondaries: {skip: "@primeuix/themes/aura/*", resolveGlob: true}
},
[...]
})
```

Finally, it's also possible to break out of the "removeUnusedDep" for a specific external if desired, for example when sharing a whole suite of external modules. This can be handy when you want to avoid the chance of cross-version secondary entrypoints being used by the different micro frontends. E.g. mfe1 uses @angular/core v20.1.0 and mfe2 uses @angular/core/rxjs-interop v20.0.8, then you might want to use consistent use of v20.1.0 so rxjs-interop should be exported by mfe1. The "shareAll" prop allows you to enforce this:

```typescript
shared: share({
"@angular/core": {
singleton: true,
strictVersion: true,
requiredVersion: "auto",
includeSecondaries: {shareAll: true}
},
[...]
})
```

#### shareAll

The `shareAll` helper shares all your dependencies defined in your `package.json`. The `package.json` is look up as described above:
Expand Down
12 changes: 11 additions & 1 deletion libs/native-federation-core/src/lib/config/share-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export const DEFAULT_SECONDARIES_SKIP_LIST = [
'@angular/common/upgrade',
];

type IncludeSecondariesOptions = { skip: string | string[] } | boolean;
type IncludeSecondariesOptions =
| { skip: string | string[]; resolveGlob?: boolean; shareAll?: boolean }
| boolean;
type CustomSharedConfig = SharedConfig & {
includeSecondaries?: IncludeSecondariesOptions;
};
Expand Down Expand Up @@ -159,12 +161,14 @@ function getSecondaries(
): Record<string, SharedConfig> | null {
let exclude = [...DEFAULT_SECONDARIES_SKIP_LIST];

let resolveGlob = false;
if (typeof includeSecondaries === 'object') {
if (Array.isArray(includeSecondaries.skip)) {
exclude = includeSecondaries.skip;
} else if (typeof includeSecondaries.skip === 'string') {
exclude = [includeSecondaries.skip];
}
resolveGlob = !!includeSecondaries.resolveGlob;
}

// const libPath = path.join(path.dirname(packagePath), 'node_modules', key);
Expand All @@ -179,6 +183,7 @@ function getSecondaries(
exclude,
shareObject,
preparedSkipList,
resolveGlob,
);
if (configured) {
return configured;
Expand All @@ -200,6 +205,7 @@ function readConfiguredSecondaries(
exclude: string[],
shareObject: SharedConfig,
preparedSkipList: PreparedSkipList,
resolveGlob: boolean,
): Record<string, SharedConfig> | null {
const libPackageJson = path.join(libPath, 'package.json');

Expand Down Expand Up @@ -267,6 +273,7 @@ function readConfiguredSecondaries(
secondaryName,
entry,
{ discovered: discoveredFiles, skip: exclude },
resolveGlob,
);
items.forEach((e) =>
discoveredFiles.add(typeof e === 'string' ? e : e.value),
Expand Down Expand Up @@ -300,9 +307,11 @@ function resolveSecondaries(
secondaryName: string,
entry: string,
excludes: { discovered: Set<string>; skip: string[] },
resolveGlob: boolean,
): Array<string | KeyValuePair> {
let items: Array<string | KeyValuePair> = [];
if (key.includes('*')) {
if (!resolveGlob) return items;
const expanded = resolveWildcardKeys(key, entry, libPath);
items = expanded
.map((e) => ({
Expand Down Expand Up @@ -570,6 +579,7 @@ export function share(
if (shareObject.includeSecondaries) {
includeSecondaries = shareObject.includeSecondaries;
delete shareObject.includeSecondaries;
if (includeSecondaries?.shareAll) shareObject.includeSecondaries = true;
}

result[key] = shareObject;
Expand Down
2 changes: 1 addition & 1 deletion libs/native-federation-core/src/lib/core/bundle-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export async function bundleShared(
platform: 'browser' | 'node' = 'browser',
cacheOptions: { pathToCache: string; bundleName: string },
): Promise<Array<SharedInfo>> {
const checksum = getChecksum(sharedBundles);
const checksum = getChecksum(sharedBundles, fedOptions.dev ? '1' : '0');
const folder = fedOptions.packageJson
? path.dirname(fedOptions.packageJson)
: fedOptions.workspaceRoot;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const DEFAULT_SKIP_LIST: SkipList = [
'@angular/localize',
'@angular/localize/init',
'@angular/localize/tools',
(pkg) => pkg.startsWith('rxjs/internal'),
// '@angular/platform-server',
// '@angular/platform-server/init',
// '@angular/ssr',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export async function loadFederationConfig(
throw new Error('Expected ' + fullConfigPath);
}

const config = (await import(fullConfigPath)) as NormalizedFederationConfig;
const config = (await import(fullConfigPath))
?.default as NormalizedFederationConfig;

if (config.features.ignoreUnusedDeps && !fedOptions.entryPoint) {
throw new Error(
Expand Down
15 changes: 6 additions & 9 deletions libs/native-federation-core/src/lib/core/remove-unused-deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,12 @@ function filterShared(
config: NormalizedFederationConfig,
usedPackageNamesWithTransient: Set<string>,
) {
const filteredSharedNames = Object.keys(config.shared).filter((shared) =>
usedPackageNamesWithTransient.has(shared),
);

const filteredShared = filteredSharedNames.reduce(
(acc, curr) => ({ ...acc, [curr]: config.shared[curr] }),
{},
);
return filteredShared;
return Object.entries(config.shared)
.filter(
([shared, meta]) =>
!!meta.includeSecondaries || usedPackageNamesWithTransient.has(shared),
)
.reduce((acc, [shared, meta]) => ({ ...acc, [shared]: meta }), {});
}

function findUsedDeps(
Expand Down
6 changes: 5 additions & 1 deletion libs/native-federation-core/src/lib/utils/bundle-caching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const getFilename = (title: string) => {

export const getChecksum = (
shared: Record<string, NormalizedSharedConfig>,
dev: '1' | '0',
): string => {
const denseExternals = Object.keys(shared)
.sort()
Expand All @@ -26,7 +27,10 @@ export const getChecksum = (
);
}, 'deps');

return crypto.createHash('sha256').update(denseExternals).digest('hex');
return crypto
.createHash('sha256')
.update(denseExternals + `:dev=${dev}`)
.digest('hex');
};

export const cacheEntry = (pathToCache: string, fileName: string) => ({
Expand Down
Loading