Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion examples/module-federation/mf-host/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@module-federation/rsbuild-plugin": "^0.0.2",
"@module-federation/rsbuild-plugin": "^0.6.14",
"@rsbuild/core": "~1.0.16",
"@rsbuild/plugin-react": "^1.0.5",
"@types/react": "^18.3.11",
Expand Down
2 changes: 2 additions & 0 deletions examples/module-federation/mf-host/rsbuild.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export default defineConfig({
singleton: true,
},
},
// Enable this when the output of Rslib is build under 'production' mode, while the host app is 'development'.
// Reference: https://lib.rsbuild.dev/guide/advanced/module-federation#faqs
shareStrategy: 'loaded-first',
}),
],
Expand Down
31 changes: 31 additions & 0 deletions examples/module-federation/mf-react-component/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { dirname, join } from 'node:path';
import type { StorybookConfig } from 'storybook-react-rsbuild';

/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value: string): any {
return dirname(require.resolve(join(value, 'package.json')));
}

const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
framework: {
name: getAbsolutePath('storybook-react-rsbuild'),
options: {},
},
addons: [
{
name: '@module-federation/storybook-addon/dist/preset.js',
options: {
remotes: {
'rslib-module':
'rslib-module@http://localhost:3001/mf/mf-manifest.json',
},
},
},
],
};

export default config;
28 changes: 28 additions & 0 deletions examples/module-federation/mf-react-component/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# @examples/mf-react-component

This example demonstrates how to use Rslib to build a simple Module Federation React component.

### Usage

Dev MF module

start remote module which is loaded by rslib module

```
cd examples/mf-remote && pnpm dev
```

start rslib module and storybook

```
pnpm storybook
```

Build

```
pnpm build
```

Build and Serve dist

```
pnpm serve
```
11 changes: 8 additions & 3 deletions examples/module-federation/mf-react-component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@
"types": "./dist/cjs/index.d.ts",
"scripts": {
"build": "rslib build",
"serve": "pnpm build && http-server -p 3001 ./dist/ --cors"
"dev": "rslib dev:mf",
"serve": "pnpm build & http-server -p 3001 ./dist/ --cors",
"storybook": "pnpm dev & storybook dev -p 6006"
},
"devDependencies": {
"@module-federation/enhanced": "^0.6.11",
"@module-federation/rsbuild-plugin": "^0.0.2",
"@module-federation/rsbuild-plugin": "^0.6.14",
"@module-federation/storybook-addon": "0.0.0-next-20241029093536",
"@rsbuild/plugin-react": "^1.0.5",
"@rslib/core": "workspace:*",
"@types/react": "^18.3.11",
"http-server": "^14.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"storybook": "^8.3.6",
"storybook-react-rsbuild": "^0.1.1"
},
"peerDependencies": {
"react": "*"
Expand Down
7 changes: 7 additions & 0 deletions examples/module-federation/mf-react-component/rslib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ export default defineConfig({
},
assetPrefix: 'http://localhost:3001/mf',
},
dev: {
assetPrefix: 'http://localhost:3001/mf',
},
// just for dev
server: {
port: 3001,
},
plugins: [
pluginModuleFederation({
name: 'rslib_provider',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { Counter } from 'rslib-module';

const Component = () => <Counter />;

export default {
title: 'App Component',
component: Component,
};

export const Primary = {};
8 changes: 6 additions & 2 deletions examples/module-federation/mf-react-component/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"compilerOptions": {
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
"*": ["./@mf-types/*"]
}
},
"include": ["src/**/*"]
"include": ["src/**/*", "src/stories"]
}
2 changes: 1 addition & 1 deletion examples/module-federation/mf-remote/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"react-dom": "^18.3.1"
},
"devDependencies": {
"@module-federation/rsbuild-plugin": "^0.0.2",
"@module-federation/rsbuild-plugin": "^0.6.14",
"@rsbuild/core": "~1.0.16",
"@rsbuild/plugin-react": "^1.0.5",
"@types/react": "^18.3.11",
Expand Down
20 changes: 19 additions & 1 deletion packages/core/src/cli/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { RsbuildMode } from '@rsbuild/core';
import { type Command, program } from 'commander';
import { build } from '../build';
import { initRsbuild, loadConfig } from '../config';
import { dev } from '../dev';
import { logger } from '../utils/logger';

export type CommonOptions = {
Expand Down Expand Up @@ -36,8 +37,9 @@ export function runCli(): void {

const buildCommand = program.command('build');
const inspectCommand = program.command('inspect');
const devCommand = program.command('dev:mf');

[buildCommand, inspectCommand].forEach(applyCommonOptions);
[buildCommand, inspectCommand, devCommand].forEach(applyCommonOptions);

buildCommand
.option('-w --watch', 'turn on watch mode, watch for changes and rebuild')
Expand Down Expand Up @@ -82,5 +84,21 @@ export function runCli(): void {
}
});

devCommand
.description(`dev format: 'mf' library`)
.action(async (options: CommonOptions) => {
try {
const rslibConfig = await loadConfig({
path: options.config,
envMode: options.envMode,
});
await dev(rslibConfig);
} catch (err) {
logger.error('Failed to dev.');
logger.error(err);
process.exit(1);
}
});

program.parse();
}
37 changes: 37 additions & 0 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1202,3 +1202,40 @@ export async function initRsbuild(
},
});
}

export async function initDevMFRsbuild(
rslibConfig: RslibConfig,
): Promise<RsbuildInstance> {
const rsbuildConfigObject = await composeCreateRsbuildConfig(rslibConfig);
const mfRsbuildConfig = rsbuildConfigObject.find(
(config) => config.format === 'mf',
);
if (!mfRsbuildConfig) {
logger.warn(
`${color.green('format: "mf"')} should be added into rslib config.
Check the documentation (https://lib.rsbuild.dev/guide/advanced/module-federation) to get started with "mf" format.`,
);
process.exit(1);
}
mfRsbuildConfig.config = changeEnvForDev(mfRsbuildConfig.config);

return createRsbuild({
rsbuildConfig: mfRsbuildConfig.config,
});
}

function changeEnvForDev(rsbuildConfig: RsbuildConfig) {
return mergeRsbuildConfig(rsbuildConfig, {
mode: 'development',
dev: {
writeToDisk: true,
},
tools: {
rspack: {
optimization: {
nodeEnv: 'development',
},
},
},
});
}
12 changes: 12 additions & 0 deletions packages/core/src/dev.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { initDevMFRsbuild } from './config';

import type { RsbuildInstance } from '@rsbuild/core';
import type { RslibConfig } from './types/config';

export async function dev(config: RslibConfig): Promise<RsbuildInstance> {
const rsbuildInstance = await initDevMFRsbuild(config);

await rsbuildInstance.startDevServer();

return rsbuildInstance;
}
Loading