storybookjs / storybook

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

[Bug]: @storybook/addon-controls break some stories #27071

Open hanshank opened 4 months ago

hanshank commented 4 months ago

Describe the bug

Working on a Storybook application for a large corporation and we are trying to upgrade from Storybook v6 to v7. I have already gotten rid of the old addon-knobs library in favor of @storybook/addon-controls before the migration. The issue I'm seeing is with one specific story file and I can't for the life of me figure out what's going on. The story works perfect when I don't add @storybook/addon-controls inside of the addons array in main.js. As soon as adding it, I see some error about Modal is undefined, Modal being a component that is not even imported in my Story. I've noticed that for some broken stories I can fix them by converting certain barrel imports (using index.js files for re-exporting modules) into importing from each separate module.

I'm stumped at this point. I've tried downgrading to earlier minor versions of Storybook, switched to @storybook/addon-essentials - I just don't get what the issue could be.

Here's storybook/main.js:

const path = require('path');

const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

const pkg = require('../../package.json');

// actions, backgrounds, docs, viewport, toolbars, measure, outline, and highlight
module.exports = {
  stories: ['../../src/**/*.stories.@(ts|js|tsx)'],

  addons: [
    '@storybook/addon-a11y',
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    // {
    //   name: '@storybook/addon-essentials',
    //   options: {
    //     // controls: false,
    //     // docs: true,
    //     toolbars: false,
    //     measure: false,
    //     outline: false,
    //     highlight: false,
    //   },
    // },
  ],

  docs: {
    autodocs: false, // TODO: Do we need this for now?
  },

  framework: {
    name: '@storybook/nextjs',
    options: {},
  },

  webpackFinal: async (config) => {
    config.plugins.push(
      new VanillaExtractPlugin({
        identifiers: 'short',
      })
    );
    config.plugins.push(new MiniCssExtractPlugin({}));
    config.module.rules.push({
      test: /\.vanilla\.css$/i, // Targets only CSS files generated by vanilla-extract\
      use: [
        MiniCssExtractPlugin.loader,
        {
          loader: require.resolve('css-loader'),
          options: {
            url: false, // Required as image imports should be handled via JS/TS import statements
          },
        },
      ],
    });

    const nonVanillaExtractCSSRuleIdx = config.module.rules.findIndex(
      (r) => r?.test?.toString?.() === '/\\.css$/'
    );

    // eslint-disable-next-line no-param-reassign
    config.module.rules[nonVanillaExtractCSSRuleIdx].exclude = [
      config.module.rules[nonVanillaExtractCSSRuleIdx].exclude,
      /\.vanilla\.css$/i,
    ];

    config.plugins.push(
      new webpack.DefinePlugin({
        __APP_NAME__: JSON.stringify(pkg.name),
        __APP_VERSION__: JSON.stringify(pkg.version),
        'global.window.COMMITHASH': JSON.stringify(
          process.env.GIT_SHA || 'no-build-number'
        ),
      })
    );

    return config;
  },

  core: {},
};

To Reproduce

I can't share the repo since it's for my work - But hoping this is a common issue with @storybook/addon-controls

System

System:
    OS: macOS 14.1.1
    CPU: (10) arm64 Apple M1 Pro
  Binaries:
    Node: 16.14.0 - ~/.nvm/versions/node/v16.14.0/bin/node
    Yarn: 1.22.21 - ~/.nvm/versions/node/v18.15.0/bin/yarn
    npm: 8.3.1 - ~/.nvm/versions/node/v16.14.0/bin/npm
  Browsers:
    Chrome: 124.0.6367.119
    Safari: 17.1
  npmPackages:
    @storybook/addon-a11y: ~7.6.19 => 7.6.19 
    @storybook/addon-essentials: ~7.6.19 => 7.6.19 
    @storybook/addon-links: ~7.6.19 => 7.6.19 
    @storybook/nextjs: ~7.6.19 => 7.6.19 
    @storybook/preview-api: ~7.6.19 => 7.6.19 
    @storybook/theming: ~7.6.19 => 7.6.19

Additional context

No response

hanshank commented 4 months ago

These error messages aren't very helpful either. Complaining about Modal being undefined, and I can't even see a reference to Modal in the file it claims the error is in:

Screenshot 2024-05-09 at 9 52 18 AM Screenshot 2024-05-09 at 9 52 23 AM
hanshank commented 4 months ago

UPDATE: I've looked into the barrel imports (using index.js to re-export modules), and it seems to be causing issues when @storybook/addon-controls is enabled. Even though the story only uses certain modules that are re-exported in those index.js files, I'm wondering if react-docgen scans all the other imported modules too and then somehow errors out down the line. I've tried following the import trails, but I can't even get to the file the screenshot above is claiming has an undefined modal.

It's just super weird, cause everything works fine when @storybook/addon-controls or @storybook/addon-essentials are not enabled

hanshank commented 4 months ago

Also - using TypeScript, Webpack 5 and Babel here + the storybook nextjs framework

hanshank commented 4 months ago

I've narrowed it down to be happening for the following scenario:

  1. @storybook/addon-essentials are added to main.ts and either controls or docs are NOT set to false (they are enabled). Disabling both of these will fix the issue
  2. A simple Story that is importing a component/function from an index file with other imports that are unused, e.g.
import React from 'react';

import TestComponent from '@/src/components/TestComponent'; // imports from barrel file (index.tsx)

export default {
  component: TestComponent,
};

export const CoolStory = (args) => <TestComponent {...args} />;
CoolStory.args = {
  text: 'Hello',
};

And the @/src/components/TestComponent import from the index.tsx file:

import AnotherModule from "../AnotherModule"; // this is not utilized or explicitly imported, but I think react-docgen analyzes it which causes the undefined module error???
import TestComponent from './TestComponent';

export { AnotherModule };

export default TestComponent;
shilman commented 4 months ago

I haven't heard of this issue before. One thing you can try is to turn off docgen in .storybook/main.js:

// .storybook/main.js
export default {
  typescript: { reactDocgen: false }
}

This means that you will not get autogenerated controls, but if you still want docs/controls it could be a workaround.

If you can create a reproduction at https://storybook.new or see repro docs it might be possible for somebody from the team to debug what's going on.