Skip to content

Commit 0c375f7

Browse files
committed
fix(mf)!: Honour the skip list for sharedMappings
`Array.prototype.filter` returns a new array. The result was discarded, so the call was a no-op and sharedMappings reached mappings.register() unfiltered. Assign it back. BREAKING CHANGE: a package that is both listed in `sharedMappings` and on the skip list is no longer mapped or shared. Affected names are the ones assembled into `skip`: tslib, zone.js, @angular-architects/module-federation, @angular-architects/module-federation-runtime, the three @softarc/* entries, @angular/router/upgrade, @angular/common/upgrade, and anything in the caller's own `skip` option. In practice these are not things people put in sharedMappings, which exists for monorepo libraries resolved through tsconfig `paths`, but a config relying on the old behaviour will silently stop sharing that package. The skip list is still only consulted for an explicit `sharedMappings` array. Omitting it maps every non-wildcard tsconfig path, skip-listed or not; the new spec pins that asymmetry rather than changing it.
1 parent 72bb15e commit 0c375f7

3 files changed

Lines changed: 108 additions & 2 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"paths": {
4+
"@angular-architects/module-federation": ["mf-runtime/src/index.ts"],
5+
"tslib": ["tslib/src/index.ts"],
6+
"@angular/router/upgrade": ["router-upgrade/src/index.ts"],
7+
"my-lib": ["my-lib/src/index.ts"],
8+
"opt-out-lib": ["opt-out-lib/src/index.ts"]
9+
}
10+
}
11+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { join } from 'path';
2+
3+
// findRootTsConfigJson() walks up from cwd() to the real workspace tsconfig.
4+
// Point it at a fixture instead so the mappings under test are fixed.
5+
jest.mock('./share-utils', () => ({
6+
...jest.requireActual('./share-utils'),
7+
findRootTsConfigJson: jest.fn(),
8+
}));
9+
10+
import { findRootTsConfigJson } from './share-utils';
11+
import { withModuleFederationPlugin } from './with-mf-plugin';
12+
13+
const FIXTURE_TSCONFIG = join(__dirname, '__fixtures__/tsconfig.paths.json');
14+
15+
beforeEach(() => {
16+
(findRootTsConfigJson as jest.Mock).mockReturnValue(FIXTURE_TSCONFIG);
17+
});
18+
19+
// `shared: {}` keeps shareAll() — which reads the real root package.json — out
20+
// of these tests. The sharedMappings descriptors are merged into it either way.
21+
function build(config: Record<string, unknown>) {
22+
// withModuleFederationPlugin mutates the config it is handed, merging the
23+
// mapping descriptors into `shared` before passing it to the webpack plugin.
24+
const mfConfig: Record<string, unknown> = { shared: {}, ...config };
25+
const result = withModuleFederationPlugin(mfConfig);
26+
27+
return {
28+
aliases: Object.keys(result.resolve.alias),
29+
shared: Object.keys(mfConfig['shared']),
30+
};
31+
}
32+
33+
describe('withModuleFederationPlugin sharedMappings', () => {
34+
it('maps a library that is not skip-listed', () => {
35+
const { aliases, shared } = build({ sharedMappings: ['my-lib'] });
36+
37+
expect(aliases).toEqual(['my-lib']);
38+
expect(shared).toEqual(['my-lib']);
39+
});
40+
41+
it('drops entries on DEFAULT_SKIP_LIST', () => {
42+
const { aliases, shared } = build({
43+
sharedMappings: [
44+
'@angular-architects/module-federation',
45+
'tslib',
46+
'my-lib',
47+
],
48+
});
49+
50+
expect(aliases).toEqual(['my-lib']);
51+
expect(shared).toEqual(['my-lib']);
52+
});
53+
54+
it('drops entries on DEFAULT_SECONDARIES_SKIP_LIST', () => {
55+
const { aliases, shared } = build({
56+
sharedMappings: ['@angular/router/upgrade', 'my-lib'],
57+
});
58+
59+
expect(aliases).toEqual(['my-lib']);
60+
expect(shared).toEqual(['my-lib']);
61+
});
62+
63+
it('drops entries named in the caller-supplied skip option', () => {
64+
const { aliases, shared } = build({
65+
sharedMappings: ['opt-out-lib', 'my-lib'],
66+
skip: ['opt-out-lib'],
67+
});
68+
69+
expect(aliases).toEqual(['my-lib']);
70+
expect(shared).toEqual(['my-lib']);
71+
});
72+
73+
it('maps nothing when every entry is skipped', () => {
74+
// An empty array must not be mistaken for "no sharedMappings given", which
75+
// is what turns on the map-every-tsconfig-path behaviour below.
76+
const { aliases, shared } = build({ sharedMappings: ['tslib'] });
77+
78+
expect(aliases).toEqual([]);
79+
expect(shared).toEqual([]);
80+
});
81+
82+
it('maps every tsconfig path when sharedMappings is omitted', () => {
83+
// Pre-existing asymmetry: the skip list is only consulted for an explicit
84+
// sharedMappings array, so this path still maps skip-listed keys.
85+
const { aliases } = build({});
86+
87+
expect(aliases).toEqual([
88+
'@angular-architects/module-federation',
89+
'tslib',
90+
'@angular/router/upgrade',
91+
'my-lib',
92+
'opt-out-lib',
93+
]);
94+
});
95+
});

libs/mf/src/utils/with-mf-plugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { ModifyEntryPlugin } from './modify-entry-plugin';
1010
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
1111

1212
export function withModuleFederationPlugin(config: unknown) {
13-
const sharedMappings = config['sharedMappings'];
13+
let sharedMappings = config['sharedMappings'];
1414
delete config['sharedMappings'];
1515

1616
const skip = [
@@ -22,7 +22,7 @@ export function withModuleFederationPlugin(config: unknown) {
2222
delete config['skip'];
2323

2424
if (sharedMappings) {
25-
sharedMappings.filter((m) => !skip.includes(m));
25+
sharedMappings = sharedMappings.filter((m) => !skip.includes(m));
2626
}
2727

2828
const mappings = new SharedMappings();

0 commit comments

Comments
 (0)