Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"@module-federation/modern-js",
"@module-federation/retry-plugin",
"@module-federation/data-prefetch",
"@module-federation/rsbuild-plugin"
"@module-federation/rsbuild-plugin",
"@module-federation/storybook-addon"
]
],
"ignorePatterns": ["^alpha|^beta"],
Expand Down
4 changes: 4 additions & 0 deletions .changeset/mean-jokes-remember.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
'@module-federation/storybook-addon': patch
---
feat: support storybook dev remote app in rsbuild(rslib) project [#3131](https://github.com/module-federation/core/pull/3131)
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ migrations.json
packages/**/dist
apps/**/dist

**/@mf-types
**/@mf-types/**
**/cypress/downloads

Expand All @@ -67,3 +66,6 @@ packages/enhanced/test/js
**/dist-test/**
**/cypress/downloads
/packages/data-prefetch/jest/cache/

# storybook cases
!apps/rslib-module/@mf-types/**
32 changes: 32 additions & 0 deletions apps/rslib-module/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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/preset.js',
options: {
remotes: {
'rslib-module':
'rslib-module@http://localhost:3000/mf/mf-manifest.json',
},
shareStrategy: 'loaded-first',
},
},
],
};

export default config;
34 changes: 34 additions & 0 deletions apps/rslib-module/@mf-types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type {
PackageType as PackageType_0,
RemoteKeys as RemoteKeys_0,
} from './rslib-module/apis.d.ts';
declare module '@module-federation/runtime' {
type RemoteKeys = RemoteKeys_0;
type PackageType<T, Y = any> = T extends RemoteKeys_0 ? PackageType_0<T> : Y;
export function loadRemote<T extends RemoteKeys, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
export function loadRemote<T extends string, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
}
declare module '@module-federation/enhanced/runtime' {
type RemoteKeys = RemoteKeys_0;
type PackageType<T, Y = any> = T extends RemoteKeys_0 ? PackageType_0<T> : Y;
export function loadRemote<T extends RemoteKeys, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
export function loadRemote<T extends string, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
}
declare module '@module-federation/runtime-tools' {
type RemoteKeys = RemoteKeys_0;
type PackageType<T, Y = any> = T extends RemoteKeys_0 ? PackageType_0<T> : Y;
export function loadRemote<T extends RemoteKeys, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
export function loadRemote<T extends string, Y>(
packageName: T,
): Promise<PackageType<T, Y>>;
}
4 changes: 4 additions & 0 deletions apps/rslib-module/@mf-types/rslib-module/apis.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type RemoteKeys = 'rslib-module';
type PackageType<T> = T extends 'rslib-module'
? typeof import('rslib-module')
: any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface CounterButtonProps {
onClick: () => void;
label: string;
[key: string]: any;
}
export declare const CounterButton: React.FC<CounterButtonProps>;
export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export declare const Counter: React.FC;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export declare const useCounter: (initialValue?: number) => {
count: number;
increment: () => void;
decrement: () => void;
};
2 changes: 2 additions & 0 deletions apps/rslib-module/@mf-types/rslib-module/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './compiled-types/index';
export { default } from './compiled-types/index';
25 changes: 25 additions & 0 deletions apps/rslib-module/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# @examples/mf-react-component

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

### Command

Build package

```
nx build rslib-module
```

Serve package

```
nx serve rslib-module
```

Dev package

```
nx serve rslib-module & nx storybook rslib-module
```

visit http://localhost:6006
35 changes: 35 additions & 0 deletions apps/rslib-module/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "@examples/mf-react-component",
"private": true,
"exports": {
".": {
"import": "./dist/esm/index.mjs",
"require": "./dist/cjs/index.js",
"types": "./dist/cjs/index.d.ts"
}
},
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.mjs",
"types": "./dist/cjs/index.d.ts",
"scripts": {
"build": "rslib build",
"serve": "pnpm build && http-server -p 3000 ./dist/ --cors",
"storybook": "storybook dev -p 6006"
},
"devDependencies": {
"storybook": "^8.3.6",
"storybook-react-rsbuild": "^0.1.1",
"@module-federation/enhanced": "workspace:*",
"@module-federation/rsbuild-plugin": "workspace:*",
"@module-federation/storybook-addon": "workspace:*",
"@rsbuild/plugin-react": "^1.0.5",
"@rslib/core": "^0.0.14",
"@types/react": "^18.3.11",
"http-server": "^14.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"peerDependencies": {
"react": "*"
}
}
33 changes: 33 additions & 0 deletions apps/rslib-module/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "rslib-module",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/rslib-module/src",
"projectType": "library",
"tags": ["type:app"],
"targets": {
"build": {
"executor": "nx:run-commands",
"options": {
"commands": ["npm run build --prefix apps/rslib-module"]
}
},
"serve": {
"executor": "nx:run-commands",
"options": {
"commands": ["npm run serve --prefix apps/rslib-module"]
},
"dependsOn": [
{
"target": "build",
"dependencies": true
}
]
},
"storybook": {
"executor": "nx:run-commands",
"options": {
"commands": ["npm run storybook --prefix apps/rslib-module"]
}
}
}
}
60 changes: 60 additions & 0 deletions apps/rslib-module/rslib.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
import { pluginReact } from '@rsbuild/plugin-react';
import { defineConfig } from '@rslib/core';

const shared = {
dts: {
bundle: false,
},
};

export default defineConfig({
lib: [
{
...shared,
format: 'esm',
output: {
distPath: {
root: './dist/esm',
},
},
},
{
...shared,
format: 'cjs',
output: {
distPath: {
root: './dist/cjs',
},
},
},
{
...shared,
format: 'mf',
output: {
distPath: {
root: './dist/mf',
},
assetPrefix: 'http://localhost:3000/mf',
minify: true,
},
plugins: [
pluginModuleFederation({
name: 'rslib_provider',
exposes: {
'.': './src/index.tsx',
},
shared: {
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
}),
],
},
],
plugins: [pluginReact()],
});
15 changes: 15 additions & 0 deletions apps/rslib-module/src/CounterButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface CounterButtonProps {
onClick: () => void;
label: string;
[key: string]: any;
}

export const CounterButton: React.FC<CounterButtonProps> = ({
onClick,
label,
...props
}) => (
<button type="button" onClick={onClick} {...props}>
{label}
</button>
);
17 changes: 17 additions & 0 deletions apps/rslib-module/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { CounterButton } from './CounterButton';
import { useCounter } from './useCounter';

export const Counter: React.FC = () => {
const { count, increment, decrement } = useCounter();

return (
<div>
<h2>
<span id="mf-e2e-lib-title">Counter From Rslib MF Format: </span>
<span id="mf-e2e-lib-content">{count}</span>
</h2>
<CounterButton id="mf-e2e-lib-decrease" onClick={decrement} label="-" />
<CounterButton id="mf-e2e-lib-increase" onClick={increment} label="+" />
</div>
);
};
11 changes: 11 additions & 0 deletions apps/rslib-module/src/stories/index.stories.tsx
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 = {};
10 changes: 10 additions & 0 deletions apps/rslib-module/src/useCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useState } from 'react';

export const useCounter = (initialValue = 0) => {
const [count, setCount] = useState(initialValue);

const increment = () => setCount((prev) => prev + 1);
const decrement = () => setCount((prev) => prev - 1);

return { count, increment, decrement };
};
12 changes: 12 additions & 0 deletions apps/rslib-module/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"paths": {
"*": ["./@mf-types/*"]
}
},
"include": ["src/**/*", "src/stories"]
}
34 changes: 34 additions & 0 deletions packages/storybook-addon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,40 @@ module.exports = storybookConfig;

---

### Rsbuild App or Rslib Module

```
import { dirname, join } from 'node:path';
import type { StorybookConfig } from 'storybook-react-rsbuild';

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/preset.js',
options: {
// add remote here and then you can load remote in your story
remotes: {
'rslib-module':
'rslib-module@http://localhost:3000/mf/mf-manifest.json',
},
},
},
],
};

export default config;

```

### For the [NX](https://nx.dev/getting-started/intro) projects:

Replace NX utils `withModuleFederation` in `webpack.config.js` with our utils `withModuleFederation`.
Expand Down
Loading
Loading