storybook: [Bug]: Storybook 7.5.3 -> Type [component] is part of the declarations of 2 modules: [module] and StorybookComponentModule!

Describe the bug

I’m migrating our solution from mdx (1.x) stories to a new modern way (using stories.ts files).

My first attempt is to migrate a few stories about external customized components (es Kendo Components) to straightforward stories.

So basically I have a story like:

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

import { DropDownListComponent, DropDownListModule } from '@progress/kendo-angular-dropdowns';

// More on how to set up stories at: https://storybook.js.org/docs/angular/writing-stories/introduction
const meta: Meta<DropDownListComponent> = {
  title: 'Kendo/DropDownList',
  component: DropDownListComponent,
  decorators: [
    moduleMetadata({
      imports: [DropDownListModule]})
  ],
  tags: ['autodocs'],
  render: (args: DropDownListComponent) => ({
    props: {
      ...args,
    },
  })
};

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

// More on writing stories with args: https://storybook.js.org/docs/angular/writing-stories/args
export const Normal: Story = {
  args: {
    data: ['X-Small', 'Small', 'Medium', 'Large', 'X-Large', '2X-Large']
  },
};

Unfortunately, I got the error: Error: Type DropDownListComponent is part of the declarations of 2 modules: DropDownListModule and StorybookComponentModule! Please consider moving DropDownListComponent to a higher module that imports DropDownListModule and StorybookComponentModule. You can also create a new NgModule that exports and includes DropDownListComponent then import that NgModule in DropDownListModule and StorybookComponentModule.

To Reproduce

Please clone repo:

https://github.com/meriturva/Storybook2ModulesError

just run: npm run storybook and go to page: http://localhost:6006/?path=/docs/kendo-dropdownlist--docs

System

No response

Additional context

The same issue is already described:

https://github.com/storybookjs/storybook/issues/23669 https://github.com/storybookjs/storybook/issues/22282 https://github.com/storybookjs/storybook/issues/19289

but no one in version 7.5x

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Comments: 16 (10 by maintainers)

Most upvoted comments

I think I see the problem, but I would need to debug further to know if this can be fixed, without affecting the more common use case.

You are creating a story for a dependency’s component, which is not what Storybook expects. Storybook expects you to be adding stories for your project’s components. Storybook iterates the NgModules, to see if you imported a module that already declared the component, when creating the Story’s NgModule, so the Story’s NgModule doesn’t declare it a second time. Without looking into it more, I don’t know why, but the reflection utility that is parsing the metadata is returning the declarations as declarations: [[DropDownListComponent]] for DropDownListModule and Storybook is expecting declarations: [DropDownListComponent]. I will take a look and see if we can update the code that searches for declarations to handle components from dependencies, but Storybook isn’t expecting users to document external dependencies components. Even if the multiple declarations error is fixed, you still won’t get any of the benefits, such as auto-generated controls for inputs and actions for outputs, since that info is parsed from the source files.

This is typically is solved by using the dependency component in a component from your project, like dependencies should be used.

Workaround if you still want to do it directly, even though I don’t recommend it: You are probably missing out on most of the benefits of specifying a component in your Meta that isn’t from your sources, since the types data is currently gathered by compodoc and it isn’t generating for anything in node_modules. So, you could exclude the component property and just render the component yourself.

The following is how I made your code work:

// NOTE: I also added `import '@angular/localize/init';` to the top of `preview.ts`, but I am not using localize in my projects, so I don't know if that is how that should be done.

const meta: Meta<DropDownListComponent> = {
  title: 'Kendo/DropDownList',
  // NOTE: The component property is expecting a component from your project.
  // component: DropDownListComponent,
  decorators: [
    // NOTE: The component was expecting animations module to be added so I also added this, also.
    applicationConfig({
      providers: [
        provideAnimations(),
      ],
    }),
    moduleMetadata({
      imports: [DropDownListModule]
    }),
    // You could pass a template string to this function or set the `template` property
    // in the render function's return, also, if you need more control.
    componentWrapperDecorator(DropDownListComponent)
  ],
  tags: ['autodocs'],
  render: (args: DropDownListComponent) => ({
    props: {
      ...args,
    },
  })
};

@meriturva The class property should be excluded in the first story, because the class property is undefined in args. In your case, you are passing args and without class defined the function has no way of knowing about it. Even if the property was known, such as the prop being in the includes option, the following line is where it would be filtered out: https://github.com/storybookjs/storybook/blob/837936a2b258fdc4a095c67b4d1c0fb9304cb5d1/code/frameworks/angular/src/client/argsToTemplate.ts#L64

That sort of limitation is why I haven’t actually switched to argsToTemplate in my project, yet. I had started working on a smarter implementation a few years ago, but never finished it. I sort of felt like I was overthinking the problem, but I started using it again last weekend and I am trying to come up with something using more than just the args and is still simple to use. My implementation has different limitations that I want to try and avoid before I would propose it as a solution, though, so I wouldn’t say I have something better, yet.

The error is resolved together with the initial Angular problem. Storybook 7.6.0-alpha.5 will incorporate the changes as soon as it is released