Migrate from @open-wc/demoing-storybook to @web/dev-server-storybook plugin
These are my steps to migrate from @open-wc/demoing-storybook to @web/dev-server-storybook plugin. As you may already seen, @open-wc/demoing-storybook
package was sort of deprecated in 2020. Here you can find more details about the new recommended solution for Storybook.
My setup
For context, I maintain a library of web components based on Lit for my work. The library is a monorepo based on the recommendations from Open Web Components. You probably have a different setup, but the migration should be similar.
In my case, it all started with our pipeline that stoped working by throwing an error like this:
node:internal/crypto/hash:71
this[kHandle] = new _Hash(algorithm, xofLen);
^
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
...
at FSReqCallback.readFileAfterClose [as oncomplete] (node:internal/fs/read_file_context:68:3) {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
The error seems to be caused by the fact that our agents were upgraded to Node 18.x, while we were still on Node 16.x.
You can check a quick fix from StackOverflow, but on the long term you will have to migrate your Storybook setup.
I started by upgrading all my dependencies and leaving the @open-wc/demoing-storybook
package at the end, knowing that I already have the last version.
After doing all the upgrades, I still had the same error and was clearly that I had to drop that package.
The migration
First thing we need to do is to add a new npm package.
Update the packages
Uninstall @open-wc/demoing-storybook
npm uninstall @open-wc/demoing-storybook
Install the @web/dev-server-storybook plugin for web-dev-server
npm install -D @web/dev-server-storybook
This will also install @web/storybook-prebuilt which we will be using later.
Fix the local server
From now on, we'll be using a prebuilt version of Storybook and we'll be using the web-dev-server to also start the Storybook.
To do this, we need a new config file for web-dev-server.
// web-dev-storybook.config.mjs
import { storybookPlugin } from '@web/dev-server-storybook';
export default {
plugins: [storybookPlugin({ type: 'web-components' })],
};
`
I put this file in the root of my project, but you can put it wherever you want.
Previously, I would start the local server for Storybook like this:
npm run storybook
where the storybook
script was:
"storybook": "start-storybook --node-resolve --watch --open",
Now, we should change it to:
"storybook": "web-dev-server --node-resolve --open --config web-dev-storybook.config.mjs",
Fix the Storybook config
In your /.storybook
folder you should have these two files: main.js and preview.js.
These configs are probably different than mine, so I'll just put my before and after for them.
main.js
// main.js before
module.exports = {
stories: [
'../packages/**/stories/*.stories.{js,mdx,md}',
],
addons: [
'storybook-prebuilt/addon-docs/register.js',
],
};
// main.js after
const { copy } = require('@web/rollup-plugin-copy');
module.exports = {
stories: [
'../packages/**/stories/*.stories.{js,mdx,md}',
],
rollupConfig(config) {
// we copy these files, because they are consumed at run time
config.plugins.push(copy({ patterns: 'packages/**/custom-elements.json' }));
return config;
},
};
One mention here is that in my library, every component has a custom-elements.json
file, so know I have to copy them at build time, using the @web/rollup-plugin-copy
plugin.
To install this package, use:
npm install -D @web/rollup-plugin-copy
preview.js
// preview.js before
import {
addParameters,
addDecorator,
setCustomElements,
withA11y,
} from '@open-wc/demoing-storybook';
import { componentsList } from './components-list.js';
async function run() {
// Custom Elements is used to generate API documentation on Docs tab in Storybook
const customElementsJson = {
version: 2,
tags: [],
};
for (const [pckg, components] of Object.entries(componentsList)) {
for (let component of components) {
try {
const customElement = await (
await fetch(
new URL(
`../packages/${pckg}/components/${component}/custom-elements.json`,
import.meta.url
)
)
).json();
customElementsJson.tags.push(customElement.tags[0]);
} catch (err) {}
}
}
addDecorator(withA11y);
addParameters({
a11y: {
config: {},
options: {
checks: { 'color-contrast': { options: { noScroll: true } } },
restoreScroll: true,
showRoots: true,
},
},
docs: {
iframeHeight: '200px',
},
});
setCustomElements(customElementsJson);
}
run();
// preview.js after
import {
addParameters,
setCustomElements,
} from '@web/storybook-prebuilt/web-components.js';
import { componentsList } from './components-list.js';
async function run() {
/**
* Custom Elements is used to generate API documentation on Docs tab in Storybook
* Minimal example for new scheme:
* {
* schemaVersion: '2.0.0',
* modules: [
* {
* declarations: [
* {
* tagName: 'my-component',
* properties: [
* { name: 'data', type: 'array', 'description': "Foo.", default: 'null' }
* ],
* events: [],
* slots: [],
* cssProperties: []
* },
* ...
* ]
* }
* ]
* }
*/
const customElementsJson = {
'schemaVersion': '2.0.0',
'modules': [],
};
for (const [pckg, components] of Object.entries(componentsList)) {
for (let component of components) {
try {
const customElement = await (
await fetch(
new URL(
`../packages/${pckg}/components/${component}/custom-elements.json`,
import.meta.url
)
)
).json();
customElementsJson.modules.push({
declarations: [
{
...customElement.tags[0],
tagName: customElement.tags[0].name,
},
],
});
} catch (err) {}
}
}
addParameters({
a11y: {
config: {},
options: {
checks: { 'color-contrast': { options: { noScroll: true } } },
restoreScroll: true,
showRoots: true,
},
},
docs: {
iframeHeight: '200px',
},
});
setCustomElements(customElementsJson);
}
await run();
Please note that I have an older scheme version for custom-elements.json and that's why I build the
customElementsJson
object differently.
Fix the stories
Open all your stories and change the imports like this:
import { Story, Preview, Meta, Props, html } from '@open-wc/demoing-storybook';
to:
import { html } from 'lit';
import { Story, Preview, Meta, ArgsTable } from '@web/storybook-prebuilt/addon-docs/blocks.js';
Please note that Props was renamed to ArgsTable.
You also need to change <Props>
to <ArgsTable>
in your stories.
Fix the build
Here, I just changed the build script from:
"storybook:build": "build-storybook -o demo-storybook -s storybook-static",
to:
"storybook:build": "build-storybook --output-dir demo-storybook",
Done
Now we just need to test it. To start the Storybook locally, run:
npm run storybook
To build the Storybook, run:
npm run storybook:build