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.
This commit is contained in:
Yann Braga 2020-09-21 16:53:12 +02:00
parent e66da69547
commit deb453ecb7
6 changed files with 45 additions and 39 deletions

View File

@ -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()],
};
}

View File

@ -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',
{

View File

@ -1,11 +1,11 @@
import React from 'react';
export const Refresh = () => {
export const FastRefreshExample = () => {
const [value, setValue] = React.useState('abc');
return (
<>
<input value={value} onChange={(event) => setValue(event.target.value)} />
<p>Change the input value then this text in the component.</p>
<p>Change the input value then this text in the component file.</p>
<p>The state of the input should be kept.</p>
</>
);

View File

@ -0,0 +1,9 @@
import React from 'react';
import { FastRefreshExample } from '../components/FastRefreshExample';
export default {
title: 'React Fast Refresh',
component: FastRefreshExample,
};
export const Default = () => <FastRefreshExample />;

View File

@ -1,8 +0,0 @@
import React from 'react';
import { Refresh } from './react-refresh-example';
export default {
title: 'Core/React Refresh',
};
export const Default = () => <Refresh />;

View File

@ -40,6 +40,7 @@ export interface StorybookOptions {
configType: 'DEVELOPMENT' | 'PRODUCTION';
presetsList: Preset[];
typescriptOptions: TypescriptOptions;
[key: string]: any;
}
/**