Yes, you can!
If you want to write your stencil stories for storybook using TSX (the Typescript version of JSX), this is actually possible. A bit of tweaking, and you should go to go. BUT - this is still a very preliminary work, and I expect it to suffer quite few bumps in different scenarios. Nevertheless, I thought it it worth sharing, as I know people were looking for a solution.
This is assuming you are using the html version of Storybook with Stencil. You can find a working version in my stencil-one demo repo. (This is my demo repo for unit testing in Stencil, so feel free to look around).
These are the main versions I worked with. I have no idea if it will be compatible with other versions.
Stencil: 2.15
Storybook: 6
webpack: 5
babel-loader: 8
Step 1: Write your story
This is what a story should look like, using CSF3 (Component Story Format). Obviously, it should be in a file named .tsx
, so it will go thru the right tooling. Also, change the path that looks for your stories to include .tsx files. (stories option in the main file).
/** @jsx h */
/** @jsxRuntime classic */
import {h} from '@stencil/core';
export default {
title: 'My Basic',
};
export const Default = {
render: () => (<my-basic first="Millie" last="Brown"></my-basic>)
};
Note the @jsx
directives. They seem to be necessary.
Step 2: Configure Webpack for jsx
We are going to tweak .storybook/main
so it will include the babel jsx transformer. In order to do that we will find the rule that handles tsx and add the @babel/plugin-transform-react-jsx
as plugin with the pragma: {'h'}
.
webpackFinal: async (config) => {
const tsxRule = config.module.rules.find(rule => 'a.tsx'.match(rule.test));
if(tsxRule) {
const options = tsxRule.use[0].options;
options.plugins = [
['@babel/plugin-transform-react-jsx', {
prgama: 'h'
}],
...options.plugins
];
}
return config;
}
Step 3: Render the stories using Stencil's renderVDom
The last part is changes to the storybook/preview
code. Create a function that will be used as a decorator and will render elements to the DOM.
const stencilWrapper = (storyFn, context) => {
const host = document.createElement('div');
stencilClient.renderVdom(
{
$ancestorComponent$: undefined,
$flags$: 0,
$modeName$: undefined,
$cmpMeta$: {
$flags$: 0,
$tagName$: 'div',
},
$hostElement$: host,
},
storyFn(context)
);
return host.children[0];
}
And then activate it: addDecorator(stencilWrapper);
You will also need to make sure that you are calling the defineCustomElements (which you should, anyway) in the preview code or the preview-manager html file.
As mentioned above, this is still prone to errors. If you have any suggestions, improvements, bugs fixes etc, please comment.