Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 12 additions & 0 deletions e2e/cases/module-federation/v1-remote-only/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { expect, rspackTest } from '@e2e/helper';

rspackTest(
'should start remove-only MF app in dev',
async ({ devOnly, logHelper }) => {
await expect(devOnly()).resolves.toBeTruthy();
},
);

rspackTest('should build remove-only MF app', async ({ build }) => {
Comment thread
chenjiahan marked this conversation as resolved.
Outdated
Comment thread
chenjiahan marked this conversation as resolved.
Outdated
await expect(build()).resolves.toBeTruthy();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Rspack } from '@rsbuild/core';

export const mfConfig: Rspack.ModuleFederationPluginOptions = {
name: 'remote',
exposes: {
'./Button': './src/Button',
},
filename: 'remoteEntry.js',
shared: {
react: {
singleton: true,
requiredVersion: '^19.0.0',
},
'react-dom': {
singleton: true,
requiredVersion: '^19.0.0',
},
},
};
10 changes: 10 additions & 0 deletions e2e/cases/module-federation/v1-remote-only/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import { mfConfig } from './moduleFederation.config';

export default defineConfig({
plugins: [pluginReact()],
moduleFederation: {
options: mfConfig,
},
});
5 changes: 5 additions & 0 deletions e2e/cases/module-federation/v1-remote-only/src/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const Button = () => (
<button type="button" id="button">
Button
</button>
);
40 changes: 30 additions & 10 deletions packages/core/src/plugins/entry.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { castArray, color, createVirtualModule } from '../helpers';
import type { RsbuildEntryDescription, RsbuildPlugin } from '../types';
import { castArray, color, createVirtualModule, isObject } from '../helpers';
import type { RsbuildEntryDescription, RsbuildPlugin, Rspack } from '../types';

export const pluginEntry = (): RsbuildPlugin => ({
name: 'rsbuild:entry',
Expand Down Expand Up @@ -32,16 +32,36 @@ export const pluginEntry = (): RsbuildPlugin => ({
}
});

// Check missing entry config
api.onBeforeCreateCompiler(({ bundlerConfigs }) => {
if (bundlerConfigs.every((config) => !config.entry)) {
throw new Error(
`${color.dim('[rsbuild:config]')} Could not find any entry module, please make sure that ${color.yellow(
'src/index.(ts|js|tsx|jsx|mts|cts|mjs|cjs)',
)} exists, or customize entry through the ${color.yellow(
'source.entry',
)} configuration.`,
);
const hasEntry = bundlerConfigs.some((config) => config.entry);
if (hasEntry) {
return;
}

const isModuleFederationPlugin = (plugin: Rspack.Plugin) =>
isObject(plugin) &&
plugin.constructor.name === 'ModuleFederationPlugin';

const hasModuleFederation = bundlerConfigs.some(({ plugins }) =>
plugins?.some(isModuleFederationPlugin),
);

// Allow entry to be left empty when module federation is enabled
if (hasModuleFederation) {
bundlerConfigs.forEach((config) => {
config.entry = {};
});
return;
}

throw new Error(
`${color.dim('[rsbuild:config]')} Could not find any entry module, please make sure that ${color.yellow(
'src/index.(ts|js|tsx|jsx|mts|cts|mjs|cjs)',
)} exists, or customize entry through the ${color.yellow(
'source.entry',
)} configuration.`,
);
});
},
});
Loading