Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Storybook 7.x storysource addon doesn't show whole story code #22922

Open
Podlipny opened this issue Jun 5, 2023 · 43 comments
Open

[Bug]: Storybook 7.x storysource addon doesn't show whole story code #22922

Podlipny opened this issue Jun 5, 2023 · 43 comments

Comments

@Podlipny
Copy link

Podlipny commented Jun 5, 2023

Describe the bug

I have a problem with the Storybook addon Storysource after migration from Storybook 6.x to Storybook 7.x. In Storybook 6.x I was able to see the whole story code, but now I am able only to see args content.

image

To Reproduce

here is repo: https://github.com/Podlipny/storybook-storysource-issue

just npm i and npm storybook, tab code should contain whole story code

System

Storybook 7 and newer

Additional context

No response

@KevinGhadyani-Okta
Copy link

KevinGhadyani-Okta commented Jul 18, 2023

This looks like an issue with the AST. I'm making some wild guesses here, but it's probably doing a check inside the Component, and now the component is an object.

I wonder if simply changing it to look at storyObject.render instead of the storyObject would fix it.

@Podlipny
Copy link
Author

repo with code to replicate this issue is here: https://github.com/Podlipny/storybook-storysource-issue

I am defining story based on storybook documentation, so this should wor without any need to modify anything

import type { Meta, StoryObj } from '@storybook/react';

import { Button } from './Button';

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: { control: 'color' },
  },
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Primary: Story = {
  render: () => <Button primary label="Button" />,
  args: {
    primary: true,
    label: 'Button sdsd sdsd sdsds',
  },
};

@yingpengsha
Copy link

Is there any progress and possible workaround on this issue?

@Podlipny
Copy link
Author

Podlipny commented Aug 8, 2023

nothing I would know about - we just stopped using storysource until this bug is resolved

@gluharry
Copy link

gluharry commented Nov 8, 2023

I am also able to reproduce this after migrating from 6.x to 7.5.
Is there any progress or problem identification on this?

Cheers!

@valentinpalkovic
Copy link
Contributor

Can someone help me to understand the issue?

As far as I understand it, in Storybook 6.x the whole Storyfile was outputted as source code. Now, in 7.x, only the code is outputted, which applies to the selected Story. Isn't this the wished behavior? Why should someone be interested in showing the source code from the other Stories when one is selected? Wouldn't this be a mess for huge Story files? I am missing some context here.

@aaron-troglia
Copy link

I am also seeing this issue on v7.5. The information outlined in "Displaying full source" on the landing page does not appear to make a difference.

@valentinpalkovic, The end goal isn't to see other stories' source code, but to see the full component code of the corresponding story that is selected. Right now, we're just seeing the args.

Screenshot of the current result:
Screenshot 2023-11-15 at 3 48 01 PM

Compared to the desired (screenshot pulled from the Storysource landing page gif)
Screenshot 2023-11-15 at 3 49 11 PM

@sumitdahal7
Copy link

I also encountered the same problem while displaying a source code by using storysource. Has anyone got the solutions of it ??

@JamesIves
Copy link

JamesIves commented Jan 11, 2024

Seeing the same issue:

  • @storybook/addon-storysource: "^7.6.7"
  • @storybook/web-components: "7.6.4"

Output shows the following:

{
  args: {
    ['icon-group']: 'general'
  }
}

versus the desired:

<component-name icon-group="general"></component-name>

The code preview in the doc view works just fine, which is ultimately what I want in the addon view that updates with the controls.

@mm-georges
Copy link

Could anyone find a workaround to this issue? :(

@SalahAdDin
Copy link

Here I am, same issue:
image

@aaron-troglia
Copy link

I found that there is a storySource parameter you can add to override what the rendered story code can be.

For example:

Button.stories.ts

const meta = {
  title: 'Example/Button',
  component: Button,
  parameters: {
    layout: 'centered',
    storySource: {
      source: 'foo' //Put your code here
    }
  },

Based on how the addon works, it looks like it tries to load the loaderSource first, then defaults to an object of the args:

/core/addons/storysource/src/StoryPanel.tsx

export const StoryPanel: React.FC<StoryPanelProps> = ({ api }) => {
  const story = api.getCurrentStoryData();
  const selectedStoryRef = React.useRef<HTMLDivElement>(null);
  //The param I'm passing in the above example
  const { source: loaderSource, locationsMap }: SourceParams = useParameter('storySource', {});
  const { source: { originalSource: docsSource } = {} }: DocsParams = useParameter('docs', {});
  // prefer to use the source from source-loader, but fallback to
  // source provided by csf-plugin for vite usage
  const source = loaderSource || docsSource || 'loading source...';

@Podlipny
Copy link
Author

thanks for response guys, We've been able to make it work with this inside `.storybook/preview

export const parameters = {
  docs: { source: { type: 'code' } },
...

@SalahAdDin
Copy link

docs: { source: { type: 'code' } },

It does not work for us.

@ChenReuven
Copy link

is there any update? it seems that there is a lot of issues with the show code , source code mechanism

@anibe
Copy link

anibe commented Mar 13, 2024

This issue appears to be fixed in 8.x but it would be nice if a fix is made available for those who can't upgrade yet 🙏

@brian-patrick-3
Copy link

Since upgrading to Storybook v8 I can only see the current story source, and there is no way to reveal the full story source.

@aaron-troglia
Copy link

@oeem1011 I also ran in into a similar issue when trying out a few tactics. My initial thought was to simply convert the exported component into a string:

import { Button } from './Button';

const meta = {
  title: 'Example/Button',
  component: Button,
  parameters: {
    layout: 'centered',
    storySource: {
      source: `${Button}`
    }
  }, //...continued

But like you said it coverts the code. It might work for some crude use-cases, but isn't a great option.

@mm-georges
Copy link

after upgrading to storybook 8, still running into the same issue :(

@ddamato
Copy link

ddamato commented Mar 14, 2024

after upgrading to storybook 8, still running into the same issue :(

Sorry to hear that but also glad I didn't go through the upgrade just for this now. Clearly, there's something else going on.

@mm-georges
Copy link

Any chance this will be fixed in the future?

@sdandrader
Copy link

Same issue here! @valentinpalkovic there is any chance, please?

@prokhvit
Copy link

Still actual

@brynshanahan
Copy link

We're also getting this in 7.0 and 8.0.

When running the dev server with Vite the story source appears correctly, but then when building for production we get {} as the story source.

The issue only appears when displaying stories in a custom .mdx file. When using autodocs the source appears correctly which makes me think it's not to do with source parsing?

@wondasom
Copy link

It is unfortunate that it is still happening. Our team used to use .mdx as default doc format but recently decided on the following as an alternative and now working on changing existing docs 🥲

  • Use CSF's autodocs feature instead of .mdx for component overview docs.
  • Add description to component and each story level if applicable. (You can also add readme to the component description)
const meta: Meta<typeof COMPONENT> = {
  title: 'CATEGORY/COMPONENT',
  parameters: {
    docs: {
      description: {
        component:
          '🖊️ COMPONENT DESCRIPTION GOES HERE', // 👈 You can pass a readme file here as well. 
      },
    },
    ...
  },
}
 
export default meta
type Story = StoryObj<typeof COMPONENT>
 
 
...
 
 
export const Default: Story = (args: COMPONENT_PROPS) => {
  return (
    ...
  )
}
 
Default.parameters = {
  docs: {
    description: {
      story: '🖊️ STORY DESCRIPTION GOES HERE',
    },
  },
}

@Zlvsky
Copy link

Zlvsky commented Jun 10, 2024

Any updates/workarounds?:(

@brynshanahan
Copy link

@Zlvsky if you check out @sashathor's branch it appears they've used a custom component that parses the story source instead of relying on the component

@Zlvsky
Copy link

Zlvsky commented Jun 11, 2024

@brynshanahan
Alright, thanks!

Also I've made workaround that works for me to view the file source code:

  1. Create separate file with exported source code as a string (if you use webpack, you can try raw-loader)
export const code = `
// your code here
`
  1. Import it on Component story and pass with parameters
import { code } from './Component.code'

export const Primary: Story = (args) => {
  return (
    <Component {...args}>
      Primary
    </Component>
  )
}

Primary.parameters = {
  storySource: {
    source: code
  }
}

image

@Omar-Assadi-copilot
Copy link

Any updates?

@ilchenkoArtem
Copy link

Any updates?

@brynshanahan
Copy link

We managed to fix this issue. We tracked it down to React contexts being imported twice from the same package, in one build we were getting module.cjs and module.mjs of the same module. The culprit was our custom Rollup resolver plugin.
We were able to fix it by changing our custom resolver plugin to use this.resolve so it would use Vite's default resolving rather than just straight require.resolve

@ddamato
Copy link

ddamato commented Sep 6, 2024

It's still happening on my project, but less so than I reported earlier. Out of 70 components, this seems to affect 7 of them. Also noticed this because where it happens, the Storybook Controls are inert in the docs. More specifically, the first story in the file used as the docs example renders knobs that do nothing. And the code shows precisely what is written in source instead of what is meant to be written as a component.

// Expected in Story Source
<Tabs id='default-tabs' />
// Actual in Story Source
{
  args: { id: 'default-tabs' }
  render: function Default(args) { return <Tabs { ...args }/> }
}

Note that I have plenty of other stories that utilize render that do not have this problem. I'm well aware the render function I'm giving in this example seems excessive. I've omitted the parts within for the sake of simplicity in the example. I also have a component that simply displays {} as is in the source.

Also note that if I fire up the local Storybook for examples that do not work, the Storybook Controls do work on the individual story pages. In my setup, this seems to be a problem specifically when rendering docs for certain components that don't seem to be different from others that are working.

@shilman
Copy link
Member

shilman commented Sep 9, 2024

@ddamato is the behavior identical in dev and build modes?

@ddamato
Copy link

ddamato commented Sep 9, 2024

@ddamato is the behavior identical in dev and build modes?

Yes identical behavior between both.

@shilman
Copy link
Member

shilman commented Sep 11, 2024

@ddamato is this the literal story source?

{
  args: { id: 'default-tabs' }
  render: function Default(args) { return <Tabs { ...args }/> }
}

If so, can you try changing it to the following and see if that fixes anything:

{
  args: { id: 'default-tabs' }
  render: (args) => { return <Tabs { ...args }/> }
}

@ddamato
Copy link

ddamato commented Sep 11, 2024

Yes, that is the literal source. That change doesn't seem to affect the output past showing the new source.

@mm-georges
Copy link

Is this getting fixed? We really miss the old behaviour of the Storysource in our Project.

@yasevplaton
Copy link

yasevplaton commented Oct 8, 2024

Hey, guys!
We've also encountered this issue in 8.3.3, and did a little analysis, here are the results (to clarify, there are screenshots with storysource-addon code below).

  1. In 7.5.2 we have storySource.source with full file content in story's parameters, this is convenient because in this case we see all scope for the current story. We would like to have this behaviour, at least it should be managed by parameter. Expected result Image

  2. In 8.1.10 we don't have storySource and docs.source.originalSource properties at all and just see "loading source..." in code panel. Image

  3. In 8.3.3 we also don't have storySource property, and we could work only with docs.source.originalSource that just refers to object with arguments for story. This is not convenient especially for basic story (in this case we just have empty object as code for the story). Actual result Image

Storybook config

const path = require('path');  
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');  
import { StorybookConfig } from '@storybook/react-webpack5'  
  
const config: StorybookConfig = {  
  stories: [  
    '../docs/**/*.@(mdx|stories.@(ts|tsx))',  
    '../docs/*.@(mdx|stories.@(ts|tsx))',  
    '../src/**/*.@(mdx|stories.@(ts|tsx))'  
  ],  
  addons: [  
    '@storybook/addon-docs',  
    '@storybook/addon-essentials',  
    '@storybook/addon-storysource',  
    '@storybook/addon-links',  
    'storybook-dark-mode',  
    '@storybook/addon-webpack5-compiler-babel'  
  ],  
  managerHead: () => `  
    <style>      .css-1wmxdc3, .css-1nwijr1 {        margin-right: 0 !important;      }      .css-1rb1jn6 {        max-width: 100% !important;      }    </style>  `,  
  framework: '@storybook/react-webpack5',  
  webpackFinal: async (config) => {  
    if (!config.resolve || !config.module || !config.module.rules) {  
      return config  
    }  
    config.resolve.alias = {  
      ...config.resolve.alias,  
      '@src': path.resolve(__dirname, '../src/'),  
      '@design-system': path.resolve(__dirname, '../design-system/'),  
      '@icons': path.resolve(__dirname, '../icons/'),  
      '@helpers': path.resolve(__dirname, '../helpers/'),  
      '@style': path.resolve(__dirname, '../style/'),  
      '@sb': path.resolve(__dirname, '../.storybook/'),  
    };  
    config.module.rules.push({  
      test: /\.less$/,  
      include: [  
        path.resolve(__dirname, '..'),  
        path.resolve(__dirname, '..', 'node_modules', 'antd')  
      ],  
      use: [  
        require.resolve('style-loader'),  
        {  
          loader: require.resolve('css-loader'),  
          options: {  
            modules: {  
              mode: 'global',  
              localIdentName: '[name]_[local]_[hash:base64:8]'  
            },  
            sourceMap: true  
          }  
        },  
        {  
          loader: require.resolve('less-loader'),  
          options: {  
            lessOptions: {  
              paths: [path.resolve(__dirname, '..')],  
              javascriptEnabled: true  
            }  
          }  
        }  
      ]  
    })  
  
    config.resolve.plugins = [  
      ...(config.resolve.plugins || []),  
      new TsconfigPathsPlugin({  
        extensions: config.resolve.extensions  
      })  
    ]  
  
    return config  
  }  
}  
  
module.exports = config

preview.ts

import { Preview } from '@storybook/react'  
import { badgesConfig } from './badges'  
import { withI18n } from './decorators/withI18n'  
import { themes } from '@storybook/theming'  
import { CustomDocsContainer } from './Docs'  
import { withThemeProvider } from './decorators/withThemeProvider'  
import { ThemeKey } from '@design-system/types'  
import '../style/styles.less'  
import { themeColors } from '@design-system/tokens'  
import { withBadges } from '@sb/decorators/withBadges'  
  
import lightThemeLogo from './assets/Hexa_UI_Light.svg'  
import darkThemeLogo from './assets/Hexa_UI_Dark.svg'  
  
export const globalTypes = {  
  theme: {  
    name: 'Theme',  
    descriptions: 'Global theme for components',  
    defaultValue: ThemeKey.Light  
  },  
  version: {  
    name: 'Version',  
    descriptions: 'UI Kit Versions',  
    defaultValue: 'hexa-ui'  
  },  
  locale: {  
    name: 'Locale',  
    descriptions: 'Localization language',  
    toolbar: {  
      icon: 'globe',  
      items: [  
        { value: 'en-us', title: 'English' },  
        { value: 'ru-ru', title: 'Русский' },  
        { value: 'de-de', title: 'Deutsch' },  
        { value: 'ja-jp', title: '日本語' },  
        { value: 'fr-fr', title: 'Français (France)' },  
        { value: 'it-it', title: 'Italiano' },  
        { value: 'es-es', title: 'Español (España)' },  
        { value: 'es-mx', title: 'Español (Mexico)' },  
        { value: 'pt-pr', title: 'Português (Brasil)' },  
        { value: 'tr-tr', title: 'Türkçe' },  
        { value: 'pl-pl', title: 'Polski' },  
        { value: 'ko-kr', title: '한국어' },  
        { value: 'ar-ae', title: 'العربية' },  
        { value: 'kk-kz', title: 'Қазақша' },  
        { value: 'zh-hans', title: '中文(简体)' },  
        { value: 'zh-hant', title: '中文(台灣)' },  
        { value: 'hash-id', title: 'Hash ID' },  
      ],  
      showName: true,  
    },  
  },  
}  
  
const preview: Preview = {  
  decorators: [  
    withI18n,  
    withThemeProvider,  
    withBadges  
  ],  
  argTypes: {  
    componentId: { control: false },  
    dataTestId: { control: false },  
  },  
  parameters: {  
    docs: {  
      container: CustomDocsContainer,  
    },  
    darkMode: {  
      light: { ...themes.light, appBg: themeColors.bg.base.light, brandImage: lightThemeLogo.toString() },  
      dark: { ...themes.dark, appBg: themeColors.bg.base.dark, brandImage: darkThemeLogo.toString() },  
    },  
    controls: {  
      expanded: true,  
      matchers: {  
        color: /(background|color)$/i,  
        date: /Date$/  
      }  
    },  
    badgesConfig  
  },  
  tags: ['autodocs']  
}  
export default preview

It seems that some changes in source-loader between 7.5.2 and 8.1.10 (8.3.3) have led to the current behavior. So here are two questions

  1. Is this a bug or feature? Looks like it should be managed by some parameter (for example showFullSource) for source-loader. If this is a bug, I could and I would like to contribute and help.
  2. Do you have 5-30 minutes for a small call to navigate through the codebase?

@shilman @valentinpalkovic

@SalahAdDin
Copy link

Hey, guys! We've also encountered this issue in 8.3.3, and did a little analysis, here are the results (to clarify, there are screenshots with storysource-addon code below).

1. In 7.5.2 we have `storySource.source` with full file content in story's parameters, this is convenient because in this case we see all scope for the current story. We would like to have this behaviour, at least it should be managed by parameter. **Expected result** ![Image](https://github.com/user-attachments/assets/57997ef6-7ec4-4f29-8e83-2b57ba224e6d)

2. In 8.1.10 we don't have `storySource` and `docs.source.originalSource` properties at all and just see `"loading source..."` in code panel. ![Image](https://github.com/user-attachments/assets/11af16c8-b66c-45d1-a5e0-ce1e7b31ced8)

3. In 8.3.3 we also don't have `storySource` property, and we could work only with `docs.source.originalSource` that just refers to object with arguments for story. This is not convenient especially for basic story (in this case we just have empty object as _code_ for the story). **Actual result** ![Image](https://github.com/user-attachments/assets/1fc71408-fdaa-4aff-8020-34a410a448e5)

Storybook config

const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
import { StorybookConfig } from '@storybook/react-webpack5'

const config: StorybookConfig = {
stories: [
'../docs//.@(mdx|stories.@(ts|tsx))',
'../docs/
.@(mdx|stories.@(ts|tsx))',
'../src/
/*.@(mdx|stories.@(ts|tsx))'
],
addons: [
'@storybook/addon-docs',
'@storybook/addon-essentials',
'@storybook/addon-storysource',
'@storybook/addon-links',
'storybook-dark-mode',
'@storybook/addon-webpack5-compiler-babel'
],
managerHead: () => <style> .css-1wmxdc3, .css-1nwijr1 { margin-right: 0 !important; } .css-1rb1jn6 { max-width: 100% !important; } </style> ,
framework: '@storybook/react-webpack5',
webpackFinal: async (config) => {
if (!config.resolve || !config.module || !config.module.rules) {
return config
}
config.resolve.alias = {
...config.resolve.alias,
'@src': path.resolve(__dirname, '../src/'),
'@design-system': path.resolve(__dirname, '../design-system/'),
'@iCons': path.resolve(__dirname, '../icons/'),
'@helpers': path.resolve(__dirname, '../helpers/'),
'@Style': path.resolve(__dirname, '../style/'),
'@sb': path.resolve(__dirname, '../.storybook/'),
};
config.module.rules.push({
test: /.less$/,
include: [
path.resolve(__dirname, '..'),
path.resolve(__dirname, '..', 'node_modules', 'antd')
],
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
modules: {
mode: 'global',
localIdentName: '[name][local][hash:base64:8]'
},
sourceMap: true
}
},
{
loader: require.resolve('less-loader'),
options: {
lessOptions: {
paths: [path.resolve(__dirname, '..')],
javascriptEnabled: true
}
}
}
]
})

config.resolve.plugins = [  
  ...(config.resolve.plugins || []),  
  new TsconfigPathsPlugin({  
    extensions: config.resolve.extensions  
  })  
]  

return config  

}
}

module.exports = config

preview.ts

import { Preview } from '@storybook/react'
import { badgesConfig } from './badges'
import { withI18n } from './decorators/withI18n'
import { themes } from '@storybook/theming'
import { CustomDocsContainer } from './Docs'
import { withThemeProvider } from './decorators/withThemeProvider'
import { ThemeKey } from '@design-system/types'
import '../style/styles.less'
import { themeColors } from '@design-system/tokens'
import { withBadges } from '@sb/decorators/withBadges'

import lightThemeLogo from './assets/Hexa_UI_Light.svg'
import darkThemeLogo from './assets/Hexa_UI_Dark.svg'

export const globalTypes = {
theme: {
name: 'Theme',
descriptions: 'Global theme for components',
defaultValue: ThemeKey.Light
},
version: {
name: 'Version',
descriptions: 'UI Kit Versions',
defaultValue: 'hexa-ui'
},
locale: {
name: 'Locale',
descriptions: 'Localization language',
toolbar: {
icon: 'globe',
items: [
{ value: 'en-us', title: 'English' },
{ value: 'ru-ru', title: 'Русский' },
{ value: 'de-de', title: 'Deutsch' },
{ value: 'ja-jp', title: '日本語' },
{ value: 'fr-fr', title: 'Français (France)' },
{ value: 'it-it', title: 'Italiano' },
{ value: 'es-es', title: 'Español (España)' },
{ value: 'es-mx', title: 'Español (Mexico)' },
{ value: 'pt-pr', title: 'Português (Brasil)' },
{ value: 'tr-tr', title: 'Türkçe' },
{ value: 'pl-pl', title: 'Polski' },
{ value: 'ko-kr', title: '한국어' },
{ value: 'ar-ae', title: 'العربية' },
{ value: 'kk-kz', title: 'Қазақша' },
{ value: 'zh-hans', title: '中文(简体)' },
{ value: 'zh-hant', title: '中文(台灣)' },
{ value: 'hash-id', title: 'Hash ID' },
],
showName: true,
},
},
}

const preview: Preview = {
decorators: [
withI18n,
withThemeProvider,
withBadges
],
argTypes: {
componentId: { control: false },
dataTestId: { control: false },
},
parameters: {
docs: {
container: CustomDocsContainer,
},
darkMode: {
light: { ...themes.light, appBg: themeColors.bg.base.light, brandImage: lightThemeLogo.toString() },
dark: { ...themes.dark, appBg: themeColors.bg.base.dark, brandImage: darkThemeLogo.toString() },
},
controls: {
expanded: true,
matchers: {
color: /(background|color)$/i,
date: /Date$/
}
},
badgesConfig
},
tags: ['autodocs']
}
export default preview

It seems that some changes in source-loader between 7.5.2 and 8.1.10 (8.3.3) have led to the current behavior. So here are two questions

1. Is this a bug or feature? Looks like it should be managed by some parameter (for example `showFullSource`) for source-loader. If this is a bug, I could and I would like to contribute and help.

2. Do you have 5-30 minutes for a small call to navigate through the codebase?

@shilman @valentinpalkovic

I think it will require a PR.

@raythurnvoid
Copy link

If you are interested for an "hard-coded" workaround that uses docs.source.code check this out:

#12495 (comment)

TLTR: I create a custom addon and show the source code that i generate using LLMs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests