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
5 changes: 5 additions & 0 deletions .changeset/mf-shared-array-deep-imports.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": patch
---

Read the `react-native` config from the array form of `shared` in `ModuleFederationPlugin`, so the generated `react-native/` and `@react-native/` deep imports inherit its `eager`, `import` and `version` values instead of falling back to the defaults.
13 changes: 10 additions & 3 deletions packages/repack/src/plugins/ModuleFederationPluginV1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,16 @@ export class ModuleFederationPluginV1 {
dependencies: SharedDependencies
): SharedConfig | string | undefined => {
if (Array.isArray(dependencies)) {
return dependencies.find((item) =>
typeof item === 'string' ? item === name : Boolean(item[name])
);
// object entries wrap the config under the dependency name,
// so unwrap it instead of returning the wrapper
for (const item of dependencies) {
if (typeof item === 'string') {
if (item === name) return item;
} else if (item[name]) {
return item[name];
}
}
return undefined;
}
return dependencies[name];
};
Expand Down
13 changes: 10 additions & 3 deletions packages/repack/src/plugins/ModuleFederationPluginV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,16 @@ export class ModuleFederationPluginV2 {
dependencies: MF.Shared
): MF.SharedConfig | string | undefined => {
if (Array.isArray(dependencies)) {
return dependencies.find((item) =>
typeof item === 'string' ? item === name : Boolean(item[name])
);
// object entries wrap the config under the dependency name,
// so unwrap it instead of returning the wrapper
for (const item of dependencies) {
if (typeof item === 'string') {
if (item === name) return item;
} else if (item[name]) {
return item[name];
}
}
return undefined;
}
return dependencies[name];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,39 @@ describe('ModuleFederationPlugin', () => {
expect(config.shared['@react-native/'].import).toBe(false);
});

it('should determine eager based on shared react-native config in array', () => {
new ModuleFederationPluginV1({
name: 'test',
shared: [
{ react: { singleton: true, eager: true } },
{
'react-native': {
singleton: true,
eager: false,
requiredVersion: '0.76.0',
},
},
],
}).apply(mockCompiler);

const config = mockPlugin.mock.calls[0][0];
expect(config.shared[2]['react-native/'].eager).toBe(false);
expect(config.shared[3]['@react-native/'].eager).toBe(false);
expect(config.shared[2]['react-native/'].requiredVersion).toBe('0.76.0');
expect(config.shared[3]['@react-native/'].requiredVersion).toBe('0.76.0');
});

it('should propagate import=false to deep imports in array', () => {
new ModuleFederationPluginV1({
name: 'test',
shared: [{ 'react-native': { singleton: true, import: false } }],
}).apply(mockCompiler);

const config = mockPlugin.mock.calls[0][0];
expect(config.shared[1]['react-native/'].import).toBe(false);
expect(config.shared[2]['@react-native/'].import).toBe(false);
});

it('should set default federated entry filename', () => {
new ModuleFederationPluginV1({
name: 'test',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,31 @@ describe('ModuleFederationPlugin', () => {
expect(config.shared['@react-native/'].import).toBe(false);
});

it('should determine eager based on shared react-native config in array', () => {
new ModuleFederationPluginV2({
name: 'test',
shared: [
{ react: { singleton: true, eager: true } },
{ 'react-native': { singleton: true, eager: false } },
],
}).apply(mockCompiler);

const config = mockPlugin.mock.calls[0][0];
expect(config.shared[2]['react-native/'].eager).toBe(false);
expect(config.shared[3]['@react-native/'].eager).toBe(false);
});

it('should propagate import=false to deep imports in array', () => {
new ModuleFederationPluginV2({
name: 'test',
shared: [{ 'react-native': { singleton: true, import: false } }],
}).apply(mockCompiler);

const config = mockPlugin.mock.calls[0][0];
expect(config.shared[1]['react-native/'].import).toBe(false);
expect(config.shared[2]['@react-native/'].import).toBe(false);
});

it('should add CorePlugin & ResolverPlugin to runtime plugins by default', () => {
new ModuleFederationPluginV2({ name: 'test' }).apply(mockCompiler);

Expand Down