Open xeho91 opened 1 month ago
Turns out I was wrong before. I am not sure how I made the wrong assumption in my research. I think confused object destructuring & fields renaming, with setting a type. You can actually set a parameter type in snippet's function, e.g.:
{#snippet template({ args, context }: Template<Component>)}
<!-- ... -->
{/snippet}
Using JSDoc:
Full example on how we could use templating, by removing the <Template />
component. At the moment is type-safe by using TypeScript only for now.
<script context="module" lang="ts">
import type { Meta } from '@storybook/svelte';
import Text from './Text.svelte';
/**
* Demonstration on how to use multiple templates in one stories file,
* powered by Svelte's **snippets**.
*/
export const meta: Meta<Text> = {
title: 'Templates',
tags: ['autodocs'],
};
</script>
<script lang="ts">
import { Story, type Template } from '../src/index.js';
</script>
{#snippet template1({ args }: Template<Text>)}
<h2 style="color: lightgreen">Template 1</h2>
<p>{args.text}</p>
{/snippet}
{#snippet template2({ args }: Template<Text>)}
<h2 style="color: fuchsia">Template 2</h2>
<hr>
<p>{args.text}</p>
{/snippet}
<Story
name="Story with template 1"
children={template1}
args={{ text: 'This story uses the first template' }}
/>
<Story
name="Story with template 2"
children={template2}
args={{ text: 'This story uses second template' }}
/>
<Story
name="Custom template"
args={{ text: 'This story uses custom template passed as children' }}
>
{#snippet children({ args })}
<h2 style="color: orange; font-weight: 700;">Custom template</h2>
<hr style="border-style: dashed">
<p>{args.text}</p>
<hr>
{/snippet}
</Story>
Currently the snippet accepts only one argument - which is an object:
export type Template<
Component extends SvelteComponent,
Props = NonNullable<Partial<ComponentProps<Component>>>,
> = {
args: Props;
context: StoryContext<Props>;
};
I'm thinking if this is the good direction?
Because if we'd like to follow the type of known function render(args, storyContext)
function, then in order to obtain the storyContext
only, we would have to write like this:
{#snippet template(_args: Args, context: StoryContext))}
<!-- ... -->
{/snippet}
which is less convenient in the usage. Not to mention it doesn't really do the 'rendering', in my understanding.
This is interesting, I like this.
You don't need to import the Story
and Template
type in a normal script right, you could have done it all in the context="module"
script?
With this setup, if you wanted a static story that doesn't react to args, you could ditch the snippet altogether right? Would be cool.
<Story
name="static template"
>
<h2 style="color: orange; font-weight: 700;">Custom template</h2>
<hr style="border-style: dashed">
<p>some text</p>
<hr>
</Story>
render
function parameters would be better than making it slightly easier to get StoryContext, so I'd say this is better:{#snippet template(args: ComponentProps<MyComponent>, context: StoryContext)}
<!-- ... -->
{/snippet}
It's rare that users need to read the context in a template, so giving them just args is easier for users in 95 % of cases. it's even rarer to not need args and only context, so I don't think we should optimize for that. In fact that used to be what the render
function received, just one big context, but in reality most users just wanted args so it was split up into two parameters back in SB 6 IIRC.
We could perhaps make a helper type for getting the Args
type, which would essentially (for now) just alias to ComponentProps
. Bringing it all together:
<script context="module" lang="ts">
import type { Meta } from '@storybook/svelte';
import { Story, type Args } from '../src/index.js';
import Text from './Text.svelte';
/**
* Demonstration on how to use multiple templates in one stories file,
* powered by Svelte's **snippets**.
*/
export const meta: Meta<Text> = {
title: 'Templates',
tags: ['autodocs'],
};
</script>
{#snippet template1(args: Args<Text>)}
<h2 style="color: lightgreen">Template 1</h2>
<p>{args.text}</p>
{/snippet}
{#snippet template2(args: Args<Text>)}
<h2 style="color: fuchsia">Template 2</h2>
<hr>
<p>{args.text}</p>
{/snippet}
<Story
name="Story with template 1"
children={template1}
args={{ text: 'This story uses the first template' }}
/>
<Story
name="Story with template 2"
children={template2}
args={{ text: 'This story uses second template' }}
/>
<Story
name="Custom template"
args={{ text: 'This story uses custom template passed as children' }}
>
{#snippet children(args)}
<h2 style="color: orange; font-weight: 700;">Custom template</h2>
<hr style="border-style: dashed">
<p>{args.text}</p>
<hr>
{/snippet}
</Story>
Did you find a way to make <Story />
typesafe from just inferring from the children
snippet, or have you just omitted that part here?
Eg. for:
{#snippet template(args: Args<Text>)}
<h2 style="color: fuchsia">Template 2</h2>
<hr>
<p>{args.text}</p>
{/snippet}
<Story
name="Story with template"
children={template}
args={{ text: 'This story uses the first template' }}
/>
Will the args
prop on the story be typesafe based on the Args<Text>
type from the template snippet?
- You don't need to import the
Story
andTemplate
type in a normal script right, you could have done it all in thecontext="module"
script?
I haven't had a chance to update the parser by the time you asked this question. I've removed completely parsing of the "instance" which is the normal <script>
tag in the svelte file, and moved it to "module" parsing aka <script context="module">
.
- With this setup, if you wanted a static story that doesn't react to args, you could ditch the snippet altogether right? Would be cool.
<Story name="static template" > <h2 style="color: orange; font-weight: 700;">Custom template</h2> <hr style="border-style: dashed"> <p>some text</p> <hr> </Story>
That's correct! The property children
is optional.
At the moment, this is the way how it works:
<Story>
has nested children, it will use nested children<Story>
has {children}
prop, it will use the template from this snippetsetTemplate(snippet)
was used in the Stories file, then the <Story>
will use the template set by setTemplate
via Svelte context.
- I think being consistent with the core
render
function parameters would be better than making it slightly easier to get StoryContext, so I'd say this is better:{#snippet template(args: ComponentProps<MyComponent>, context: StoryContext)} <!-- ... --> {/snippet}
Alright, no problem. I'll save it on the TODO list. EDIT: β
It's rare that users need to read the context in a template, so giving them just args is easier for users in 95 % of cases. it's even rarer to not need args and only context, so I don't think we should optimize for that. In fact that used to be what the
render
function received, just one big context, but in reality most users just wanted args so it was split up into two parameters back in SB 6 IIRC.We could perhaps make a helper type for getting the
Args
type, which would essentially (for now) just alias toComponentProps
. Bringing it all together:<script context="module" lang="ts"> import type { Meta } from '@storybook/svelte'; import { Story, type Args } from '../src/index.js'; import Text from './Text.svelte'; /** * Demonstration on how to use multiple templates in one stories file, * powered by Svelte's **snippets**. */ export const meta: Meta<Text> = { title: 'Templates', tags: ['autodocs'], }; </script> {#snippet template1(args: Args<Text>)} <h2 style="color: lightgreen">Template 1</h2> <p>{args.text}</p> {/snippet} {#snippet template2(args: Args<Text>)} <h2 style="color: fuchsia">Template 2</h2> <hr> <p>{args.text}</p> {/snippet} <Story name="Story with template 1" children={template1} args={{ text: 'This story uses the first template' }} /> <Story name="Story with template 2" children={template2} args={{ text: 'This story uses second template' }} /> <Story name="Custom template" args={{ text: 'This story uses custom template passed as children' }} > {#snippet children(args)} <h2 style="color: orange; font-weight: 700;">Custom template</h2> <hr style="border-style: dashed"> <p>{args.text}</p> <hr> {/snippet} </Story>
Will it be a problem if this Args
type helper will conflict with the type Args
from @storybookjs/svelte
?
EDIT:
I've created temporary TArgs<Meta>
and TContext<Meta>
helper types
I couldn't get rid of the idea you planted in my mind, by making defineMeta
instead.
It's possible and it works on examples so far - I'll test on my hobby project tomorrow.
There's the recent example (includes templating as well) :
<script context="module" lang="ts">
import { defineMeta, type TArgs } from '../src/index.js';
import Text from './Text.svelte';
/**
* Demonstration on how to use multiple templates in one stories file,
* powered by Svelte's **snippets**.
*/
const { Story, meta } = defineMeta({
title: 'Templates',
component: Text,
tags: ['autodocs'],
args: { text: "" },
argsTypes: {
text: { control: "text" },
},
});
</script>
{#snippet template1(args: TArgs<typeof meta>)}
<h2 style="color: lightgreen">Template 1</h2>
<p>{args?.text}</p>
{/snippet}
{#snippet template2(args: TArgs<typeof meta>)}
<h2 style="color: fuchsia">Template 2</h2>
<hr>
<p>{args?.text}</p>
{/snippet}
<Story
name="Story with template 1"
children={template1}
args={{ text: 'This story uses the first template' }}
/>
<Story
name="Story with template 2"
children={template2}
args={{ text: 'This story uses second template' }}
/>
<Story name="Static template">
<h2 style="color: aqua">Static template</h2>
<hr>
<p>{"Static template."}</p>
</Story>
<Story
name="Custom template"
args={{ text: 'This story uses custom template passed as children' }}
>
{#snippet children(args)}
<h2 style="color: orange;font-weight: 700;">Custom template</h2>
<hr style="border-style: dashed">
<p>{args?.text}</p>
<hr>
{/snippet}
</Story>
At the moment I found one gotcha. The linters (TypeScript, ESLint or Biome) will point out that there's unused meta
destructured from the defineMeta({ ... })
expression call.
Is not really "unused", at least not in the final output after parsing the *.stories.file
(via Vite's code transformation). meta
is used as argument in parser - collect-stories
.
export const
- mehzimmerframe
), where it will automatically destructure meta
. Right during the transformation of the *.stories.svelte
file, and passing it forward for stories collecting.Did you find a way to make
<Story />
typesafe from just inferring from thechildren
snippet, or have you just omitted that part here?Eg. for:
{#snippet template(args: Args<Text>)} <h2 style="color: fuchsia">Template 2</h2> <hr> <p>{args.text}</p> {/snippet} <Story name="Story with template" children={template} args={{ text: 'This story uses the first template' }} />
Will the
args
prop on the story be typesafe based on theArgs<Text>
type from the template snippet?
Last time I checked - (I need to double/triple/multiple π confirm it again) - if the template had incorrect types, then TypeScript was showing me error on the children={template}
prop passed to <Story />
Will it be a problem if this
Args
type helper will conflict with the typeArgs
from@storybookjs/svelte
?
Hmm I don't think so, as long as the user doesn't import both. The user could be confused about which package to import the types from, but I'm not sure there's a way around that.
defineMeta
I do think it's confusing from a user's perspective that the meta
property is unused. "Why do I need to destructure it?"
Exporting it is the least magical, but also more verbose than it needs to be. If we just omitted meta
entirely, then the mental model would be that defineMeta
is not just a type-helper, but an actual factory function that will set the meta when called. I think that's a fine mental model for the user.
Then we'd have to extract the content and export it default in the parser to make SB happy.
And the types for the snippet would then be snippet(args: Args<typeof Story>)
Will it be a problem if this
Args
type helper will conflict with the typeArgs
from@storybookjs/svelte
?Hmm I don't think so, as long as the user doesn't import both. The user could be confused about which package to import the types from, but I'm not sure there's a way around that.
defineMeta
I do think it's confusing from a user's perspective that the
meta
property is unused. "Why do I need to destructure it?" Exporting it is the least magical, but also more verbose than it needs to be. If we just omittedmeta
entirely, then the mental model would be thatdefineMeta
is not just a type-helper, but an actual factory function that will set the meta when called. I think that's a fine mental model for the user. Then we'd have to extract the content and export it default in the parser to make SB happy.And the types for the snippet would then be
snippet(args: Args<typeof Story>)
Totally agreed on the mental model. I refactored the vite plugin, and split into two:
pre-transform
- transforms the original source code, to see if meta
was destructured - if not, then transform the codepost-transform
- it adds the appendix to the source code, and removes the previous default export <ComponentName>
, because AFAIK Storybook internally expects export default meta
.Following the feedback, there's an updated example:
<script context="module" lang="ts">
import { defineMeta, type Args } from '../src/index.js';
import Text from './Text.svelte';
/**
* Demonstration on how to use multiple templates in one stories file,
* powered by Svelte's **snippets**.
*/
const { Story } = defineMeta({
title: 'Templates',
component: Text,
tags: ['autodocs'],
args: { text: "" },
argsTypes: {
text: { control: "text" },
},
});
</script>
{#snippet template1(args: Args<typeof Story>)}
<h2 style="color: lightgreen">Template 1</h2>
<p>{args?.text}</p>
{/snippet}
{#snippet template2(args: Args<typeof Story>)}
<h2 style="color: fuchsia">Template 2</h2>
<hr>
<p>{args?.text}</p>
{/snippet}
<Story
name="Story with template 1"
children={template1}
args={{ text: 'This story uses the first template' }}
/>
<Story
name="Story with template 2"
children={template2}
args={{ text: 'This story uses second template' }}
/>
<Story name="Static template">
<h2 style="color: aqua">Static template</h2>
<hr>
<p>{"Static template."}</p>
</Story>
<Story
name="Custom template"
args={{ text: 'This story uses custom template passed as children' }}
>
{#snippet children(args)}
<h2 style="color: orange;font-weight: 700;">Custom template</h2>
<hr style="border-style: dashed">
<p>{args?.text}</p>
<hr>
{/snippet}
</Story>
meta
anymore, the vite plugin transform will handle the case even if it was destructured alreadyTArgs
to Args
and from TContext
to StoryContext
typeof Story
- Args<typeof Story>
& StoryContext<typeof Story>
Great work! This is really starting to look promising, like something we can prerelease and gather feedback on.
What's left to do here?
What's left to do here?
Apart from the obvious need to update the documentation, and the tests. I'll list separate issue in each comment of what is not seen in the code changes, and the rest I'll make comments on where I need the help.
A warning appears while running the Storybook (command pnpm storybook
):
[!WARNING] The CJS build of Vite's Node API is deprecated. See https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.
Using VITE_CJS_TRACE=true
to debug:
I can't figure out whether the issue lies on the Storybook's internal configuration of Vite or the addon.
Build breaks (command pnpm build
), without the workaround - see the bottom of this comment.
What I know:
zimmerframe
is an ESM-only package.svelte-package
is somehow(?) trying to import this package as CJS format. I can't locate the options/settings on where I can change this behaviour.Might be(?) related to this issue: https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2129023551
This is what I do to not get blocked on further development of this addon
./node_modules/zimmerframe/package.json
"exports": {
".": {
"types": "./types/index.d.ts",
- "import": "./src/walk.js"
+ "default": "./src/walk.js"
}
},
Vite CJS warning
This is a limitation of Storybook. Currently, Storybook loads any presets (like main.ts, or addon presets) with esbuild-register in a way that compiles them to CJS, which triggers this warning. The workaround is to turn any Vite imports in presets to dynamic imports, because those will stay as import('vite') instead of require('vite'). So the imports defined in pre-transform.ts and post-transform.ts needs to be dynamic imports within the functions.
Build breaks (command pnpm build)
I think you confused yourself (and me π ) here a bit. I tried it out, it's not the build command that's failing, it's build-storybook, which makes sense given it's a Storybook build error being thrown. This is the exact same problem as above, however this is the first time that I've experienced this "forced" CJS becoming a real problem beyond Vite's warning.
I've pushed commits that fixes both issues above.
However now building Storybook throws a new error from Rollup:
I haven't looked into this yet, but it seems like we or Svelte 5 is transforming the stories files to invalid syntax, possibly only when in build/rollup mode.
EDIT Resolved! β
`, 1); var root_2 = $.template(`
`, 1); var Story_default = $.template(`
`, 1); var root_3 = $.template(`
{\"Static template.\"}
"},"Custom template":{"id":"CustomTemplate","name":"Custom template","rawSource":"{args?.text}
\n`, 1), Templates_stories.filename, [[26, 2], [27, 2]]); var root_2 = $.add_locations($.template(`
`, 1), Templates_stories.filename, [[31, 2], [32, 2], [33, 2]]); var Story_default = $.add_locations($.template(`
`, 1), Templates_stories.filename, [[49, 2], [50, 2], [51, 2]]); var root_3 = $.add_locations($.template(`
{\"Static template.\"}
"},"Custom template":{"id":"CustomTemplate","name":"Custom template","rawSource":"{args?.text}
\nI'm close, damn it! π
I've created a test snippet: https://github.com/storybookjs/addon-svelte-csf/blob/experimental-support-svelte-v5/test/compile.ts
It almost gives me what I need.
Currently the output from the initial test file: https://github.com/storybookjs/addon-svelte-csf/blob/experimental-support-svelte-v5/src/parser/extract/compiled/nodes.test.ts
... is:
mark_module_start();
Virtual_stories.filename = "/@virtual:vite-plugin-virtual/virtual:stories.svelte";
function Virtual_stories($$anchor, $$props) {
if (new.target === Virtual_stories) throw new Error("Instantiating a component with `new` is no longer valid in Svelte 5. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more information");
push($$props, false, Virtual_stories);
const { Story } = defineMeta();
init();
bind_prop($$props, "Story", Story);
return pop({
get Story() {
return Story;
},
...legacy_api()
});
}
mark_module_end(Virtual_stories);
Which is close to what I need in order to produce tests for the functions related to compiled AST & transformation.
I've encountered one blocker for further parsing/analysing the AST. The output didn't include the imports at all.
I'm talking about:
import { defineMeta } from "@storybook/addon-svelte-csf";
// ... rest of the compiled code
And I ran out of ideas how to get it included in the compiled output. Perhaps some of vite's plugin is missing(?), or we need to include vite plugins from Storybook?
Perhaps the imports are treeshaken out? Have you tried with a more real-life example, where you use context="module"
and actually define a <Story/>
?
Perhaps the imports are treeshaken out? Have you tried with a more real-life example, where you use
context="module"
and actually define a<Story/>
?
Good thought, totally forgot about context="module"
! Slight progress. Changing entry to:
<script context="module">
import { defineMeta } from "@storybook/addon-svelte-csf";
export const { Story } = defineMeta();
</script>
<Story name="Default" />
and adding treeshake: false
to rollupOptions
:
... outputs:
mark_module_start();
Virtual_stories.filename = "/@virtual:vite-plugin-virtual/virtual:stories.svelte";
const { Story } = defineMeta();
function Virtual_stories($$anchor, $$props) {
if (new.target === Virtual_stories) throw new Error("Instantiating a component with `new` is no longer valid in Svelte 5. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more information");
push($$props, false, Virtual_stories);
init();
var fragment = comment();
var node = first_child(fragment);
validate_component(Story)(node, { name: "Default" });
append($$anchor, fragment);
return pop({ ...legacy_api() });
}
mark_module_end(Virtual_stories);
What changed as expected:
const { Story } = defineMeta();
... got moved outside the function.
But still, import { defineMeta } from "@storybookjs/addon-svelte-csf"
not included.
Currently we're using svelte-package
to build this addon. I've explored this package source: https://github.com/sveltejs/kit/tree/main/packages/kit
I don't see a way how we can use glob pattern or any similar option to omit tests files from being included in the build output.
*.test.ts
from ./src/
to ./test/
directoryvite
for building - using the lib
option, and include *.svelte
files without being compiled - as in produce the same results as svelte-package
do right nowCurrently we're using
svelte-package
to build this addon.
I came to the same conclusion. Let's just separate tests into their own files like it was 2022 π Not a big deal, not worth the effort trying to change our bundling system.
- HTML comments above
<Story>
component, which are supposed to be automatically inserted intoparameters.docs.description.story
doesn't work
Good catch!
- Property
source
- e.g.<Story source="code..." />
doesn't work either
Don't worry about this for now, I have an alternative solution to the whole Source Code situation. π
Source snippet generation is pretty broken, always producing <StoryRenderer allTheArgs... />
.
This is because we're relying on SB core's built in source generator, which isn't clever enough to understand this syntax. it basically does some string concatenation like <COMPONENT_NAME ARGS_AS_ATTRIBUTES... />
.
The stable version of this addon is a bit more clever at extracting the source snippets, but we've disabled/removed that in this branch, and it wouldn't work with the new template/snippet syntax anyway, but we can draw inspiration from it:
For starters, I think we can remove the source
prop on Story
.
And then I want to explore this flow:
X.stories.svelte
file.Our Vite plugin currently transforms after Svelte has compiled the files. There might be a built-in way in the Vite API to get the original source in our transform
-hook, but if not, we could either:
A. Read the source from the file system directly. This probably wouldn't work with virtual files (is that even a use case?), and it could be a bit slow. This is what this addon currently does at https://github.com/storybookjs/addon-svelte-csf/blob/0c31f56cbe0595b6c2a07b5f1188d6493f504aff/src/plugins/vite-svelte-csf.ts#L25-L28
B. Add a pre
plugin, where all it does is store the source to a resolve id -> source
map, that our post
plugin can then read from and do whatever it want with.
This is the tricky part. I'm not sure if we should do this with the AST and string positions, or just with raw string parsing. I see multiple cases we need to support, ranked here from simplest to most complex:
Similar to what we do in the "create appendix" logic now, I think we can add these extracted source snippets as variables to the compiled output, so they can be read at runtime. I don't yet know what the exact structure should be for this, but I don't think that's too crucial.
These strings then need to be passed down to the StoryRenderer
as props here https://github.com/storybookjs/addon-svelte-csf/blob/0b0e5c41da873d72d9d04a2d94b0ce9d21e84dd7/src/runtime/create-runtime-stories.ts#L51-L59
Eg. given the string
<MyComponent {...args} somethingElse={args.someArg}>
<h2>A header</h2>
</MyComponent>
It should expand current args
to
<MyComponent myProp="A" other={false} somethingElse={42}>
<h2>A header</h2>
</MyComponent>
There are also some edge cases, eg. if a snippet references a variable from somewhere else like the instance script, we can't expand that to be what it actually is. I don't think we should aim to support that right out the gate, There is always the transform
parameter that users can use to fix this in their use case.
And then we emit the final string to the SB channel.
We can draw inspiration from https://github.com/storybookjs/storybook/blob/4bd5ef3549a514a60ad0683df5fb85896895a92c/code/renderers/svelte/src/docs/sourceDecorator.ts#L101-L136
Step 2 is definitely the hardest part and I think I could use your help there @xeho91 with your AST expertise. The rest of the steps looks pretty straightforward to me.
hello, can we test the module published on npmjs like 5.0.0--canary.181.04f02dc.0
it seems to fail early on my end. What should be the other dependencies of storybook ?
@benoitf thanks for trying it out! We're hoping it's ready for broader feedback soon.
Which error are you getting? It should work if you follow the version requirements listed here: https://github.com/storybookjs/addon-svelte-csf/blob/experimental-support-svelte-v5/README.md#latest
@JReinhold here is the error I got (it's about loading src files while there is only a dist folder in the published npmjs module)
$ storybook build
@storybook/cli v8.1.11
info => Cleaning outputDir: storybook-static
info => Loading presets
SB_CORE-SERVER_0002 (CriticalPresetLoadError): Storybook failed to load the following preset: ./.storybook/main.ts.
Please check whether your setup is correct, the Storybook dependencies (and their peer dependencies) are installed correctly and there are no package version clashes.
If you believe this is a bug, please open an issue on Github.
SB_CORE-SERVER_0002 (CriticalPresetLoadError): Storybook failed to load the following preset: node_modules/@storybook/addon-svelte-csf/dist/preset.js.
Please check whether your setup is correct, the Storybook dependencies (and their peer dependencies) are installed correctly and there are no package version clashes.
If you believe this is a bug, please open an issue on Github.
Error: Cannot find module 'node_modules/@storybook/addon-svelte-csf/src/compiler/transform/shared/description.ts'
at createEsmNotFoundErr (node:internal/modules/cjs/loader:1181:15)
at finalizeEsmResolution (node:internal/modules/cjs/loader:1169:15)
at Module._resolveFilename (node:internal/modules/cjs/loader:1106:16)
at Module._resolveFilename (node_modules/esbuild-register/dist/node.js:4799:36)
at Module._load (node:internal/modules/cjs/loader:985:27)
at Module.require (node:internal/modules/cjs/loader:1235:19)
at require (node:internal/modules/helpers:176:18)
at Object.<anonymous> (node_modules/@storybook/addon-svelte-csf/dist/compiler/transform/story/insert-description.js:37:26)
at Module._compile (node:internal/modules/cjs/loader:1376:14)
at extensions..js (node_modules/esbuild-register/dist/node.js:4845:15)
at loadPreset (node_modules/@storybook/core-common/dist/index.js:12:59)
at loadPreset (node_modules/@storybook/core-common/dist/index.js:12:59)
at async Promise.all (index 2)
at async loadPresets (node_modules/@storybook/core-common/dist/index.js:12:483)
at async getPresets (node_modules/@storybook/core-common/dist/index.js:12:1503)
at async buildStaticStandalone (node_modules/@storybook/core-server/dist/index.js:36:3268)
at async withTelemetry (node_modules/@storybook/core-server/dist/index.js:40:3599)
at async build (node_modules/@storybook/cli/dist/generate.js:705:1409)
at async Command.<anonymous> (node_modules/@storybook/cli/dist/generate.js:708:150)
WARN Failed to load preset: {"type":"presets","name":"node_modules/@storybook/addon-svelte-csf/dist/preset.js"} on level 1
Error: Cannot find module 'node_modules/@storybook/addon-svelte-csf/src/compiler/transform/shared/description.ts'
at createEsmNotFoundErr (node:internal/modules/cjs/loader:1181:15)
at finalizeEsmResolution (node:internal/modules/cjs/loader:1169:15)
at Module._resolveFilename (node:internal/modules/cjs/loader:1106:16)
at Module._resolveFilename (node_modules/esbuild-register/dist/node.js:4799:36)
at Module._load (node:internal/modules/cjs/loader:985:27)
at Module.require (node:internal/modules/cjs/loader:1235:19)
at require (node:internal/modules/helpers:176:18)
at Object.<anonymous> (node_modules/@storybook/addon-svelte-csf/dist/compiler/transform/story/insert-description.js:3:246)
at Module._compile (node:internal/modules/cjs/loader:1376:14)
at extensions..js (node_modules/esbuild-register/dist/node.js:4845:15)
error Command failed with exit code 1.
it comes from https://github.com/storybookjs/addon-svelte-csf/blob/04f02dc3dc1ec0e656586be3f233cfd72e23d65a/package.json#L17-L19
replacing it by "#*": "./dist/*.js"
I made progress
Thanks for the fix @benoitf β€οΈ. I added a "source"
import condition to be used internally, because the dist
map would cause the "Go To Definition" functionality to go to .d.ts
files instead of the source files which were quite annoying. Can you check that it still works on your end?
@JReinhold I confirm your fix is better and it's still working on my end π
Hi, FYI with more recent versions of svelte5, (updating from 5.0.0-next.164 to 5.0.0-next.174) I'm now receiving the error
node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24
CompileError: `p` has already been declared
$ storybook build
@storybook/cli v8.1.11
info => Cleaning outputDir: storybook-static
info => Loading presets
info => Building manager..
info => Manager built (182 ms)
info => Building preview..
WARN No story files found for the specified pattern: src/stories/**/*.mdx
vite v5.3.3 building for production...
./sb-common-assets/fonts.css doesn't exist at build time, it will remain unchanged to be resolved at runtime
transforming...
The TypeScript option verbatimModuleSyntax is now required when using Svelte files with lang="ts". Please add it to your tsconfig.json.
x Build failed in 1.16s
β 101 modules transformed.
=> Failed to build the preview
[vite-plugin-svelte] [plugin vite-plugin-svelte] ../node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte (12:24): /home/runner/work/podman-desktop/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24 `p` has already been declared
file: /home/runner/work/podman-desktop/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24
CompileError: `p` has already been declared
at e (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/errors.js:61:8)
at Module.declaration_duplicate (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/errors.js:130:2)
at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:98:6)
at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:88:24)
at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:88:24)
at VariableDeclaration (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:490:34)
at visit (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:121:13)
at next (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:63:23)
at create_block_scope (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:[28](https://github.com/containers/podman-desktop/actions/runs/9806646693/job/27078814364?pr=7959#step:7:29)0:3)
at visit (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:121:13)
attention => Storybook now collects completely anonymous telemetry regarding usage.
This information is used to shape Storybook's roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://storybook.js.org/telemetry
Hi, FYI with more recent versions of svelte5, (updating from 5.0.0-next.164 to 5.0.0-next.174) I'm now receiving the error
node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24 CompileError: `p` has already been declared
$ storybook build @storybook/cli v8.1.11 info => Cleaning outputDir: storybook-static info => Loading presets info => Building manager.. info => Manager built (182 ms) info => Building preview.. WARN No story files found for the specified pattern: src/stories/**/*.mdx vite v5.3.3 building for production... ./sb-common-assets/fonts.css doesn't exist at build time, it will remain unchanged to be resolved at runtime transforming... The TypeScript option verbatimModuleSyntax is now required when using Svelte files with lang="ts". Please add it to your tsconfig.json. x Build failed in 1.16s β 101 modules transformed. => Failed to build the preview [vite-plugin-svelte] [plugin vite-plugin-svelte] ../node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte (12:24): /home/runner/work/podman-desktop/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24 `p` has already been declared file: /home/runner/work/podman-desktop/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:12:24 CompileError: `p` has already been declared at e (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/errors.js:61:8) at Module.declaration_duplicate (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/errors.js:130:2) at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:98:6) at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:88:24) at Scope.declare (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:88:24) at VariableDeclaration (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:490:34) at visit (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:121:13) at next (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:63:23) at create_block_scope (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/svelte/src/compiler/phases/scope.js:[28](https://github.com/containers/podman-desktop/actions/runs/9806646693/job/27078814364?pr=7959#step:7:29)0:3) at visit (file:///home/runner/work/podman-desktop/podman-desktop/node_modules/zimmerframe/src/walk.js:121:13) attention => Storybook now collects completely anonymous telemetry regarding usage. This information is used to shape Storybook's roadmap and prioritize features. You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL: https://storybook.js.org/telemetry
From the error trace, it doesn't look like there's an issue on our side. I can be wrong. Does it fails as well, when you downgrade version down to 172? There's also latest one 174.
For now, I can't upgrade version to the latest one, because there were some breaking changes to the types of svelte/compiler
(since version 165). I've reached out to maintainers on Discord to find a solution.
Let me know if your issue still persist in other versions than 173 π
with 172 it was the same error (see the log trace) https://github.com/containers/podman-desktop/actions/runs/9777005225/job/26990739363
it's a FYI if you already saw this.
5.0.0--canary.181.17d1807.0
Ok, so I've tried to reproduce the error in two places:
174
)In both, I've cleaned cache, and I'm not getting this error π€ I'll dive in into your repository to see if I can reproduce locally.
Alright, I was able to reproduce in your repository on my machine.
I've managed to narrow it down by modifying Story.svelte
inside node_modules/
.
It breaks when destructuring ...restProps
: https://github.com/storybookjs/addon-svelte-csf/blob/17d18078bf20ae36e526ddf73a19e4fc4ef58aca/src/runtime/Story.svelte#L70
However, this case is way too complicated to introduce to Svelte maintainers. For now I can't figure out a simple case to reproduce this issue.
Using Svelte 5 REPL didn't help. I suspect it be problem with @sveltejs/vite-plugin-svelte
optimization part. Because its the one who gives the following error which I was able to reproduce. And using dev mode, there's a little more info:
The TypeScript option verbatimModuleSyntax is now required when using Svelte files with lang="ts". Please add it to your tsconfig.json.
β [ERROR] /Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:6:24 `p` has already been declared [plugin vite-plugin-svelte:optimize-svelte]
../node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:6:0:
6 β
β΅ ^
The plugin "vite-plugin-svelte:optimize-svelte" was triggered by this import
../node_modules/@storybook/addon-svelte-csf/dist/index.js:2:27:
2 β import StoryComponent from './runtime/Story.svelte';
β΅ ~~~~~~~~~~~~~~~~~~~~~~~~
/Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/@storybook/cli/bin/index.js:23
throw error;
^
Error: Build failed with 1 error:
../node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:6:24: ERROR: [plugin: vite-plugin-svelte:optimize-svelte] /Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:6:24 `p` has already been declared
at failureErrorWithLog (/Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/vite/node_modules/esbuild/lib/main.js:1472:15)
at /Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/vite/node_modules/esbuild/lib/main.js:945:25
at /Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/vite/node_modules/esbuild/lib/main.js:1353:9
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
errors: [Getter/Setter],
warnings: [Getter/Setter]
}
Node.js v20.12.2
βELIFECYCLEβ Command failed with exit code 7.
I'll highlight the most important part, so I can investigate it further later on.
[!CAUTION] ERROR: [plugin: vite-plugin-svelte:optimize-svelte] /Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/@storybook/addon-svelte-csf/dist/runtime/Story.svelte:6:24
p
has already been declared at failureErrorWithLog (/Users/xeho91/Nextcloud/Projects/oss/podman-desktop/node_modules/vite/node_modules/esbuild/lib/main.js:1472:15)
Thanks @xeho91 for the investigation π
Credits
Additional goals
Resources
Breaking changes
webpack
- See discussion https://github.com/storybookjs/storybook/discussions/27092<Meta />
component<Template />
component in favor of Svelte snippets<Story />
components no longer has a propautodocs
, usetags={['autodocs']}
instead<Story />
components no longer has a propsource
, we've revamped the behaviour< v7.4
New features
defineMeta({ ... })
- works in TypeScript and with JSDocsetTemplate
to allow adding a default{#snippet children()}
to all of the<Story>
in the stories file.Args<typeof Story>
andStoryContext<typeof Story>
to get typings while creating Svelte v5 snippets outside the<Story />
TODO
indexer.ts
- it uses Svelte AST fromsvelte.compile
to extract the data required for indexerestree-walker
tozimmerframe
,modernAst
option in thesvelte.compile
<Meta>
and<Template>
component<Story>
to use Svelte 5 featurescontext
to use Svelte 5 runes instead ofwritable()
stories/
source
in componentStory
, see: https://github.com/storybookjs/addon-svelte-csf/pull/181#discussion_r1614834092 and comment: https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2143539873./ERRORS.md
(below are the error categories):PARSER_EXTRACT_SVELTE
PARSER_EXTRACT_COMPILED
PARSER_ANALYSE_DEFINE_META
PARSER_ANALYSE_STORY
./examples/
directoryMIGRATION.md
guideREADME.md
CHANGELOG.md
with migration guide, new prerequisites and breaking changesIssues
Legend:
Related to tests
π‘ Tests emit error that the components should userender
fromsvelte/render
instead ofmount
- I'm not sure how to deal with this one yet. Perhaps using environment variableTEST
?π‘ Related to above. It seems we can't usesetContext
during the tests - we used' therender
instead ofmount
, it will break while runningvitest
, AFAIK.@storybook/vite-builder
&@storybook/svelte-vite
). Based the compiled output, I want to test the snippets which analyse/extract AST nodes from the compiled output. To see if creating appendix to the compiled output works as expected.Related to runtime
Actions
tab doesn't work, I couldn't figure out whether is related to the breaking change thaton:*
should be replaced withon*
(removed colon)Typings forargs
used in{#snippet children(args)}
- no idea yet how to crack this oneSetting thelayout
in export meta parameters is brokenImporting thezimmerframe
fails due tovite
not being able to getexports
correctly - current workaround to continue developing: manual overrideimport
todefault
in./node_modules/zimmerframe/package.json
.π΄ Inserting HTML comments as description &<Story>
doesn't work in the development mode - see: https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2143379765Related to TypeScript
π‘ Stories with requiredchildren
snippet, and not being explicitly set. See comment: https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2130744977π‘ https://github.com/storybookjs/addon-svelte-csf/pull/181#issuecomment-2132124184π¦ Published PR as canary version:
5.0.0--canary.181.168fccb.0
:sparkles: Test out this PR locally via: ```bash npm install @storybook/addon-svelte-csf@5.0.0--canary.181.168fccb.0 # or yarn add @storybook/addon-svelte-csf@5.0.0--canary.181.168fccb.0 ```