storybookjs / storybook

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

[Bug]: Unable to abstract the CSF Default Export with a function #21703

Closed jimmy-e closed 1 year ago

jimmy-e commented 1 year ago

Describe the bug

Hi, I want to abstract the CSF default export object for Storybook, like below:

metaFunction.js

export const getMeta = (title, component) => ({
  title: `Example/${title}`,
  component: component,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: { control: 'color' },
  },
});

Button.stories.js:

import { Button } from './Button';
import { getMeta } from './metaFunction';

// This works 👇
// const meta = {
//   title: 'Example/Button',
//   component: Button,
//   tags: ['autodocs'],
//   argTypes: {
//     backgroundColor: { control: 'color' },
//   },
// };

// This doesn't 👇
const meta = getMeta('Button', Button);

export default meta;

export const Primary = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary = {
  args: {
    label: 'Button',
  },
};

export const Large = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

The problem is that when I use the getMeta function, Storybook crashes with the error "CSF: missing default export". It seems like I must declare an object and cannot abstract it at all, or even use a spread object inside the initial meta object.

Is there any way to abstract the CSF default export object with a function?

To Reproduce

Go to this repo and the function_debug branch, run npm install and then npm run storybook.

System

`^7.0.0-rc.5`

Additional context

No response

giniedp commented 1 year ago

this holds us back from upgrading to Storybook 7 and CSF 3

shilman commented 1 year ago

This is an intentional change. I've updated the code to make the error a little more descriptive: #22190

SB7 statically analyzes the story files for performance reasons and we can't statically analyze functions. You'll need to rewrite your default exports if you've written functions to generate them -- we should have been more explicit about disallowing this kind of code in earlier Storybook versions, but unfortunately that ship has sailed. The performance benefits of the new approach greatly outweigh the costs, so I don't expect this to change in future versions of Storybook.

Closing this for now!

giniedp commented 1 year ago

with this feature flag i was able to keep my old abstraction

  features: {
    storyStoreV7: false, // 👈 Opt out of on-demand story loading
  },

https://storybook.js.org/docs/angular/configure/overview#on-demand-story-loading

@shilman is that the way to go? Or is it a side effect? Another way is to export the minimal structure that is needed for the static analyzer and then augment the object with custom code later. But that is ugly and weird.

I understand the performance benefits, but i dislike the idea of being forced to a certain code format. I need to wrap the stories with a custom DSL to reduce some boilerplate code and add typesafety.

shilman commented 1 year ago

Whoopee!! I just released https://github.com/storybookjs/storybook/releases/tag/v7.1.0-alpha.8 containing PR #22190 that references this issue. Upgrade today to the @future NPM tag to try it out!

npx sb@next upgrade --tag future
shilman commented 1 year ago

Jeepers creepers!! I just released https://github.com/storybookjs/storybook/releases/tag/v7.0.7 containing PR #22190 that references this issue. Upgrade today to the @latest NPM tag to try it out!

npx sb@latest upgrade
dmitry-stepanenko commented 11 months ago

Storybook becomes more and more verbose without a need. We have a lot of configurations that we want to abstract, a simple wrapper for the Meta could do it. Please bring this functionality back or at least make it optional. For me it's totally fine to sacrifice some of the performance gains in favour of much better DX

localusercamp commented 11 months ago

Storybook becomes more and more verbose without a need.

Absolutely agree, this is just SO rediculous...

StarDust198 commented 10 months ago

Any news on this? Wanted to wrap our stories in a helper too and got same error..

dmitry-stepanenko commented 9 months ago

Any news on this? Wanted to wrap our stories in a helper too and got same error..

There's a workaround, that works for now

const meta: CosMeta = { 
  title: 'Required Title',
  ...your props
};
cosMeta(meta);
export default meta;

export const Primary = cosStory();

Basically we mutate the statically defined meta object in. place using cosMeta function. All cos-prefixed interfaces and utils from the example are our custom ones.

smhutch commented 5 months ago

Tried to upgrade Storybook, and now I need to update 160+ files to remove a carefully crafted abstraction.

@shilman the error message we're showing here still isn't helpful. I am returning an object from the function that I added to add type-safety and other guardrails.

frank-topel-dbi commented 2 months ago

@shilman Your performance optimizations should really be configurable in this regard. This comes really unexpected and makes it much harder if not impossible to simply automate generation of stories using proper abstractions!