storybook icon indicating copy to clipboard operation
storybook copied to clipboard

Sveltekit aliased imports support

Open madeleineostoja opened this issue 3 years ago β€’ 19 comments

Describe the bug The new @storybook/svelte setup breaks when you try and integrate with Sveltekit, because it relies on using aliased imports generated at runtime like $app/env.

I tried adding these aliases to webpack directly, eg:

webpackFinal: async (config) => {
    config.resolve.alias = {
      ...config.resolve?.alias,
      $app: path.resolve(__dirname, '../.svelte-kit/dev/runtime/app')
    };
    return config;
  }

But then I get parsing errors, I assume because it's an ES module and storybook needs to transpile it

File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|  */
| 
> var browser = !import.meta.env.SSR;

System

System:
    OS: macOS 11.2.1
    CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
  Binaries:
    Node: 15.9.0 - /usr/local/bin/node
    Yarn: 1.22.4 - ~/.yarn/bin/yarn
    npm: 7.5.3 - /usr/local/bin/npm
  Browsers:
    Chrome: 90.0.4430.212
    Firefox: 74.0
    Safari: 14.0.3
  npmPackages:
    @storybook/addon-actions: ^6.2.9 => 6.2.9 
    @storybook/addon-essentials: ^6.2.9 => 6.2.9 
    @storybook/addon-links: ^6.2.9 => 6.2.9 
    @storybook/addon-svelte-csf: ^1.0.0 => 1.0.0 
    @storybook/svelte: ^6.2.9 => 6.2.9 

Additional context I imagine using the upcoming pluggable builders with Vite (with ES build support, which sveltekit uses under the hood) might fix this issue, but I couldn't get the alpha storybook-vite-builder working either.

madeleineostoja avatar May 17 '21 00:05 madeleineostoja

FWIW also opened an issue for this in Svelte/kit because it sounds like it might need a solution upstream, unless there's something about webpack aliases and storybook's babel runtime I'm missing https://github.com/sveltejs/kit/issues/1485

madeleineostoja avatar May 27 '21 01:05 madeleineostoja

@j3rem1e any chance you can take a quick look?

shilman avatar May 27 '21 03:05 shilman

vite/snowpack uses 'import.meta', which is not supported by webpack 4.

Sadly, webpack5 supports 'import.meta' but not 'import.meta.env' . You should probably mock '$app/env' (ie, aliasing $app/env to a file you own), or try to use the vite-builder.

svelte-kit is more and more dependent of vite.

j3rem1e avatar May 27 '21 19:05 j3rem1e

@j3rem1e can we figure out how to get it running in @storybook/builder-vite

https://github.com/eirslett/storybook-builder-vite/issues/16

shilman avatar May 28 '21 01:05 shilman

ah that makes sense then. Mocking all the runtime imports of sveltekit ($app/env is just one) would probably be more work than its worth, especially if getting the vite builder running smoothly would fix it. I think as long as hardcoded aliases to the .svelte-kit files that are generated during dev work that's a reasonable gotcha β€” you'd have to have had run svelte-kit dev before storybook will work, I remember a similar limitation with Gatsby shimming back in the day. We can just document those aliases, there'd be 4 of them ($app/env, $app/navigation, $app/paths, $app/stores)

madeleineostoja avatar May 28 '21 02:05 madeleineostoja

@madeleineostoja Ooh those aliases sound like a good workaround! I think we can get the vite builder working, but I suspect it will be awhile before that is officially supported, and in the meantime it would be good to have a solution for webpack. Any chance you can help add that?

shilman avatar May 28 '21 04:05 shilman

By the sounds of it webpack 5 won’t support the full import.meta.* that sveltekit uses though? The runtime aliases have that syntax, that was the original issue unfortunately. So it sounds like vite will be the only reasonable answer for now

madeleineostoja avatar May 28 '21 06:05 madeleineostoja

FYI seems the problem with the vite builder is addon-svelte-csf depending on webpack https://github.com/eirslett/storybook-builder-vite/issues/16#issuecomment-855219901

madeleineostoja avatar Jun 07 '21 04:06 madeleineostoja

I can confirm that with @storybook/[email protected], [email protected], and @storybook/[email protected] this is now fixed πŸŽ‰

You can add a manual alias to Sveltekit's runtime modules in viteFinal and they work, with the caveat being that you have to have had run sveltekit dev previously.

module.exports = {
  core: { builder: 'storybook-builder-vite' },
  async viteFinal(config) {
    config.resolve.alias = {
      $app: path.resolve('./.svelte-kit/dev/runtime/app'),
    };

    return config;
  }
};

I think this is worth documenting somewhere, probably in the docs for @storybook/svelte, because sveltekit is the biggest use case for storybook + svelte, and it's broken out of the box currently. Hopefully the svelte team comes up with a more robust way to consume those runtime modules outside of sveltekit, but for now this workaround is at least fairly transparent, and I remember doing similar things with Gatsby and Storyboook so πŸ€·β€β™€οΈ

madeleineostoja avatar Jun 16 '21 05:06 madeleineostoja

@jonniebigodes @j3rem1e can you two please figure out the best way to document this? it's weird because SvelteKit depends on vite community builder, which is not part of core. But we're going to have to figure this out and I don't want to lose more Svelte users.

shilman avatar Jun 16 '21 12:06 shilman

Also just in case you wanted to document the other option for the runtime aliases, this would be the path based on sveltekit build

path.resolve('./.svelte-kit/build/runtime/app')

If you used ^ you'd probably want to make your storybook run script

svelte-kit build && start-storybook

Might be a better default for documentation, doesn't have the gotcha of having to have had run sveltekit dev recently

madeleineostoja avatar Jun 17 '21 05:06 madeleineostoja

Not sure if this was ever documented. However, just got this working and thought I'd share the slight tweaks that have probably come up in last few months:

  • Needed to pin the dependency: [email protected]. Newer versions appear not to handle main.cjs well? Only looks for main.js.
  • Needed to add an additional configuration option for vite:
config.server.fsServe.strict = false;
config.server.fsServe.allow = ['.'];          // <~ new

For everything else, following along with what @madeleineostoja 's did here works well.

Nothing spectacular but it did take some time to work out the right set of tweaks! Oh well.

michaelwooley avatar Sep 21 '21 21:09 michaelwooley

cc @eirslett @IanVS ☝️

shilman avatar Sep 21 '21 23:09 shilman

Newer versions appear not to handle main.cjs well? Only looks for main.js.

Hmmm, that seems odd. Would you be willing to open an issue in https://github.com/eirslett/storybook-builder-vite with the details of what you are seeing, @michaelwooley?

IanVS avatar Sep 22 '21 01:09 IanVS

A way to work around the issue is to mock the functions yourself.

If the component uses import {goto} from $app/navigation

I created a .storybook/app/navigation.js file and exported the goto function:

export function goto() {
  console.log("hello storybook trying to call goto but we mocked it.");
}

Then we can link the $app alias to the .storybook app folder by adding this to the webpack4 config:

config.resolve.alias = {
...
  $app: path.resolve(__dirname, '../.storybook/app/')
...

Full webpack config:

  webpackFinal: async (config) => {
    config.module.rules.push({
      test: [/\.stories\.js$/, /index\.js$/],
      use: [require.resolve('@storybook/source-loader')],
      include: [path.resolve(__dirname, '../src')],
      enforce: 'pre'
    });
    config.resolve.alias = {
      ...config.resolve.alias,
      $lib: path.resolve(__dirname, '../src/lib'),
      $app: path.resolve(__dirname, '../.storybook/app/')
    };
    return config;
  },

At least this solution will allow you to run a storybook and create the components with webpack 4.

nielsvandermolen avatar Jan 27 '22 13:01 nielsvandermolen

https://github.com/michaelwooley/storybook-experimental-vite demonstrates setting up Storybook with the new vite.config.js, which fixes $app/env

benmccann avatar Jul 06 '22 17:07 benmccann

$app/env is now well supported by adding the SvelteKit Vite plugin in viteFinal. I've been looking at the other SvelteKit aliases and, as a novice Storybook user, I'm not sure what if anything we should do to support them. My first inclination is that if your components are well-structured you would not need to use any of these aliases. E.g. a generic button component wouldn't need to navigate, but could accept an action that would result in navigation.

Do folks have use cases for the other aliases besides $app/env that they can describe?

benmccann avatar Jul 08 '22 16:07 benmccann

My first inclination is that if your components are well-structured you would not need to use any of these aliases. E.g. a generic button component wouldn't need to navigate, but could accept an action that would result in navigation.

I think that's a fairly broad and opinionated assumption. Taking your own example of a button that needs in-app navigatation, unless you're distributing that component as part of a consumable design system, making app navigation a seperate action on every instance of that button sounds a lot more like a workaround for these kind of issues than a good design pattern. It's like saying you should always pass react router's Link component as a prop rather than just using it in your app's components directly.

In any case $app/navigation is a trivial example, something like $app/stores is more problematic, where components can and absolutely should access global Sveltekit state directly, since that's the point of global state.

Tbh I've seen this kind of rationale a bunch of times from the Svelte team in different discussions and it irks me β€” "what you're all doing that svelte can't support right now is bad practice, do it our way". Idk just feels off, and very different from just flagging that something doesn't work for x technical reason and has y as a workaround/alternate pattern

madeleineostoja avatar Jul 10 '22 09:07 madeleineostoja

$app/env is now well supported by adding the SvelteKit Vite plugin in viteFinal.

The $app/env example seems to be broken again with the latest sveltekit (1.0.0-next.481)... the import appears to have been moved to $app/environment https://kit.svelte.dev/docs/modules#$app-environment. I would've expected the same alias configuration to work as outlined above:

// .storybook/main.js
module.exports = {
  //...
  async viteFinal(config, { configType }) {
    config.resolve.alias = {
      $app: path.resolve("./.svelte-kit/runtime/app"),
    };
    return config;
  },
};

But with this we get the following error, that the module can't be found:

Could not load .svelte-kit/runtime/app/environment (imported by src/components/_shared/Blog/Preview/Preview.svelte): 
ENOENT: no such file or directory, open '.svelte-kit/runtime/app/environment'

jamesjwarren avatar Sep 14 '22 10:09 jamesjwarren

This should be supported in Storybook 7.0 using the sveltekit framework (@storybook/sveltekit), right @JReinhold?

IanVS avatar Jan 10 '23 00:01 IanVS

I'd have guessed it's blocked by https://github.com/storybookjs/storybook/pull/20239?

benmccann avatar Jan 10 '23 00:01 benmccann

Most aliases are now supported out-of-the-box with the latest Storybook 7. You can see a summary of what is supported and not supported here: https://github.com/storybookjs/storybook/tree/next/code/frameworks/sveltekit

There are a few that are not yet supported and make more sense to support as mocks. I've created a new issue to track that: https://github.com/storybookjs/storybook/issues/20999. PRs for it would be very welcome!

benmccann avatar Feb 07 '23 21:02 benmccann