Closed maraisr closed 2 years ago
@LeeBurton at the time i was testing it lit-html was a peer dependency. It is normal that you have to install peer dependencies by yourself. https://nodejs.org/es/blog/npm/peer-dependencies/
For what it's worth, I got stencil working with this config in .storybook/preview.js
import { defineCustomElements } from "../dist/esm/loader.mjs"
defineCustomElements()
configure(require.context('../src', true, /.*\.stories\.(js|mdx)$/), module);
@idmyn I tried that and while it compiles, any change made to any src file still doesn't get loaded into browser without a manual hard reload.
I got it to work by running Stencil's build locally with watch enabled in one npm run script while running start-storybook
in parallel with npm-run-all
package.
I configured storybook's webpack config to watch Stencil's dist files using the following in my main.js:
const path = require('path');
const glob = require('glob');
module.exports = {
webpackFinal: (config) => {
// watch all revelant files in dist folder
const distDir = path.resolve(__dirname, '../dist');
const files = glob.sync(`${distDir}/**/*.entry.js`, { absolute: true, ignore: ['**/*.system.entry.js'] });
config.entry.push(...files);
return config;
},
};
You may have to change the paths/files a bit for your project, but this worked for me.
Just wondering, did @DesignByOnyx or @Edd-Strickland ever look at turning their solutions into a preset for 6? I've used both repo's and - as is usually the way - I like bits of each :-)
I've moved my copy of @Edd-Strickland's to 6.0.0-beta reasonably successfully, although I find it doesn't always rebuild everything when it spots a change (eg readme.md).
Is this publicly available @paulfelton?
It is now, help yourself :-)
I've forked Edd's project. @Edd-Strickland, shall I pop in a PR? It'll need good review, I'm no expert in this.
I've bumped the packages, refactored the config to the new format. I had to add a typings and refer to it in tsconfig to get the story to import the stencil readme, and add a config to translate 'notes' to 'docs'.
Wishlist:
@paulfelton do you need anything from me?
@ndelangen I'm not sure. As you may have gathered, I'm pretty new to both Stencil and Storybook, so just munged together what I can drag up from various issues discussions, google, etc.
I had a go at a starter repo as well, heavily inspired but all the great efforts in this issue (thanks all!).
https://github.com/elwynelwyn/stencilbook-ding
Uses @storybook/web-components
, working with the essentials addons (e.g. Controls, Actions). Latest versions of everything at this stage..
Some extra integration between Stencil dev server and the Storybook preview frame (so the Stencil error overlay shows up inline in Storybook - better DX!) (check ./storybook/preview-body.html
and ./src/index.html
for the deets).
~Mashed the Stencil devserver into start-storybook
so you just run a single command and it spins up stencil behind the scenes.~
EDIT: simplified this with concurrently
+ wait-on
- wait for Stencil to spin up, then go ahead with Storybook
Code changes (to Stencil components or Storybook stories) will reload the preview frame (not the entire storybook app). It's not proper HMR but it's reasonably nice to dev with!
Nice. The link doesn't work.
Whoops, repo is public now ^
I've put together a boilerplate repo using stencil v2 and @storybook/web-components v6 here: https://github.com/bjankord/stencil-storybook-boilerplate
There's also a repo at https://github.com/miriamgonp/stencil-web-components-boilerplate built by @miriamgonp from the Storybook/Stencil discord channel. Anyone fancy combining these emerging boilerplates? ;-)
These two repos look great. If they were consolidated into one with would be a good addition. And if anyone would be willing to contribute with a tutorial in Intro to Storybook based on these two repos we would really appreciate. Let me know if anyone is willing to help us with it and i would gladly go over to help out members of the community that use Stencil.
i got a proper hmr solution ;) coming soon!
i got a proper hmr solution ;) coming soon!
here it is! Stencil 2+ & Storybook 6+ (Old Stencil version should also works ;)) https://github.com/dutscher/stencil-storybook have fun and cheers
edit: with storybook on gh-pages https://dutscher.github.io/stencil-storybook/index.html
Swapped this ^^ in to our project last week and after stripping out the bits not relevant to us (Bootstrap, scss, chromatic etc) and fixing a couple minor things (e.g. package.json name not working everywhere it's imported due to being in @myorg/my-proj format) it's been working really well.
Have been using it for a day or so now and the HMR is excellent!
@elwynelwyn anything we need to do on storybook's side do you think?
@ndelangen the important things are:
cheers
@ndelangen do you have plan to add an official support for Stencil in the near future, or we should use solution by @dutscher. Which is awesome by the way, many thanks man.
I've been trying to get Storybook + Stencil working together based off of @dutscher 's configuration, and I think I've found a way where the proxy.js
isn't necessary but HMR still works. Here are some relevant files from my setup (unfortunately the repo is still internal right now, so I can't link to it yet):
package.json (selected scripts)
"start": "concurrently -n storybook,stencil -c \"bgMagenta.bold,bgBlue.bold\" \"npm:storybook\" \"npm:watch:stencil\"",
"watch:stencil": "stencil build --watch",
"storybook": "start-storybook -p 6006",
.storybook/main.js
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
};
.storybook/preview.js
import { defineCustomElements } from '../loader';
defineCustomElements(); // Load the web components
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};
My Stencil config is the default, and my stories.tsx
file is modeled after @dutscher 's as well (using lit-html
). I tried to get things to work by writing plain JSX instead of a template string, but I wasn't able to get that working. Something for another day, perhaps!
I may encounter some problems with this at some point, but it's working for now.
@dutscher - when I run new:component
, it doesn't seem to generate a readme.md
file (neither does it when I add more content to my component). I'm not clear if that's an issue or not, but the stencil config in your project seems to have the necessary config to generate it.
I note that the my-component
sample has a readme.md
, but I'm not sure if that was automatically generated, or whether my-component was just copied from another boilerplate. new:component creates test specs in a /tests
folder, where as my-component has them as the same level as the component and the story. Likewise, it generates a css file rather than a scss.
Some of this maybe out of scope, but I thought I'd check.
And while writing, anyone else spotted this interesting article? Maybe some further enhancements that could be made inspired by it?
Paul
@paulfelton this is because the readme's are being built to the dist directory in the stencil.config.ts. I had this issue for a while myself and it was throwing errors. I have been playing with Storybook and StencilJS together for 2+ years now and though @dutscher implementation is the best by far, (with slight modifications 😜), I was not happy with any of them and started my own solution because of the sheer complexity of the setup and weight of all the dependencies for Storybook. That being said here is the best implementation of Storybook + StencilJS that I have managed to put together if anyone is looking for another example.
https://github.com/MadnessLabs/Enjin-Editor
I have made too many modifications to list here, but the ones to fix the readme files are below.
1) Remove dir from "docs-readme" output in stencil.config.ts
2) Add --docs flag to watch:stencil command in package.json
I am also looking for an official tutorial how to use Stencil with storybook-web-components.
Thanks @dutscher for your demo project, I also created one with a different approach using storybook-html and storybook-react: https://www.mokkapps.de/blog/run-build-and-deploy-stencil-and-storybook-from-one-repository/
Will there be an official way to run stencil with storybook-web-components without a lot of hacky configuration?
We've presented a prototype to the Stencil team for how an official integration might work, and are waiting to hear back as they figure out their development priorities for Stencil.
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:
npm run build:watch
and npm run storybook
separately.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>
)
};
@marcolanaro thanks for preparing the PR for the Storybook repo! However, I have some difficulties with the recipe you've presented, my component is not rendered in the preview, however, I can see the (empty) custom element present in the iframe DOM tree. Could you be so kind and prepare a git repo with an example to compare what I've missed?
@marcolanaro thanks for preparing the PR for the Storybook repo! However, I have some difficulties with the recipe you've presented, my component is not rendered in the preview, however, I can see the (empty) custom element present in the iframe DOM tree. Could you be so kind and prepare a git repo with an example to compare what I've missed?
Here's an example: https://github.com/storybookjs/storybook/pull/15479/files#diff-edc4a8c7ec583ed332aa47d2865c8152677aee654797876ed500a8f9e3a19343R9
@Sebosek did you tried with tsx or jsx files? I had problems with tsx files but with jsx it's working fine
@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 😊
@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!
@marcolanaro I'll spend some time at the weekend. Until now, everything I tried failed with just no stories visible
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:
- you need to run
npm run build:watch
andnpm run storybook
separately.- 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
. Inpreview.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 :)
@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 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.
my solution with the proxy before can HMR in stencil and storybook. but we need an official solution.
cheers
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! https://github.com/ionic-team/stencil/issues/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: https://github.com/storybookjs/storybook/pull/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!
@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
@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 :)
@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?
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!
Thank you for the update @splitinfinities
I appreciate the hard work, effort and time you've put in!
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>
3) 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'
})],
}
},
4) Run stencil in dev mode:
stencil build --dev --watch
5) Access storybook via browsersync proxy port, 3000
This seems to work pretty well sofar.
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:
- Add build output to static dirs:
"staticDirs": [{ from: "../www/build", to: "/build" }]
- Add build artifacts to preview.html:
<script type="module" src="build/components.esm.js"></script> <script nomodule src="build/components.js"></script>
- 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' })], } },
- Run stencil in dev mode:
stencil build --dev --watch
- 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.
Does anyone have issues running "compiled" stories via build-storybook
and Stencil? Please see https://github.com/storybookjs/storybook/issues/25704
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
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.
@rschaufler
A project on guthub would be great, that way we can track if something is broken in the new releases
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
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...