storybook: Error: CSF: missing default export

Using 6.4.0-beta.27.

This may not be a bug? Writing stories in separate files and re-exporting them from a single file yields the error:

Error: CSF: missing default export


To Reproduce

Re-export stories from a single file. Example:

import { Panel } from '../Panel';

export default {
  title: 'components/Panel/props',
  component: Panel,
};

export { Active } from './active.story';
export { Attach } from './attach.story';
export { Resizable } from './resizable.story';

System

  System:
    OS: macOS 11.6
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
  Binaries:
    Node: 14.17.3 - ~/.nvm/versions/node/v14.17.3/bin/node
    Yarn: 1.22.4 - ~/.yarn/bin/yarn
    npm: 6.14.13 - ~/.nvm/versions/node/v14.17.3/bin/npm
  Browsers:
    Chrome: 95.0.4638.69
    Firefox: 93.0
    Safari: 15.0
  npmPackages:
    @storybook/addon-a11y: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/addon-essentials: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/addon-postcss: ^2.0.0 => 2.0.0 
    @storybook/addon-storysource: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/builder-webpack5: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/components: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/manager-webpack5: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/react: 6.4.0-beta.27 => 6.4.0-beta.27 
    @storybook/theming: 6.4.0-beta.27 => 6.4.0-beta.27 

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 2
  • Comments: 20 (7 by maintainers)

Most upvoted comments

@shilman Is it not possible to evaluate the default export while statically analyzing the CSF module? We get dramatic DX imporvements by using this tiny helper for defining type safe meta/stories.

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

export function storyFactory<
  C extends keyof JSX.IntrinsicElements | JSXElementConstructor<any> = never,
>(Component: C, metaPrams: Omit<Meta<C>, 'component'>) {
  return {
    meta: {
      ...(metaPrams ?? {}),
      component: Component,
    },
    story: (args: StoryObj<ComponentProps<typeof Component>>) => args,
  };
}

example usage:

import {storyFactory} from 'storybook-utils';

import {MyComponent} from './MyComponent';

const {meta, story} = storyFactory(MyComponent, {
  // define component level meta properties
  decorators: [],
  args: {}
});

// type safe stories
export const Default = story({
  args: {
    allConnectionsAssigned: false,
  },
});

export default meta;

Is there a reason why this should not be supported? As long as a function returns an object with valid meta properties, who cares how it is defined?

I had the same problem, took me a while to realize I had to set storyStoreV7: false I think the storybook docs should elaborate on this, as the current description for the storyStoreV7 flag is “Configures Storybook to load stories on demand, rather than during boot up.” which doesn’t really mention this problem. Also, reading further into the article, it very vaguely mentions limitations in csf.

hi @seanmcintyre! Thanks for filing this. Can you share your main.js config as well (specifically the features field)?

Starting in 6.4 we’re statically analyzing the structure of CSF and this structure is not currently supported by the analysis. I need to think about whether/how to support it–it’s technically possible, but may have some limitations. And if we choose not to support it, we should have a lot clearer error message.

@NiklasPor We’ll have a legacy mode so you can still use old code in V7. However, we’re seeing dramatic performance improvements coming from the on-demand store + lazy compilation in webpack5, so in order to benefit from those you’ll need to update your code.

@nagromLobo CSF is based on ES modules exporting objects with a particular API

That said, there are limitations. Due to implementation details, there are certain things we don’t support. For example, the following is valid ESM:

const bar = 'bar';
export default { title: `foo/${bar}` }

However, we can’t statically analyze that. So instead, you’d need to write it as:

export default { title: "foo/bar" }

We’ve tried to encode some of these constraints into linting rules: https://github.com/storybookjs/eslint-plugin-storybook

The issue is still present in version v7.0.0-rc.7 though I’m actually using default export in the component

export default {
  title: 'Components/Tabs/Static',
  component: VfTabs,
  args: {
    tabs: ['tab 1', 'tab 2', 'tab 3']
  },
  argTypes: {
    variant: {
      control: false
    },
    default: {
      control: false,
      description: 'Default slot for sections of tabs'
    }
  }
} as unknown as Meta

To get storybook to play nice with typescript and our components we wrote some utils to generate the default export / individual stories. This suggests to me that that wouldn’t be recommended. Practically I’m not seeing any problems (v6.4.21), though this makes me think that our storybook could run into issues in the future because we implemented this under the assumption that storybook was consuming runtime ES modules.

We did exactly the same as you did @nagromLobo, we have custom helper functions that wrap the CSF syntax and have additional requirements (zeplinUrl, … which need to be provided.

I guess the implementations based on runtime interpretation will break in V7? (Also we’re using Angular Storybook, so we added some more quality of life features like a NgModule which can be passed directly)