storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.05k stars 9.24k forks source link

[Bug]: Storybook Build Extremely Slow When Importing FontAwesome #19736

Open JonHaywood opened 1 year ago

JonHaywood commented 1 year ago

Describe the bug

When a story imports a component that uses the FontAwesome npm package, build time skyrockets. On my local machine it takes around 20 minutes for my entire project, but over an hour on my build server.

I'm using React and MDX stories. I can reproduce the 20 minute build consistently with all the files in my project. But I can also reproduce it when I have just one MDX story, given that story imports a component that uses FontAwesome. In the case of only that one MDX story, the build takes 10 minutes on my machine. The issue disappears immediately if I create one MDX story which doesn't reference FontAwesome. In that case the build is under 60 seconds.

Example MDX story that can repro the issue:

import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import { HelperIcon } from './HelperIcon';

<Meta 
    title="Other/HelperIcon" 
    component={HelperIcon} 
/>

export const Template = (args) => <HelperIcon {...args} />;

# HelperIcon

<Canvas>
    <Story name="Basic Usage">
        {Template.bind({})}
    </Story>
</Canvas>

### HelperIcon Props

<ArgsTable of={HelperIcon} />

Example component:

import './HelperIcon.scss';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faQuestionSquare } from '@fortawesome/pro-solid-svg-icons';

export const HelperIcon = () => {
    return (
        <span>
            <FontAwesomeIcon icon={faQuestionSquare} />
        </span>
    );
};

Important note: I have FontAwesome (pro and free) installed locally. So the build is not hitting the live npm servers. I have a yarn workspace set up with all the FontAwesome packages in the /vendor directory.

I suspect the root cause of the issue isn't anything special about FontAwesome but the sheer number of files on disk in those packages. FontAwesome has tens of thousands of files included across all its packages. However, this isn't a problem for my rollup build, it completes just fine and pretty quick. So there's something about the Storybook webpack build that's getting hitched up. I'm hoping there's some config flag I can tweak in main.js that can speed this up, or tell it to exclude a folder, or something.

Here's main.js:

const path = require('path');

module.exports = {
    stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
    addons: [
        {
            // this added is needed for PostCSS 8, which is required to process Tailwind CSS
            name: '@storybook/addon-postcss',
            options: {
                postcssLoaderOptions: {
                    implementation: require('postcss'),
                },
            },
        },
        '@storybook/addon-links',
        '@storybook/addon-essentials',
        '@storybook/addon-controls',
    ],
    webpackFinal: (config) => {
        config.resolve.fallback = {
            stream: require.resolve('stream-browserify'),
            crypto: require.resolve('crypto-browserify'),
        };
        config.module.rules.push({
            test: /\.(scss|sass)$/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        postcssOptions: {
                            sourceMap: true,
                            plugins: [],
                        },
                    },
                },
                {
                    loader: 'sass-loader',
                    options: {
                        sourceMap: true,
                    },
                },
                {
                    loader: 'sass-resources-loader',
                    options: {
                        resources: path.resolve(__dirname, '../', 'src/css/resources.scss'),
                    },
                },
            ],
        });
        return config;
    },
    core: {
        builder: 'webpack5',
    },
};

To Reproduce

Edit: I was able to repro this with the free versions of FontAwesome. Repository here: https://github.com/JonHaywood/storybook-fontawesome-repro

The build times aren't as dramatic but still significant. Building with just one story that references FontAwesome takes 2 minutes reliably on my machine. Removing that story takes it down to 22 seconds.

System

Environment Info:

  System:
    OS: Windows 10 10.0.22000
    CPU: (16) x64 Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz
  Binaries:
    Node: 14.19.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 6.14.16 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.22000.120.0), Chromium (106.0.1370.52)
DanielHoffmann commented 1 year ago

One thing I noticed is that when you import font-awesome like this:

import { faQuestionSquare } from '@fortawesome/pro-solid-svg-icons';

all fonts from the package are inlined in the sourcemaps (+10mb of inlined SVG). This was happening both in my normal builds and storybook builds

Try adding this

devtool: null to your storybook webpack config in main.js to completely disable sourcemaps and see if it improves.

I haven't figured out how to disable sourcemaps for font-awesome only in storybook builds though. Adding this to plugins work on my normal builds but not in storybook:

            new EvalSourceMapDevToolPlugin({
              filename: '[file].map[query]',
              exclude: [/fortawesome/i],
              module: true,
              columns: false,
            }),

for now I just live with it in storybook