the problem we are encountering when trying to add storybook to our project is, that when we run development server, webpack builds every part of the app (resolves ~50,000 dependencies), therefore, when we run it, on network tab we can see unnecessary file downloaded (which contains entire app) that causes entire story (which is downloaded as separate file due to storyStoreV7 flag) to crash, because some lines of unnecessary bundle are raising errors (files aren't even required to display stories). Example error:
TypeError: Cannot read properties of undefined (reading 'CheckboxList')
at Module.CheckboxList (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:35683:111)
at Module../js/forms/fields/checkbox-list/index.tsx (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:41141:103)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
at Module../js/forms/fields/index.js (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:43187:73)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
at Module../js/apps/admin/forms/add-reward-rule/index.tsx (http://localhost:6007/js_components_index_tsx-node_modules_django-channels_dist_sync_recursive-node_modules_moment_-6a9914.iframe.bundle.js:1726:71)
at __webpack_require__ (http://localhost:6007/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6007/runtime~main.iframe.bundle.js:352:21)
We found out, that when importing components with React.lazy issue is not present, we can use it this way, but it would be better to use it the "proper" way.
Storybook version: 6.5.0-alpha.42
.storybook/main.js
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
const path = require('path');
const globImporter = require('node-sass-glob-importer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
"stories": [
"../js/**/*.stories.*",
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions",
{
"name": '@storybook/preset-scss',
"options": {
"sassLoaderOptions": {
"sourceMap": true,
"sassOptions": {
"includePaths": [path.resolve(__dirname, '../js')],
"importer": globImporter(),
}
},
"cssLoaderOptions": {
"url": false,
}
}
}
],
"features": {
"storyStoreV7": true,
},
"framework": "@storybook/react",
"core": {
"builder": "webpack5"
},
"staticDirs": [path.resolve(__dirname, '../../static')],
"webpackFinal": async (config) => {
config.entry.push(path.resolve(__dirname, '../scss/main.scss'))
config.resolve.plugins = [
...(config.resolve.plugins || []),
new TsconfigPathsPlugin({
extensions: config.resolve.extensions,
}),
];
config.resolve.alias = {
...(config.resolve.alias || {}),
'@js': path.resolve(__dirname, '../js'),
}
config.plugins = [
...(config.plugins || []),
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
}),
new MiniCssExtractPlugin({
filename: 'style.css'
}),
]
config.module.rules.push(
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [{ loader: '@svgr/webpack', options: { ref: true } }],
}
)
return config
}
}
.storybook/preview.tsx
import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
import { Parameters } from '@storybook/react'
import { HistoryRouter } from '../js/routes/history-router';
import { browserHistory } from '../js/routes/history';
import '../scss/main.scss';
import theme from '../js/theme'
export const decorators = [
(Story) => {
return <StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<HistoryRouter history={browserHistory}>
{Story()}
</HistoryRouter>
</ThemeProvider>
</StyledEngineProvider>
}
]
export const parameters: Parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
export const argTypes = { children: { type: 'string' }}
example story: Button.stories.tsx:
import React from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { Button } from './index';
export default {
component: Button,
} as ComponentMeta<typeof Button>;
const Template: ComponentStory<typeof Button> = (args) => {
return <Button {...args}>{args.children || 'Button'}</Button>;
};
export const Common = Template.bind({});
Common.args = { variant: 'primary' };