From deb453ecb7a47c1d83bf8898266e90c1ca99f1bf Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 21 Sep 2020 16:53:12 +0200 Subject: [PATCH] fix(fast-refresh): set babel plugin correctly in the preset - Rather than in the webpack config, set it in babel, so that there aren't multiple loaders and instead just the plugin is added together with the presets. Examples were moved to cra-kitchen-sink because official removes the babel-loader taht comes from storybook. --- .../src/server/framework-preset-react.ts | 59 ++++++++++--------- examples/cra-kitchen-sink/.storybook/main.js | 3 + .../src/components/FastRefreshExample.js} | 4 +- .../src/stories/fast-refresh.stories.js | 9 +++ .../addon-docs/react-refresh.stories.js | 8 --- lib/core/types/index.ts | 1 + 6 files changed, 45 insertions(+), 39 deletions(-) rename examples/{official-storybook/stories/addon-docs/react-refresh-example.js => cra-kitchen-sink/src/components/FastRefreshExample.js} (67%) create mode 100644 examples/cra-kitchen-sink/src/stories/fast-refresh.stories.js delete mode 100644 examples/official-storybook/stories/addon-docs/react-refresh.stories.js diff --git a/app/react/src/server/framework-preset-react.ts b/app/react/src/server/framework-preset-react.ts index f75037e8571..c2180d367dd 100644 --- a/app/react/src/server/framework-preset-react.ts +++ b/app/react/src/server/framework-preset-react.ts @@ -1,10 +1,27 @@ import { TransformOptions } from '@babel/core'; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import type { Configuration } from 'webpack'; -import { logger } from '@storybook/node-logger'; -import type { StorybookOptions } from './types'; -export function babelDefault(config: TransformOptions) { +import { logger } from '@storybook/node-logger'; +import type { StorybookOptions } from '@storybook/core/types'; + +export async function babel(config: TransformOptions, options: StorybookOptions) { + const isDevelopment = options.configType === 'DEVELOPMENT'; + const reactOptions = await options.presets.apply('reactOptions', {}, options); + const fastRefreshEnabled = + isDevelopment && (reactOptions.fastRefresh || process.env.FAST_REFRESH === 'true'); + + if (!fastRefreshEnabled) { + return config; + } + + return { + ...config, + plugins: [require.resolve('react-refresh/babel'), ...(config.plugins || [])], + }; +} + +export async function babelDefault(config: TransformOptions) { return { ...config, presets: [ @@ -16,35 +33,19 @@ export function babelDefault(config: TransformOptions) { }; } -export function webpackFinal(config: Configuration, { reactOptions }: StorybookOptions) { - const isDevelopment = config.mode === 'development'; +export async function webpackFinal(config: Configuration, options: StorybookOptions) { + const isDevelopment = options.configType === 'DEVELOPMENT'; + const reactOptions = await options.presets.apply('reactOptions', {}, options); const fastRefreshEnabled = - isDevelopment && (reactOptions?.fastRefresh || process.env.FAST_REFRESH === 'true'); - if (fastRefreshEnabled) { - logger.info('=> Using React fast refresh feature.'); + isDevelopment && (reactOptions.fastRefresh || process.env.FAST_REFRESH === 'true'); + + if (!fastRefreshEnabled) { + return config; } + + logger.info('=> Using React fast refresh feature.'); return { ...config, - module: { - ...config.module, - rules: [ - ...config.module.rules, - fastRefreshEnabled && { - test: /\.[jt]sx?$/, - exclude: /node_modules/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - plugins: [require.resolve('react-refresh/babel')], - }, - }, - ], - }, - ].filter(Boolean), - }, - plugins: [...config.plugins, fastRefreshEnabled && new ReactRefreshWebpackPlugin()].filter( - Boolean - ), + plugins: [...(config.plugins || []), new ReactRefreshWebpackPlugin()], }; } diff --git a/examples/cra-kitchen-sink/.storybook/main.js b/examples/cra-kitchen-sink/.storybook/main.js index 0f293afbb70..16290a03d47 100644 --- a/examples/cra-kitchen-sink/.storybook/main.js +++ b/examples/cra-kitchen-sink/.storybook/main.js @@ -3,6 +3,9 @@ const path = require('path'); module.exports = { stories: ['../src/stories/**/*.stories.@(js|mdx)'], logLevel: 'debug', + reactOptions: { + fastRefresh: true, + }, addons: [ '@storybook/preset-create-react-app', { diff --git a/examples/official-storybook/stories/addon-docs/react-refresh-example.js b/examples/cra-kitchen-sink/src/components/FastRefreshExample.js similarity index 67% rename from examples/official-storybook/stories/addon-docs/react-refresh-example.js rename to examples/cra-kitchen-sink/src/components/FastRefreshExample.js index 07924321e48..d9e382ffa97 100644 --- a/examples/official-storybook/stories/addon-docs/react-refresh-example.js +++ b/examples/cra-kitchen-sink/src/components/FastRefreshExample.js @@ -1,11 +1,11 @@ import React from 'react'; -export const Refresh = () => { +export const FastRefreshExample = () => { const [value, setValue] = React.useState('abc'); return ( <> setValue(event.target.value)} /> -

Change the input value then this text in the component.

+

Change the input value then this text in the component file.

The state of the input should be kept.

); diff --git a/examples/cra-kitchen-sink/src/stories/fast-refresh.stories.js b/examples/cra-kitchen-sink/src/stories/fast-refresh.stories.js new file mode 100644 index 00000000000..f96f85877dc --- /dev/null +++ b/examples/cra-kitchen-sink/src/stories/fast-refresh.stories.js @@ -0,0 +1,9 @@ +import React from 'react'; +import { FastRefreshExample } from '../components/FastRefreshExample'; + +export default { + title: 'React Fast Refresh', + component: FastRefreshExample, +}; + +export const Default = () => ; diff --git a/examples/official-storybook/stories/addon-docs/react-refresh.stories.js b/examples/official-storybook/stories/addon-docs/react-refresh.stories.js deleted file mode 100644 index 57efe1072b0..00000000000 --- a/examples/official-storybook/stories/addon-docs/react-refresh.stories.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { Refresh } from './react-refresh-example'; - -export default { - title: 'Core/React Refresh', -}; - -export const Default = () => ; diff --git a/lib/core/types/index.ts b/lib/core/types/index.ts index d0c0c7f0233..afc126a01fc 100644 --- a/lib/core/types/index.ts +++ b/lib/core/types/index.ts @@ -40,6 +40,7 @@ export interface StorybookOptions { configType: 'DEVELOPMENT' | 'PRODUCTION'; presetsList: Preset[]; typescriptOptions: TypescriptOptions; + [key: string]: any; } /**