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

Framework support - Stencil.js #4600

Closed
maraisr opened this issue Oct 28, 2018 · 156 comments
Closed

Framework support - Stencil.js #4600

maraisr opened this issue Oct 28, 2018 · 156 comments

Comments

@maraisr
Copy link
Contributor

maraisr commented Oct 28, 2018

Describe the solution you'd like
I'd like to see Stencil.js support, as I see Storybook to be very component focused, and Stencil being a very component focus framework - these tools would compliment each other very well.

Are you able to assist bring the feature to reality?
yes, I can...

@igor-dv
Copy link
Member

igor-dv commented Oct 29, 2018

Duplicate to #1870 and #3423. Let's continue a discussion there

@Edd-Strickland
Copy link

New Starter build for Current stencil and SB 5 to be created

@ndelangen
Copy link
Member

@Edd-Strickland want to work on a stencl support version 🎉

@Edd-Strickland
Copy link

I've upgraded the polymer starter with stencil to the latest version of SB need some help in removing polymer and adding in stencil complier now

@vogloblinsky
Copy link

Hi,

@Edd-Strickland just for information, i have implemented Stencil inside Storybook like you did in your starter, in this project : https://github.com/vogloblinsky/nutrition-web-components

I have used the HTML starter of Storybook.

For now with Storybook & Stencil, i just had to :

  • add a custom header pointing to each root JavaScript file generated by Stencil
  • add static files generated by Stencil in Storybook

The main problem i think is the usage of Webpack by Storybook to handle JavaScript files imported inside a story. The ideal workflow is to only imported the JS file of the Web Component.

@Edd-Strickland
Copy link

Yeah this is what have done previously but with the polymer version however what this means is that by importing as plain static W/C implementations is you need to update each time into your story's which feels limiting.

@nisheed2440
Copy link

Hi All, I have created a wrapper that can be installed on a stencil component type project. Hope it helps. https://github.com/nisheed2440/stencil-storybook-wrapper

@Edd-Strickland
Copy link

looks really good I'll test on Monday. Good work :)

@o-t-w
Copy link

o-t-w commented Feb 13, 2019

Will this be made into an official part of Storybook? I have a desperate need for this!

@ndelangen
Copy link
Member

@o-t-w We're trying, would you be able to help us?

@o-t-w
Copy link

o-t-w commented Feb 14, 2019

@ndelangen I would be happy to test things and provide feedback/bug reports.

@o-t-w
Copy link

o-t-w commented Feb 20, 2019

Would this work with LitElement (and web components in general) or just Stencil?

@Nightbr
Copy link

Nightbr commented Mar 6, 2019

@nisheed2440 your wrapper seems promising, I will test this soon! But it could be great to have a "native" integration documented by Storybook 👌

@Edd-Strickland
Copy link

@nisheed2440 I have been very busy(sorry everyone) but have had a very small window today to test a very vanilla version of this locally and it's really good. works really well.

going to spend some time on this next week trying to incorporate it into an existing project to see how this might work for existing stencil users / projects.

@Nightbr
Copy link

Nightbr commented Mar 7, 2019

I have tested it this morning and it works pretty well too! GJ it's really easy to setup. I have installed and tested some addons:

import '@storybook/addon-backgrounds/register';
import '@storybook/addon-knobs/register';
import '@storybook/addon-actions/register';
import '@storybook/addon-notes/register';

Everything works fine, just found one issue with addon-knobs #5017 But there is a workaround and this should be fixed pretty soon I think.

NEO97online referenced this issue in silverstone/components Mar 13, 2019
@popcorn245
Copy link

I spent the last 2 weeks playing with StencilJS and Storybook and did a livestream where I cover my solution. I feel there is a much better way, but I was able to get HMR, and most plugins to work with little issue. Would love any feedback you guys have on how to improve or import the loaders from the distribution stencil bundle.

https://www.youtube.com/watch?v=XwHtPw3izLE

And here is the repo! ^_^
https://github.com/MadnessLabs/enjin-components

@ghaiat
Copy link

ghaiat commented Mar 22, 2019

@nisheed2440 Hello, i m using an approach very similar to yours and everything is working expect chromatic. were you able to make chromatic work with stencil/storybook?
when i run, it does discover all my stories but all the screenshots are empty. it s probably missing the stencil when trying to render the component screenshot on chromatic server

@dougestey
Copy link

@nisheed2440 Thank you so much for this really great effort. Hopefully this gives the team here a head start in the right direction. Stencil and Storybooks are ideal for each other.

@stale
Copy link

stale bot commented Apr 18, 2019

Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!

@stale stale bot added the inactive label Apr 18, 2019
@shilman
Copy link
Member

shilman commented Apr 19, 2019

Anybody want to pick this up?

@stale stale bot removed the inactive label Apr 19, 2019
@ghost
Copy link

ghost commented Apr 29, 2019

My team is using StencilJS + Storybook for our common component library and I'd love to contribute. Maybe a few of us can get this thing back on track...

@shilman
Copy link
Member

shilman commented Apr 29, 2019

Seems like there's a lot of interest, e.g. https://twitter.com/dboskovic/status/1120336958008348672

One easy win would be publishing a @storybook/preset-stencil package which packages @popcorn245 's config into a storybook preset. I still need to finish off the docs for that, but I'm using it for the upcoming Storybook Docs release and it's straightforward & how most SB config will work in the future.

I'd be happy to guide anybody who wants to pick that up.

@marcolanaro
Copy link

@Sebosek did you tried with tsx or jsx files? I had problems with tsx files but with jsx it's working fine

Great question, I did not try with tsx. I will not have much time to investigate in the next few weeks, but please let me know if you solve it for this scenario 😊

@Sebosek
Copy link

Sebosek commented Jul 21, 2021

@DominicPieper, unfortunatelly, I've already removed the story as I was playing with it around :(
However I wanted to prepare a sample repo to demonstrate my problem, but suddenly this repo works as expected.
I'm not sure, what differs, gonna investigate, I had to make some configuration mistake, or something similar. Sorry for bothering @marcolanaro and thanks all for the help!

@DominikPieper
Copy link

@marcolanaro I'll spend some time at the weekend. Until now, everything I tried failed with just no stories visible

@marcolanaro
Copy link

A first milestone would be to run stories writing jsx so to render them in stencil.
A complete solution would include compiling stencil components through storybook.

I have a PR open for the first one. The only drawbacks are:

  1. you need to run npm run build:watch and npm run storybook separately.
  2. while editing stories leverage stencil HMR, editing components for the moment forces full refresh.

Here's my PR:
https://github.com/storybookjs/storybook/pull/15479/files

In the mean time you can hack around and configure it standalone using @storybook/html.
In preview.js define the following decorator:

import { renderVdom, registerHost, getHostRef, h } from '@stencil/core/internal/client';

import { defineCustomElements } from '../dist/esm/loader';

defineCustomElements();

const rootElement = document.getElementById('root');
const storyRoot = document.createElement('div');
rootElement.parentElement.appendChild(storyRoot);

registerHost(storyRoot, { $flags$: 0, $tagName$: 'story-root' })
const hostRef = getHostRef(storyRoot);

export const decorators = [
  (Story) => {
    renderVdom(hostRef, Story());
    return '<div />';
  }
];

In main.js define babel plugin:

  babelDefault: (config) => {
    return {
      ...config,
      plugins: [
        ...config.plugins,
        [require.resolve('@babel/plugin-transform-react-jsx'), { pragma: 'h' }, 'preset'],
      ],
    };
  }

Write your story like:

import { h } from '@stencil/core';

export default {
  title: 'Welcome',
};

export const Default = () => {
  return (
    <container-component>
      <div>Header</div>
      <div><data-component richData={{ foo: 'bar' }}></data-component></div>
      <div>Footer</div>
    </container-component>
  )
};

Ok, I've done some more investigations and looked into the compiler. I can now run only storybook, no need for a separate build:watch script.
Storybook will load only the components used in the story and compile them using stencil compiler.

In main.js you should have something like this:

const path = require('path');

module.exports = {
  webpack: (config, options) => {
    return {
      ...config,
      module: {
        ...config.module,
        rules: [
          ...config.module.rules,
          {
            test: /\.(tsx)$/,
            loader: path.resolve('./.storybook/loader.js'),
          },
        ],
      },
    };
  },
  babelDefault: (config) => {
    return {
      ...config,
      plugins: [
        ...config.plugins,
        [require.resolve('@babel/plugin-transform-react-jsx'), { pragma: 'h' }, 'preset'],
      ],
    };
  }
}

In loader.js you will have:

const stencil = require('@stencil/core/compiler');

module.exports = function(source) {
  const callback = this.async();
  const compiled = stencil.transpileSync(source);
  callback(null, compiled.code)
}

So now you can avoid depending on the stencil build in preview.js:

import { renderVdom, registerHost, getHostRef, h } from '@stencil/core/internal/client';

const rootElement = document.getElementById('root');
const storyRoot = document.createElement('div');
rootElement.parentElement.appendChild(storyRoot);

registerHost(storyRoot, { $flags$: 0, $tagName$: 'story-root' })
const hostRef = getHostRef(storyRoot);

export const decorators = [
  (Story) => {
    renderVdom(hostRef, Story());
    return '<div />';
  }
];

And the story will look something like this:

import { h } from '@stencil/core';

import './ContainerComponent';
import './DataComponent';

export default {
  title: 'Welcome',
};

export const Default = () => {
  return (
    <container-component>
      <div>Header</div>
      <div><data-component richData={{ foo: 'bar' }}></data-component></div>
      <div>Footer</div>
    </container-component>
  )
};

I'm sure there is still plenty of work to do and plenty of scenarios to address, but I think this is a great step forward.
Can someone please try it out? We can then move forward with #15479 :)

@shilman
Copy link
Member

shilman commented Aug 16, 2021

@marcolanaro I'd love to discuss how to move the PR forward. Can you jump onto our Discord server and chat me? https://discord.gg/storybook

@marcolanaro
Copy link

@marcolanaro I'd love to discuss how to move the PR forward. Can you jump onto our Discord server and chat me? https://discord.gg/storybook

You are right, we should do it.
There is still some good stuff I have to understand from stencil, the solution above is not ideal for module reloading.
Let's do it as soon as I'm back in mid September.

@dutscher
Copy link

my solution with the proxy before can HMR in stencil and storybook.
but we need an official solution.

cheers

@splitinfinities
Copy link

Hey all, I'm the PM on the Stencil team and I'm looking for a roundup of everything in this thread so we can put a super solid plan together for native integration. I recently filed a feature request to gather community signal around allowing Storybook stories to work with Stencil's JSX library. It got a lot of activity! ionic-team/stencil#3104 (while you're there, add some reactions if you want!)

Now, I'm trying to determine the best next steps. I'm considering an option where we can have Storybook be an optional primary dev server for Stencil, and it seems like the story authorship/JSX is a big part of that. There's quite a lot of prior art around the dev server side of things, so I want to post my round up of resources that I'm sifting through to help craft a strategy to ship this.

First, I'm digging into this PR: #15479 which adds @storybook/stencil. If we can get Stencil's JSX library usable for Stories, would that unblock the PR? Alternatively, @marcolanaro, would we have your permission to take the work you've done (We would absolutely celebrate your contributions!!) in order to get it past the finish line?

For some other prior art, about 8 months ago, @shilman created a builder for Stencil (Repo located here) which provides a standalone dev server prototype. This could be a boon, as it provides some great samples of what it could take to bring Stencil's dev server integrated as well as its HMR features to work with Storybook out of the box, without the need for a @storybook/stencil, and from within @stencil/core. In that code, Michael states that Components have HMR and Stories do not have HMR. Programmatically controlling a Storybook server is interesting, and we'd want to figure out how to maintain the current set up that many folks have, where they place their Storybook configuration files in a .storybook directory at the root of a project.

After that, we have a couple other exciting tricks up our sleeves, like creating premium framework wrapper functions (f.k.a. framework output targets) that can produce more helpful framework specific code - including stuff like automatically creating Stories for your React, Angular, and Vue components that are produced from Stencil. This could leverage Storybook's Composition Feature in order to provide an awesome experience for you while you are developing and maintaining your design systems.

If any of this is interesting, please add a reaction to this comment! If you have ideas, leads to explore, or any other recommendations, please don't hesitate to reach out to me on the Discord (splitinfinities) or reply to this issue (or the JSX one on Stencil's Github repo)

Thanks everyone for the patience! The Stencil team is very excited to help make a great solution so you can document your code effectively, test the different variations of your components, and overall increase adoption of your design systems and component libraries!

@ndelangen
Copy link
Member

@splitinfinities Would you be interested in a zoom meeting to discuss things? I don't have a ton of background knowledge about stencil, but I know the insides and outsides of storybook.

If you're interested, schedule a meeting with me here:
https://calendly.com/chromaui/60min?month=2021-12

@marcolanaro
Copy link

@splitinfinities of course you have my permission to take my previous work and make it production ready. I actually feel sorry for not being able to push that forward for the community, but I had very busy months at work. I'm still very interested to see storybook as a first class citizen for stencil :)

@tomwayson
Copy link

@splitinfinities - any update on the Stencil team's effort to give their devs first class storybook support?

It looks to me like @marcolanaro's solution above is the state of the art (though it's now a year old), but it has the limitation that it doesn't support HMR. Is that correct?

@splitinfinities
Copy link

Hey all, unfortunately I was let go from the Stencil team last December. I'm not aware of the Stencil projects direction since then. Sorry for the lack of updates on my part, since that timeframe, these tickets weren't in my purview! I may recommend closing this ticket. Folks have been reaching out to me asking about progress on this so I wanted to give an update here to curb some of that. I'm really sorry y'all!

As a community member of Storybook, I can share that I have switched to using Lit (https://lit.dev) and ViewComponent (https://viewcomponent.org) with fantastic success! They're well documented and have plenty of great features + integrate with Storybook quite well.

Thanks all - I hope you find success with the tools of your choice!

@ndelangen
Copy link
Member

Thank you for the update @splitinfinities

I appreciate the hard work, effort and time you've put in!

@raymondboswel
Copy link

The initial way I developed with stencil & storybook (as described here: https://ionic.io/blog/how-to-use-storybook-with-stencil) required doing production builds, which was fast initially, but quickly slowed down as the project grew.

So just to add one more workaround to the mix, offering fast builds via stencil dev mode and page reloads on stencil changes; I do the following:

  1. Add build output to static dirs:
    "staticDirs": [{ from: "../www/build", to: "/build" }]

  2. Add build artifacts to preview.html:

  <script type="module" src="build/components.esm.js"></script>
  <script nomodule src="build/components.js"></script>

  1. Extend webpack config, adding BrowserSync (also install browser-sync & browser-sync-webpack-plugin):
"webpackFinal": async (config) => {
    return {
      ...config,
      plugins: [...config.plugins, new BrowserSyncWebpackPlugin({
        host: 'localhost',
        port: 3000,
        proxy: 'http://localhost:6006'
      })],
    }
  },
  1. Run stencil in dev mode:
    stencil build --dev --watch

  2. Access storybook via browsersync proxy port, 3000

This seems to work pretty well sofar.

@certainlyakey
Copy link

The initial way I developed with stencil & storybook (as described here: https://ionic.io/blog/how-to-use-storybook-with-stencil) required doing production builds, which was fast initially, but quickly slowed down as the project grew.

So just to add one more workaround to the mix, offering fast builds via stencil dev mode and page reloads on stencil changes; I do the following:

  1. Add build output to static dirs:
    "staticDirs": [{ from: "../www/build", to: "/build" }]
  2. Add build artifacts to preview.html:
  <script type="module" src="build/components.esm.js"></script>
  <script nomodule src="build/components.js"></script>
  1. Extend webpack config, adding BrowserSync (also install browser-sync & browser-sync-webpack-plugin):
"webpackFinal": async (config) => {
    return {
      ...config,
      plugins: [...config.plugins, new BrowserSyncWebpackPlugin({
        host: 'localhost',
        port: 3000,
        proxy: 'http://localhost:6006'
      })],
    }
  },
  1. Run stencil in dev mode:
    stencil build --dev --watch
  2. Access storybook via browsersync proxy port, 3000

This seems to work pretty well sofar.

I can confirm this approach works with Stencil 4.4.0 and Storybook 7.4.6.

@vivere-dally
Copy link

Does anyone have issues running "compiled" stories via build-storybook and Stencil? Please see #25704

@pfteter
Copy link

pfteter commented Apr 17, 2024

Here is my take on storybook 8 and stencil with working dev mode hot reloading:
https://github.com/pfteter/stencil-storybook-8-vite-integration-dev-build/tree/main

the alternative is to use the html5 webpack framework and the BrowserSyncWebpackPlugin

@rschaufler
Copy link

i finally got Storybook 8 + StencilJS + Vite to work with Hot Reloading too

as it turns out, the cause was quite primitive. If you have a look at the documentation of the vite dev server (which storybook uses), there is a very notable hint:

The Vite server watcher watches the root and skips the .git/, node_modules/, and Vite's cacheDir and build.outDir directories by default. When updating a watched file, Vite will apply HMR and update the page only if needed.

See: https://vitejs.dev/config/server-options.html#server-watch

build.outDir is set to dist by default. Due to this, all changes made by StencilJS when recompiling the dist folder are ignored 🙈

Simple fix:

Put the following configuration into your .storybook/main.ts (or .js) file

  async viteFinal(config, { configType }) {
    const { mergeConfig } = await import('vite')

    if (configType !== 'DEVELOPMENT') {
      return config
    }

    return mergeConfig(config, {
      build: {
        // this is set to 'dist' by default which causes hot-reloading for stencil components to break
        // see: https://vitejs.dev/config/server-options.html#server-watch
        // setting it to anything other than dist fixes the issue
        outDir: 'dist-vite'
      }
    })
  },

or full example:

import type { StorybookConfig } from '@storybook/web-components-vite'

const config: StorybookConfig = {
  stories: ['../src/components', '../src/styleguide', '../src/stories'],
  addons: [
    '@storybook/addon-links',
    '@storybook/addon-essentials'
  ],
  staticDirs: ['../dist/lib-components'],
  docs: {
    autodocs: true
  },
  async viteFinal(config, { configType }) {
    const { mergeConfig } = await import('vite')

    if (configType !== 'DEVELOPMENT') {
      return config
    }

    return mergeConfig(config, {
      build: {
        // this is set to 'dist' by default which causes hot-reloading for stencil components to break
        // see: https://vitejs.dev/config/server-options.html#server-watch
        // setting it to anything other than dist fixes the issue
        outDir: 'dist-vite'
      }
    })
  },
  core: {
    disableTelemetry: true
  },
  framework: '@storybook/web-components-vite'
}

export default config

If anyone is interested, i can provide a full project setup on Github.

@pfteter
Copy link

pfteter commented May 24, 2024

@rschaufler

A project on guthub would be great, that way we can track if something is broken in the new releases

@dutscher
Copy link

i have Storybook 7.6.17 + Stencil 4.18 + Vite 4 successfully in production.
i could update my repo aswell https://github.com/dutscher/stencil-storybook if someone is interested.

cheers

@rschaufler
Copy link

@rschaufler

A project on guthub would be great, that way we can track if something is broken in the new releases

🎉 Here you go: https://github.com/rschaufler/stencil-storybook-vite

This is a working example of Storybook 8 + Stencil 4 + Vite. Make sure you have pnpm installed.
I kept the repository as minimal as possible. You can find more information in the README file i provided. Apart from the solution for Vite Hot Reloading, this repository provides a neat solution to handle dependencies between Storybook and Stencil scripts by using Google Wireit. Make sure to use the provided start script to test developing with Stencil and Storybook.

Let me know if you have any questions or feedback.

@pfteter
Copy link

pfteter commented May 24, 2024

Those are all still quite workarounds. Issues:

  • Doing a stencil production build that needs a bunch more time (preview.ts > .../loader is prod build)
  • It needs stencil running side by side with stroybook in full production build and there is no need for it it doesnt consume react/angular components. This can be optimized by a custom stencil config that removes react/angular binding generation
  • Its slow and error prune / not real HMR.

The proper solution for this problem is to configure storybook to include stencils TS files in its own build in tsconfig so ts will retrigger reload when a stencil ts file changes for that the stenciljs compiler is probably also needed to be used see:
https://stenciljs.com/docs/compiler-api but that would be a lot of work.

I have a working solution with stencil dev build but it needs a custom vite watch and that the stencil build is part of the SB deployment (https://github.com/pfteter/stencil-storybook-8-vite-integration-dev-build/blob/main/README.md)

@rschaufler
Copy link

rschaufler commented May 24, 2024

Those are all still quite workarounds

Never claimed its not a workaround, but its the least intrusive in my opinion.

  • Doing a stencil production build that needs a bunch more time (preview.ts > .../loader is prod build)

what does preview.ts has to to with a stencil production build?

  • It needs stencil running side by side with stroybook in full production build and there is no need for it it doesnt consume react/angular components. This can be optimized by a custom stencil config that removes react/angular binding generation

All solutions (including yours) have storybook running alongside stenciljs. Where do you take the full production build from? Storybook /StencilJS runs the dev script. And where do you take the argument with react/angular components from?

  • Its slow and error prune / not real HMR.

Using the repository i provided, its not slow at all and it is in fact "real" HMR. The update is instant and only for the component that was updated (not the whole dist directory). What errors do you expect? How did you measure that it is slow?

The proper solution for this problem is to configure storybook to include stencils TS files in its own build in tsconfig so ts will retrigger reload when a stencil ts file changes for that the stenciljs compiler is probably also needed to be used see: https://stenciljs.com/docs/compiler-api

Running the StencilJS dev script is also a valid solution.

I have a working solution with stencil dev build but it needs a custom vite watch and that the stencil build is part of the SB deployment (https://github.com/pfteter/stencil-storybook-8-vite-integration-dev-build/tree/main)

The solution i provided does not need this. Your solution is working around the core issue that the dist folder is ignored with a hacky vite plugin instead of just adjusting the vite configuration. Apart from that, all your criticism can be applied to your solution as well, so i don't really understand why you come up with this now.

@pfteter
Copy link

pfteter commented May 24, 2024

Just reviewing the solutions, it's not criticsm.

Using the repository i provided, its not slow at all. The update is instant and only for the component that was updated
Same thing in the other one the updates are fast and it's just the file.

Just saying it's possible to make a solution where we dont need stencil running side by side with storybook that would be the real deal.

I'm not saying my solution is good it's just a workaroud too :)

The solution i provided does not need this. Your solution is working around the core issue that the dist folder is ignored with a hacky vite plugin instead of just adjusting the vite configuration.

That is a great input, we have a lot of components and try to minimize the initial build it takes almost 2 mins.

Again I'm not saying the other solution is better it's a workaround, just saying that probably the best one would be if storybook would have stencil support out of the box without side by side running it's just TS and the stencil compiler that transforms the stencil markup.

https://storybook.js.org/addons/storybook-addon-stencil

that plugin is half way trough

@rschaufler
Copy link

rschaufler commented May 24, 2024

Yes, thats for sure. Having native support for StencilJS would be great. But as for now, we have to help ourselves with this kind of workarounds.

@pfteter
Copy link

pfteter commented May 24, 2024

https://github.com/ZanichelliEditore/storybook-addon-stencil/blob/main/src/server/stencil-loader.ts

would be similar to that as part of vite build, we just need to compile the stencil to ts files and link them in storybook. But maybe I have a wrong model of it. Anyway would be hard to maintain

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