storybookjs / storybook

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

[Bug]: Docs for MUI (Material UI) don't work with storybook v.7.6.10 #25659

Open mimiqkz opened 9 months ago

mimiqkz commented 9 months ago

Describe the bug

I followed everything instructed in the recipe, nothing works, nothing appeared. Both with Vite and Webpack

To Reproduce

Follow the recipe

System

System:
    OS: macOS 14.2.1
    CPU: (8) arm64 Apple M1 Pro
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.6.7 - ~/.nvm/versions/node/v18.17.1/bin/npm <----- active
    pnpm: 8.6.9 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 120.0.6099.234
    Edge: 120.0.2210.144
    Safari: 17.2.1
  npmPackages:
    @storybook/addon-designs: ^7.0.9 => 7.0.9 
    @storybook/addon-essentials: ^7.6.10 => 7.6.10 
    @storybook/addon-interactions: ^7.6.10 => 7.6.10 
    @storybook/addon-links: ^7.6.10 => 7.6.10 
    @storybook/addon-onboarding: ^1.0.10 => 1.0.10 
    @storybook/addon-themes: ^7.6.10 => 7.6.10 
    @storybook/blocks: ^7.6.10 => 7.6.10 
    @storybook/react: ^7.6.10 => 7.6.10 
    @storybook/react-vite: ^7.6.10 => 7.6.10 
    @storybook/test: ^7.6.9 => 7.6.10 
    eslint-plugin-storybook: ^0.6.15 => 0.6.15 
    storybook: ^7.6.9 => 7.6.10

Additional context

The follow codes are written for my button.stories.tsx

import {Meta} from '@storybook/react'
import Button from './button.component'

export default {
  title: 'Inputs/Buttons',
  parameters: {
    // Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
    layout: 'centered',
  },
  tags: ['autodocs'],
} satisfies Meta<typeof Button>

export const Default = () => <Button variant="outlined">Default</Button>,
  Primary = () => <Button>Primary</Button>,
  Secondary = () => <Button color="secondary">Secondary</Button>

The button.component.tsx (same as in the recipe):

import React from 'react';
import { Button as MuiButton, ButtonProps as MuiButtonProps } from '@mui/material';

// Only include variant, size, and color
type ButtonBaseProps = Pick<MuiButtonProps, 'variant' | 'size' | 'color'>;

// Use all except disableRipple
// type ButtonBaseProps = Omit<MuiButtonProps, "disableRipple">;

export interface ButtonProps extends ButtonBaseProps {
  label: string;
}

export const Button = ({ label, ...rest }: ButtonProps) => <MuiButton {...rest}>{label}</MuiButton>;

Then main.ts

import type {StorybookConfig} from '@storybook/react-vite'

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials',
    '@storybook/addon-onboarding',
    '@storybook/addon-interactions',
    '@storybook/addon-themes',
  ],
  staticDirs: ['../public'],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
  typescript: {
    check: false,
    reactDocgen: 'react-docgen',
    reactDocgenTypescriptOptions: {
      // Speeds up Storybook build time
      compilerOptions: {
        allowSyntheticDefaultImports: false,
        esModuleInterop: false,
      },
      // Makes union prop types like variant and size appear as select controls
      shouldExtractLiteralValuesFromEnum: true,
      // Makes string and boolean types that can be undefined appear as inputs and switches
      shouldRemoveUndefinedFromOptional: true,
      // Filter out third-party props from node_modules except @mui packages
      propFilter: (prop: any) =>
        prop.parent
          ? !/node_modules\/(?!@mui)/.test(prop.parent.fileName) : true,
    },
  },
}
export default config

For preview.ts:

import CssBaseline from '@mui/material/CssBaseline/CssBaseline';
import ThemeProvider from '@mui/material/styles/ThemeProvider';
import responsiveFontSizes from '@mui/material/styles/responsiveFontSizes';
import { withThemeFromJSXProvider } from '@storybook/addon-themes';
import createTheme from '@mui/material/styles/createTheme';
import { themes } from '@storybook/theming';

import * as theme from '../src/themes/theme'
import '@fontsource/material-icons';

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
  sidebar: {
    showRoots: false,
  },
  docs: {
    theme: themes.light,
  },
  controls: {
    expanded: true,
    hideNoControlsWarning: true,
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

export const decorators = [
  withThemeFromJSXProvider({
  themes: {
    light: responsiveFontSizes(createTheme(theme.getDesignTokens('light'))),
    dark: responsiveFontSizes(createTheme(theme.getDesignTokens('dark'))),
  },
  defaultTheme: 'light',
  Provider: ThemeProvider,
  GlobalStyles: CssBaseline,
})];

MUI v. 5.15.2 and emotion 11.11.3

mimiqkz commented 9 months ago

Themes works, but no docs and no controls from MUI

shilman commented 9 months ago

@mimiqkz In main.ts you've set typescript.reactDocgen to react-docgen. That means that your reactDocgenTypescriptOptions are being ignored. Try setting typescript.reactDocgen back to react-docgen-typescript and see if that fixes the auto-generated ArgTypes/Controls.

mimiqkz commented 9 months ago

@shilman Hi, thank you for the reply. I tried changing back to react-docgen-typescript, re-run storybook, it doesn't work either :(

shilman commented 9 months ago

Do you a have a reproduction repo you can share? If not, can you create one? Go to https://storybook.new or see repro docs. Thank you! πŸ™

mimiqkz commented 8 months ago

@shilman Sorry for a late reply, but here is the repo https://github.com/mimiqkz/storybook-vite-bug

mimiqkz commented 8 months ago

@shilman Hello, any luck regarding to this?

mimiqkz commented 8 months ago

Adding component: Button, in Meta solved the problem for me πŸ‘ Edit: Sometimes it works, sometimes not. Extremely inconsistent

valentinpalkovic commented 8 months ago

As far as I can see, the react-docgen loader isn't applied for node_modules components. We do this for performance reasons. I can see that you have resolved the issue by adding the component field to the meta. But for everyone who wants to use MUI components directly without a wrapper, this will likely not work since react-docgen isn't applied on node_module components, if they are the entry point. If a component is not in node_modules, but imports components from node_modules, react-docgen itself can traverse through the import tree and therefore it works.

So let's try to find a workaround for the case, where the component defined in the meta comes from node_modules:

Webpack-based

If you use Webpack, we must find the appropriate loader and adjust the exclude pattern. Something like this:

// .storybook/main.ts
const config = {
  webpackFinal: async (config) => {
    config.module!.rules!.forEach(
      (rule) => {
        if(rule.loader?.includes('react-docgen')) {
          // the default is: /(\.(stories|story)\.(js|jsx|ts|tsx))|(node_modules)/
          rule.exclude = /(\.(stories|story)\.(js|jsx|ts|tsx))/
        }
      }
    );

    return config;
}

export default config;

Vite-based

Well, for vite-based projects, it turns out to be more complicated because it isn't possible to change the exclude pattern by manipulating the config. The exclude pattern automatically excludes files in node_modules.

TODOs

Before we make any changes or even allow react-docgen to be applied to node_module files, could you see if the Webpack5 customizations work to confirm the theory?

mimiqkz commented 8 months ago

@valentinpalkovic I'm a bit confused. In the github example and I also stated in the comment above. Changing to react-docgen-typescript won't work so I don't understand why you are talking about react-docgen... Is there something that I missed?

valentinpalkovic commented 8 months ago

When I was talking about react-docgen-loader, I meant react-docgen, not react-docgen-typescript.

You can see here what I meant.

Sorry for the confusion. I was not following the whole thread. What exact inconsistencies do you have?

mimiqkz commented 8 months ago

@valentinpalkovic Hello, thank you for the reply. The inconsistency I have is that sometimes I get the docs + the controls from MUI, sometimes I don't. I just updated my with the example github repo

Edit more info: So from this example, Button works, but not Accordion

mimiqkz commented 8 months ago

@shilman @valentinpalkovic Ok I figured out the problem. Docs seem to not work on export default, which is weird btw, but works on named export. Would love to get some insight on why this is the case

l-campbell commented 6 months ago

That works @valentinpalkovic πŸŽ‰ πŸ‘

Would there be any way to get this working for vite based?