diff --git a/MIGRATION.md b/MIGRATION.md
index baf36606ea2d..e60f5779db7c 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -32,6 +32,7 @@
- [Next.js](#nextjs)
- [Require Next.js 13.5 and up](#require-nextjs-135-and-up)
- [Automatic SWC mode detection](#automatic-swc-mode-detection)
+ - [RSC config moved to React renderer](#rsc-config-moved-to-react-renderer)
- [Angular](#angular)
- [Require Angular 15 and up](#require-angular-15-and-up)
- [Svelte](#svelte)
@@ -69,17 +70,17 @@
- [Addon author changes](#addon-author-changes)
- [Removed `config` preset](#removed-config-preset-1)
- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)
- - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
- - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)
- - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated)
- - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop)
- - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react)
+ - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
+ - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated)
+ - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated)
+ - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop)
+ - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react)
- [From version 7.4.0 to 7.5.0](#from-version-740-to-750)
- - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)
- - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers)
+ - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)
+ - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers)
- [From version 7.0.0 to 7.2.0](#from-version-700-to-720)
- - [Addon API is more type-strict](#addon-api-is-more-type-strict)
- - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated)
+ - [Addon API is more type-strict](#addon-api-is-more-type-strict)
+ - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated)
- [From version 6.5.x to 7.0.0](#from-version-65x-to-700)
- [7.0 breaking changes](#70-breaking-changes)
- [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below)
@@ -731,6 +732,12 @@ Similar to how Next.js detects if SWC should be used, Storybook will follow more
- If you use Next.js 14 or higher and you don't have a .babelrc file, Storybook will use SWC to transpile your code.
- Even if you have a .babelrc file, Storybook will still use SWC to transpile your code if you set the experimental `experimental.forceSwcTransforms` flag to `true` in your `next.config.js`.
+##### RSC config moved to React renderer
+
+Storybook 7.6 introduced a new feature flag, `experimentalNextRSC`, to enable React Server Components in a Next.js project. It also introduced a parameter `nextjs.rsc` to selectively disable it on particular components or stories.
+
+These flags have been renamed to `experimentalRSC` and `react.rsc`, respectively. This is a breaking change to accommodate RSC support in other, non-Next.js frameworks. For now, `@storybook/nextjs` is the only framework that supports it, and does so experimentally.
+
#### Angular
##### Require Angular 15 and up
diff --git a/code/frameworks/nextjs/README.md b/code/frameworks/nextjs/README.md
index ab6a8fc9cad5..d1d234ab89fc 100644
--- a/code/frameworks/nextjs/README.md
+++ b/code/frameworks/nextjs/README.md
@@ -907,13 +907,13 @@ Storybook handles most [Typescript](https://www.typescriptlang.org/) configurati
If your app uses [React Server Components (RSC)](https://nextjs.org/docs/app/building-your-application/rendering/server-components), Storybook can render them in stories in the browser.
-To enable this set the `experimentalNextRSC` feature flag in your `.storybook/main.js` config:
+To enable this set the `experimentalRSC` feature flag in your `.storybook/main.js` config:
```js
// main.js
export default {
features: {
- experimentalNextRSC: true,
+ experimentalRSC: true,
},
};
```
diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json
index 052baf685f6c..5c7e73f7b8dc 100644
--- a/code/frameworks/nextjs/package.json
+++ b/code/frameworks/nextjs/package.json
@@ -42,7 +42,6 @@
"import": "./dist/font/webpack/loader/storybook-nextjs-font-loader.mjs"
},
"./dist/preview.mjs": "./dist/preview.mjs",
- "./dist/rsc/preview.mjs": "./dist/rsc/preview.mjs",
"./next-image-loader-stub.js": {
"types": "./dist/next-image-loader-stub.d.ts",
"require": "./dist/next-image-loader-stub.js",
@@ -164,7 +163,6 @@
"./src/images/next-legacy-image.tsx",
"./src/images/next-image.tsx",
"./src/font/webpack/loader/storybook-nextjs-font-loader.ts",
- "./src/rsc/preview.tsx",
"./src/rsc/server-only.ts",
"./src/swc/next-swc-loader-patch.ts"
],
diff --git a/code/frameworks/nextjs/src/preset.ts b/code/frameworks/nextjs/src/preset.ts
index d1bdb71527bf..4f54465d5c8a 100644
--- a/code/frameworks/nextjs/src/preset.ts
+++ b/code/frameworks/nextjs/src/preset.ts
@@ -76,9 +76,6 @@ export const previewAnnotations: PresetProperty<'previewAnnotations'> = (
) => {
const nextDir = dirname(require.resolve('@storybook/nextjs/package.json'));
const result = [...entry, join(nextDir, 'dist/preview.mjs')];
- if (features?.experimentalNextRSC) {
- result.unshift(join(nextDir, 'dist/rsc/preview.mjs'));
- }
return result;
};
@@ -169,7 +166,7 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
configureFastRefresh(baseConfig);
}
- if (options.features?.experimentalNextRSC) {
+ if (options.features?.experimentalRSC) {
configureRSC(baseConfig);
}
diff --git a/code/frameworks/nextjs/src/rsc/decorator.tsx b/code/frameworks/nextjs/src/rsc/decorator.tsx
deleted file mode 100644
index 73b7e7b4d817..000000000000
--- a/code/frameworks/nextjs/src/rsc/decorator.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import * as React from 'react';
-import type { StoryContext } from '@storybook/react';
-
-export const ServerComponentDecorator = (
- Story: React.FC,
- { parameters }: StoryContext
-): React.ReactNode =>
- parameters?.nextjs?.rsc ? (
-
-
-
- ) : (
-
- );
diff --git a/code/frameworks/nextjs/src/rsc/preview.tsx b/code/frameworks/nextjs/src/rsc/preview.tsx
deleted file mode 100644
index a26737ec1e06..000000000000
--- a/code/frameworks/nextjs/src/rsc/preview.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import type { Addon_DecoratorFunction } from '@storybook/types';
-import { ServerComponentDecorator } from './decorator';
-
-export const decorators: Addon_DecoratorFunction[] = [ServerComponentDecorator];
-
-export const parameters = {
- nextjs: {
- rsc: true,
- },
-};
diff --git a/code/lib/cli/src/sandbox-templates.ts b/code/lib/cli/src/sandbox-templates.ts
index d470e06e6ffe..e1395b81156f 100644
--- a/code/lib/cli/src/sandbox-templates.ts
+++ b/code/lib/cli/src/sandbox-templates.ts
@@ -124,7 +124,7 @@ const baseTemplates = {
},
modifications: {
mainConfig: {
- features: { experimentalNextRSC: true },
+ features: { experimentalRSC: true },
},
extraDependencies: ['server-only'],
},
@@ -141,7 +141,7 @@ const baseTemplates = {
},
modifications: {
mainConfig: {
- features: { experimentalNextRSC: true },
+ features: { experimentalRSC: true },
},
extraDependencies: ['server-only'],
},
@@ -158,7 +158,7 @@ const baseTemplates = {
},
modifications: {
mainConfig: {
- features: { experimentalNextRSC: true },
+ features: { experimentalRSC: true },
},
extraDependencies: ['server-only'],
},
@@ -175,7 +175,7 @@ const baseTemplates = {
},
modifications: {
mainConfig: {
- features: { experimentalNextRSC: true },
+ features: { experimentalRSC: true },
},
extraDependencies: ['server-only'],
},
diff --git a/code/lib/types/src/modules/core-common.ts b/code/lib/types/src/modules/core-common.ts
index ae6921115ec8..7a6bd8a99699 100644
--- a/code/lib/types/src/modules/core-common.ts
+++ b/code/lib/types/src/modules/core-common.ts
@@ -373,9 +373,9 @@ export interface StorybookConfigRaw {
disallowImplicitActionsInRenderV8?: boolean;
/**
- * Enable asynchronous component rendering in NextJS framework
+ * Enable asynchronous component rendering in React renderer
*/
- experimentalNextRSC?: boolean;
+ experimentalRSC?: boolean;
};
build?: TestBuildConfig;
diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json
index 71da45e75fa8..dd870207cd59 100644
--- a/code/renderers/react/package.json
+++ b/code/renderers/react/package.json
@@ -29,6 +29,7 @@
"./preset": "./preset.js",
"./dist/entry-preview.mjs": "./dist/entry-preview.mjs",
"./dist/entry-preview-docs.mjs": "./dist/entry-preview-docs.mjs",
+ "./dist/entry-preview-rsc.mjs": "./dist/entry-preview-rsc.mjs",
"./package.json": "./package.json"
},
"main": "dist/index.js",
@@ -64,6 +65,7 @@
"lodash": "^4.17.21",
"prop-types": "^15.7.2",
"react-element-to-jsx-string": "^15.0.0",
+ "semver": "^7.3.7",
"ts-dedent": "^2.0.0",
"type-fest": "~2.19",
"util-deprecate": "^1.0.2"
@@ -71,6 +73,7 @@
"devDependencies": {
"@storybook/test": "workspace:*",
"@types/babel-plugin-react-docgen": "^4",
+ "@types/semver": "^7.3.4",
"@types/util-deprecate": "^1.0.0",
"babel-plugin-react-docgen": "^4.2.1",
"expect-type": "^0.15.0",
@@ -97,7 +100,8 @@
"./src/index.ts",
"./src/preset.ts",
"./src/entry-preview.ts",
- "./src/entry-preview-docs.ts"
+ "./src/entry-preview-docs.ts",
+ "./src/entry-preview-rsc.tsx"
],
"platform": "browser"
},
diff --git a/code/renderers/react/src/entry-preview-rsc.tsx b/code/renderers/react/src/entry-preview-rsc.tsx
new file mode 100644
index 000000000000..96b04ab996ba
--- /dev/null
+++ b/code/renderers/react/src/entry-preview-rsc.tsx
@@ -0,0 +1,31 @@
+import * as React from 'react';
+import semver from 'semver';
+import type { Addon_DecoratorFunction } from '@storybook/types';
+import type { StoryContext } from './types';
+
+export const ServerComponentDecorator = (
+ Story: React.FC,
+ { parameters }: StoryContext
+): React.ReactNode => {
+ if (!parameters?.react?.rsc) return ;
+
+ const major = semver.major(React.version);
+ const minor = semver.minor(React.version);
+ if (major < 18 || (major === 18 && minor < 3)) {
+ throw new Error('React Server Components require React >= 18.3');
+ }
+
+ return (
+
+
+
+ );
+};
+
+export const decorators: Addon_DecoratorFunction[] = [ServerComponentDecorator];
+
+export const parameters = {
+ react: {
+ rsc: true,
+ },
+};
diff --git a/code/renderers/react/src/preset.ts b/code/renderers/react/src/preset.ts
index e9a5ac13ebf7..b7f374bd2790 100644
--- a/code/renderers/react/src/preset.ts
+++ b/code/renderers/react/src/preset.ts
@@ -17,7 +17,8 @@ export const previewAnnotations: PresetProperty<'previewAnnotations'> = async (
return result
.concat(input)
.concat([join(__dirname, 'entry-preview.mjs')])
- .concat(docsEnabled ? [join(__dirname, 'entry-preview-docs.mjs')] : []);
+ .concat(docsEnabled ? [join(__dirname, 'entry-preview-docs.mjs')] : [])
+ .concat(FEATURES?.experimentalRSC ? [join(__dirname, 'entry-preview-rsc.mjs')] : []);
};
/**
diff --git a/code/renderers/react/src/typings.d.ts b/code/renderers/react/src/typings.d.ts
index a5e002d064ee..1823ff6bd9ad 100644
--- a/code/renderers/react/src/typings.d.ts
+++ b/code/renderers/react/src/typings.d.ts
@@ -1,3 +1,4 @@
declare var STORYBOOK_ENV: 'react';
declare var FRAMEWORK_OPTIONS: any;
declare var LOGLEVEL: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent' | undefined;
+declare var FEATURES: import('@storybook/types').StorybookConfigRaw['features'];
diff --git a/code/yarn.lock b/code/yarn.lock
index 04e71212fdee..c589f2a7e3c1 100644
--- a/code/yarn.lock
+++ b/code/yarn.lock
@@ -6347,6 +6347,7 @@ __metadata:
"@types/escodegen": "npm:^0.0.6"
"@types/estree": "npm:^0.0.51"
"@types/node": "npm:^18.0.0"
+ "@types/semver": "npm:^7.3.4"
"@types/util-deprecate": "npm:^1.0.0"
acorn: "npm:^7.4.1"
acorn-jsx: "npm:^5.3.1"
@@ -6359,6 +6360,7 @@ __metadata:
prop-types: "npm:^15.7.2"
react-element-to-jsx-string: "npm:^15.0.0"
require-from-string: "npm:^2.0.2"
+ semver: "npm:^7.3.7"
ts-dedent: "npm:^2.0.0"
type-fest: "npm:~2.19"
util-deprecate: "npm:^1.0.2"