-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Vite: Add partial SvelteKit support #19338
Conversation
@@ -24,8 +25,23 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets | |||
|
|||
plugins.push(svelteDocgen(config)); | |||
|
|||
removeSvelteKitPlugin(plugins); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally this should have been a plugin, but it doesn't seem to have an affect. The plugin correctly removes vite-plugin-svelte-kit
from the config but it doesn't change any behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes unfortunately there's no way to remove plugins from within a plugin, as far as I can tell.
let extraMain; | ||
// svelte.config.js ? | ||
if (fse.existsSync('./svelte.config.js')) { | ||
logger.info("Configuring preprocessor from 'svelte.config.js'"); | ||
|
||
extraMain = { | ||
svelteOptions: { preprocess: '%%require("../svelte.config.js").preprocess%%' }, | ||
}; | ||
} else if (fse.existsSync('./svelte.config.cjs')) { | ||
logger.info("Configuring preprocessor from 'svelte.config.cjs'"); | ||
|
||
extraMain = { | ||
svelteOptions: { preprocess: '%%require("../svelte.config.cjs").preprocess%%' }, | ||
}; | ||
} else { | ||
// svelte-preprocess dependencies ? | ||
const packageJson = packageManager.retrievePackageJson(); | ||
if (packageJson.devDependencies && packageJson.devDependencies['svelte-preprocess']) { | ||
logger.info("Configuring preprocessor with 'svelte-preprocess'"); | ||
|
||
extraMain = { | ||
svelteOptions: { preprocess: '%%require("svelte-preprocess")()%%' }, | ||
}; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as per #19280 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need any MIGRATION.md notes? @JReinhold
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, users needs to remove their svelteOptions
property in main.cjs
and rely on their Vite config to pick them up instead. Svelte+Webpack users probably don't want to remove anything.
I'll write it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about pulling this change out to its own PR? I'd love to get it into the next release, since svelte apps are currently broken after bootstrapping with Storybook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! It'll be great to have sveltekit repros, and getting it working out-of-the-box is an important step to better svelte support!
@@ -24,8 +25,23 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets | |||
|
|||
plugins.push(svelteDocgen(config)); | |||
|
|||
removeSvelteKitPlugin(plugins); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes unfortunately there's no way to remove plugins from within a plugin, as far as I can tell.
return { | ||
...config, | ||
plugins, | ||
}; | ||
}; | ||
|
||
const removeSvelteKitPlugin = (plugins: PluginOption[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still love to find a way to avoid having to do this, since we'll start getting complaints about sveltekit aliases not working (even though there seems to be some debate over whether they should be used at all inside components). But, this seems like a reasonable workaround for now, until we can figure it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, let's continue investigating the core issue and do a follow up to this.
@@ -24,7 +24,7 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets | |||
const removeSvelteKitPlugin = (plugins: PluginOption[]) => { | |||
plugins.forEach((plugin, index) => { | |||
if (plugin && 'name' in plugin && plugin.name === 'vite-plugin-svelte-kit') { | |||
// eslint-disable-next-line no-param-reassign -- we explicitly want to mutate the array as stated in Vite docs | |||
// eslint-disable-next-line no-param-reassign -- we explicitly want to mutate the array as stated here: https://vitejs.dev/guide/api-plugin.html#config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is not in a config
hook, I think we don't necessarily need to follow that rule, but this seems like an okay approach anyway. I normally prefer map and filter, but since this is recursive, that might be a little trickier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Vite docs are a bit unclear on how it's handled when a partial config is returned - they say it is deeply merged into the existing config, which led me to believe it's not usable for removing any entries as we want to achieve here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but those docs are for a plugin. This code is not inside a plugin, it's directly modifying the config that we'll end up passing to vite.createServer()
inside vite-server.ts
. So there's no merging here except for the kind that we do ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah, I hadn't even noticed that.
I have a version that is more declarative, but I'm unsure if it's actually more readable. But I don't have any strong opinions so if you think it's better I'll happily push it.
export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets }) => {
const { plugins = [] } = config;
return {
...config,
plugins: [
// remove SvelteKit plugin
...plugins.map(withoutSvelteKitPlugin),
// Add svelte plugin if not present
!hasPlugin(plugins, 'vite-plugin-svelte') &&
(await import('@sveltejs/vite-plugin-svelte')).svelte(),
// Add docgen plugin
svelteDocgen(config),
].filter(Boolean),
};
};
const withoutSvelteKitPlugin = (plugin: PluginOption): PluginOption => {
if (Array.isArray(plugin)) {
// recursive - Vite plugins can be nested
return plugin.map(withoutSvelteKitPlugin).filter(Boolean);
}
if (plugin && 'name' in plugin && plugin.name === 'vite-plugin-svelte-kit') {
return undefined;
}
return plugin;
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the way you've got it right now is fine I think, and hopefully this is temporary anyway, until we can figure out what's causing the app to load instead of storybook in 7.0.
scripts/sandbox.ts
Outdated
name: 'storybook:allow-template-stories', | ||
config(config) { | ||
if (config?.server?.fs?.allow) { | ||
config.server.fs.allow.push('template-stories'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could also just set server.fs.allow
directly in the config, without needing to use a plugin here. That might even be a good test that such user-configured settings are properly honored, and that .storybook
is being added correctly by the other plugin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I tried that but you actually can't because that won't pick up on other plugin's configs.
So if I set it directly on the config config?.server?.fs?.allow
will be falsy, while doing it through this plugin logic config?.server?.fs?.allow
will actually include vite-plugin-svelte-kit
's allow list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant without the check, you could just set the allow value directly, and then the rest of everything should still work. vite-plugin-svelte-kit
should extend the user's config and the other plugin you created should as well, right? If we can't set custom allow paths in viteFinal
, we're in trouble.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I don't think that I understand what you're saying, so bear with me.
My (verbose explanation of my) logic is:
- If
allow
is empty it will default to allow the whole workspace root, so if we add to an emptyallow
we're effectively denying the rest, which might break stuff for the user. - So we have to check if
allow
is non-empty, before addingtemplate-stories
or other entries anywhere. - checking the content in
allow
directly when building the config is inadequate because some plugins might add entries toallow
, and they won't be checkable at "build config"-time. - but we can check the content in
allow
by adding our own plugin, and from it read the config, and possibly add the entires toallow
.
Which part of the above sounds wrong to you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the plugin is probably the safer approach because it can check whether the user has set server.fs.allow
themselves or not. If we always pass server.fs.allow: ['.storybook']
then we enable that feature which will may break the user's project if they have not added the directories their project uses to the config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this sandbox, we are the user. I'm not talking about setting it in all cases, just in the example sandbox, which is used for testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah, that sounds like the better approach then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, gotcha.
If we always set it in sandboxes then we might as well set it to '.'
because we'd need to allow more than just 'template-stories'
. I'm down with that.
Alternatively 'template-stories'
+ 'src'
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've allowed 'src', 'template-stories', 'node_modules'
which works, but only if sources are always in src
, but at least they were in the react-vite/default-ts
sandbox so I think it's safe to assume.
You're right that this also serves as a good way to test that we're adding .storybook
correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, but I see CI failures like:
Unable to find the Storybook folder in "/tmp/storybook/sandbox/svelte-kit-skeleton-js/.storybook". Are you sure it exists? Or maybe this folder uses a custom Storybook config directory?
Is that because the new repros have not yet been published?
@@ -24,7 +24,7 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets | |||
const removeSvelteKitPlugin = (plugins: PluginOption[]) => { | |||
plugins.forEach((plugin, index) => { | |||
if (plugin && 'name' in plugin && plugin.name === 'vite-plugin-svelte-kit') { | |||
// eslint-disable-next-line no-param-reassign -- we explicitly want to mutate the array as stated in Vite docs | |||
// eslint-disable-next-line no-param-reassign -- we explicitly want to mutate the array as stated here: https://vitejs.dev/guide/api-plugin.html#config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the way you've got it right now is fine I think, and hopefully this is temporary anyway, until we can figure out what's causing the app to load instead of storybook in 7.0.
Yes I think that's probably it, they should work once we merge, or alternatively I can manually publish them - but I'll hold off until Node 16+ is ready in the repo. |
@@ -58,7 +58,7 @@ export const webpack = async (webpackConfig: Configuration, options: PresetOptio | |||
return webpackConfig; | |||
} | |||
|
|||
if(angularOptions.enableNgcc !== false) { | |||
if (angularOptions.enableNgcc !== false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems unrelated to this PR, but I'm guessing it'll fall back out when next
is updated and merged in.
@JReinhold just FYI, it looks like there's a merge conflict |
Now that #19406 is merged, I guess this can be updated to leave the sveltekit plugin in the config, right? |
I've disabled the SvelteKit repro for now because that was the only thing blocking this merge (waiting until we upgrade to node 16). So this should be ready to merge now. @IanVS I'm sorry for the timing, I should have thought of this sooner, before the Vite announcement. |
This looks good, but as far as I know, Maybe we can merge this in, but not advertise sveltekit too hard until we can take care of that part. |
Right, that looks gnarly. This will probably not be the last time facing these issues (hello SolidStart, Astro, Qwik City and Friends), so I wonder if we could think about this in a broader way.. But let's get this in and fix building the Storybook later. |
Awesome, thanks for slogging through and getting this in, @JReinhold! |
@JReinhold FWIW I would call this a |
Issue: #19280
This PR is a first stab at setting up a SvelteKit repro and getting it to work out of the box.
TODO
vite-svelte
framework still worksWhat I did
create-svelte-with-args
sveltePreprocess
option from the template as that was causing ESM vs CJS issues and we decided it was an anti-pattern anyway since they should automatically be picked up by the Vite configvite-plugin-svelte-kit
whenever it is recognised in a Vite config because it conflicts with Storybook's VIte server handling. This has some drawbacks that certain SvelteKit features aren't available in Storybook but for now we consider that a general issue that needs to be solved in SvelteKit.How to test
git checkout origin/jeppe/sb-544-sveltekit
nvm use 16
cd code && yarn generate-repros-next --template svelte-kit/skeleton-js
cd ../sandbox/svelte-kit-skeleton-js && yarn install
yarn storybook
svelte-kit/skeleton-ts
Out of scope
I want to include a few stories based on the Svelte CSF format in the sandbox so CI also ensures that they work. That's another PR.