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]: Vue3 sourcecode does not reflect given template #30331

Open
KevinCarnaille2 opened this issue Jan 21, 2025 · 7 comments
Open

[Bug]: Vue3 sourcecode does not reflect given template #30331

KevinCarnaille2 opened this issue Jan 21, 2025 · 7 comments

Comments

@KevinCarnaille2
Copy link

Describe the bug

When editing stories, sometimes you need to create your own template from the setup function, to inject big content into slots (which contain subcomponents).
It was working for me with the v8.2.9, but after the migration (currently 8.5.0) nothing is working as expected.

The only code output I have is the name of the component, its args if given, and that's it.
To be honest I'm quite surprised, because there is no specific configuration/context to reproduce it. It's directly reproducible from a fresh project.

Is there anything new since the 8.4.0 ? Do we have to use only args with named slots into it to render our slots and have the right code snippet ? It doesn't work anyway when tryin to render other Vue components into it, from a basic string.

Thanks !

Reproduction link

None

Reproduction steps

  1. Create a new storybook project, from scratch in an empty directory: npx [email protected]
  2. Select @storybook/vue3-vite from the prompt
  3. Run the storybook locally
  4. Edit the Button example component (src/stories/Button.vue) generated by default, and add a default slot
  5. Change the story of the Button component, to use the setup system like following :
export const Primary: Story = {
  render: (args: any) => ({
    components: { Button },
    setup() {
      return { args };
    },
    template: 'Test',
  }),
  args: {
    primary: true,
    label: 'Button',
  },
};

The code snippet should render "Test" only, but it does not.
I only have

<template>
  <Button :primary="false" />
</template>

Image

System

Storybook Environment Info:
  Binaries:
    Node: 18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node
    npm: 9.6.7 - ~/.nvm/versions/node/v18.17.1/bin/npm
    pnpm: 8.7.5 - ~/.nvm/versions/node/v18.17.1/bin/pnpm <----- active
  Browsers:
    Chrome: 131.0.6778.204
  npmPackages:
    @storybook/addon-essentials: 8.5.0 => 8.5.0 
    @storybook/addon-interactions: 8.5.0 => 8.5.0 
    @storybook/addon-onboarding: 8.5.0 => 8.5.0 
    @storybook/blocks: 8.5.0 => 8.5.0 
    @storybook/test: 8.5.0 => 8.5.0 
    @storybook/vue3: 8.5.0 => 8.5.0 
    @storybook/vue3-vite: 8.5.0 => 8.5.0 
    storybook: 8.5.0 => 8.5.0

Additional context

No response

@shilman
Copy link
Member

shilman commented Jan 22, 2025

@larsrickert do you know what's going on here?

@larsrickert
Copy link
Contributor

@KevinCarnaille2 @shilman Thats indeed a current limitation of our implementation since render functions are not supported yet.

I can try to find time to take a look at this :)

@KevinCarnaille2
Copy link
Author

ok thank you @larsrickert !
But I'm surprised because it used to work for years (since the v7, even v6 if I remember well)

Is there any workaround for this ? There are some good features in the latest versions.

@larsrickert
Copy link
Contributor

larsrickert commented Jan 22, 2025

ok thank you @larsrickert ! But I'm surprised because it used to work for years (since the v7, even v6 if I remember well)

Is there any workaround for this ? There are some good features in the latest versions.

There was a full re-write of the Vue source code generator in #27194 which has a lot of improvements, especially for generating code for slots and v-models.

Whats your use case for the custom render function? I guess originally this was needed to pass slot content which is no longer necessary because you can pass them directly as arg:

export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
    mySlot: h(MyCustomComponent, { propA: "Hello World" })
    myOtherSlot: "I am just a string slot"
  },
};

As workaround, you can define the code snippet manually like so:

export const Primary: Story = {
  parameters: {
    docs: {
      source: {
        code: "<div> My custom source code </div>",
      },
    },
  },
};

@KevinCarnaille2
Copy link
Author

ok thank you @larsrickert ! But I'm surprised because it used to work for years (since the v7, even v6 if I remember well)
Is there any workaround for this ? There are some good features in the latest versions.

There was a full re-write of the Vue source code generator in #27194 which has a lot of improvements, especially for generating code for slots and v-models.

Whats your use case for the custom render function? I guess originally this was needed to pass slot content which is no longer necessary because you can pass them directly as arg:

export const Primary: Story = {
args: {
primary: true,
label: 'Button',
mySlot: h(MyCustomComponent, { propA: "Hello World" })
myOtherSlot: "I am just a string slot"
},
};
As workaround, you can define the code snippet manually like so:

My need is to be able to use slots containing other Vue components without using the H renderer, like for example :

export const Primary: Story = {
  render: (args: any) => ({
    components: { VueComponent, AnotherVueComponent },
    setup() {
      return { args };
    },
    template: `
         <VueComponent v-bind="args">
            <AnotherVueComponent>Another component</AnotherVueComponent>
         </VueComponent>
    `,
  }),
  args: {
    primary: true,
    label: 'Button',
  },
};

@larsrickert
Copy link
Contributor

My need is to be able to use slots containing other Vue components without using the H renderer, like for example:

tl;dr: I agree that custom render function templates should be considered in the source code but for you concrete use case, the render function is the wrong way and you should use the h function for the slot content.

More detailed explanation

Why can't you use the h function? Due to technical limitations, it is not fully possible to generate source code snippets when custom render functions are passed. For the exact use case that you are describing (using custom components for slots), using the h method is the recommended and intended way.

Another big advantage of this is that your story is fully type safe. So props, slots etc. will be fully typed which is not the case if you pass in a custom render function with a simple string template.

For you example, you can simply define the story like this and the source code will be generated accordingly with very good support for nested component props and slots:

export const Primary: Story = {
  args: {
    label: "Button",
    primary: true,
    default: h(
      AnotherVueComponent,
      {
        // optionally pass props for the component
      },
      "Another slot content"
    ),
  },
};

The generated source code will be:

<template>
  <VueComponent label="Button" primary>
    <AnotherVueComponent> Another slot content </AnotherVueComponent>
  </VueComponent>
</template>

@KevinCarnaille2
Copy link
Author

ok !
Thank you @larsrickert I'll try to migrate my impacted stories with the right convention then !
Maybe I've missed something, but is it explicitly documented ?

I'll get back to you if I face some issues.

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

3 participants