web-component-analyzer
web-component-analyzer copied to clipboard
Programatic usage to integrate with storybook
Hey @runem,
This project awesome :smile:
I'm using https://storybook.js.org/ to work on my components (and to showcase them). I would love to use your project to extract my JSDoc into some kind of object I could then format to HTML. This means I need direct access without the CLI part.
I tried to use your code without the CLI but I did not manage to go very far. Would you be interested to guide me so we could provide this kind of interaction?
What I did in the end (but I'm not satisfied with this) is:
- Use CLI to generate MD
- Import MD into storybook
The problems are:
- I want more control on the formatting (HTML but also filtering private stuffs
_private
etc... - I also want this to be run each time storybook's webpack dev server rebuilds...
Hi, thanks for opening this issue :-) I think your use case is very exciting!
First of all, I'm not very experienced with storybook
, so I don't know how to extend stories on compile time. Therefore there might be a better solution to the problem than what I'm proposing here.
Analyze with the CLI
A fast an easy approach for me was to extend the storyboard Webpack config with a custom plugin (see storybook documentation). It regenerates the markdown files by running the CLI command on each file change, and only when a file from src
changes, to prevent infinite recompilation.
const { AnalyzeCliCommand } = require("web-component-analyzer");
config.plugins.push({
apply: function (compiler) {
let relevantChangedFiles = null;
compiler.hooks.watchRun.tap('AnalyzeComponents', async (comp) => {
const changedFiles = Object.keys(comp.watchFileSystem.watcher.mtimes);
relevantChangedFiles = changedFiles.filter(fileName => fileName.includes("/src/"));
});
compiler.hooks.done.tap('AnalyzeComponents', async () => {
if (relevantChangedFiles == null || relevantChangedFiles.length > 0)
new AnalyzeCliCommand().run({ format: "md", outDir: "stories" }, "src/**/*.js")
});
}
});
Markdown files are emitted to the "stories" folder and can be required
by stories.
A problem with this solution is that it rebuilds everything, and not only changed files. In addition it doesn't solve customising the output. I have been considering allowing hooking up custom transformers to control the formatting, so this could be a solution to your problem. It would be interesting to know more about how you want to control the formatting/output.
Analyze without CLI
The core analyzer is built by analyzing the output of the typescript
compiler. Therefore it requires you to have access to a Typescript program. Here's an example of how to use it without the CLI:
import { analyzeComponents } from "web-component-analyzer";
analyzeComponents(sourceFile, {checker: program.getTypeChecker()})
What I tried: I played around with this approach by extending storybook with the ts-loader
Webpack loader (see storybook documentation) and providing a custom transformer. This looked something like the following code. However I stopped going this way because of problems regarding finding class declarations but I might be exploring this approach again. In addition I might be making a custom Webpack plugin that automatically regenerates only changed components.
const { analyzeComponents } = require("web-component-analyzer");
config.module.rules.push({
test: /\.js?$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
getCustomTransformers: (program) => ({ after: [
(context) => {
return (sourceFile) => {
if (sourceFile.fileName.startsWith(join(__dirname, "../src"))) {
const result = analyzeComponents(sourceFile, {checker: program.getTypeChecker()});
// Do something with the result here
}
return sourceFile;
}
}
] })
},
}
]
});
Thanks very much for your answer. This is promising. I may have time to look at this next week, I'll keep your up to date.
I tried the second approach. I had to create a tsconfig.json
file but your code example helped me a lot. I manage to output the result, now I need to figure out how to give it to storybook.
I remember using this with Vue: https://github.com/tuchk4/storybook-readme
It extracts docs from <docs></docs>
blocks and gives it to storybook. In the end, I'm trying to do something similar.
Is there a way that would abstract the fact that web-component-analyzer uses TypeScript? Something like analyse('some Custom Element code')
...
I guess, you would need file path etc so maybe raw string would not be enough.
Regarding analyzing raw text, maybe you can find inspiration in this file which I use for testing raw code: https://github.com/runem/web-component-analyzer/blob/master/test/helpers/analyze-text.ts . It basically creates program with virtual files which can then be analyzed 👍
Storybook docs mode now supports showing properties based on custom-elements.json
and it works very nice with web-component-analyzer
👍
https://github.com/storybookjs/storybook/tree/next/addons/docs/web-components
Maybe someone can make a tutorial on howto hook it into the webpack refresh/rebuild "loop" 🤗
I cannot promise I'll work on this next week, but I definitely want to ;-)
It will be a great opportunity to see how I can also hook into the process to add info I need:
- Docs for methods
- List of translation keys
- List of images assets
- Size of the file
- List of deps (and size)
Update:
So, yesterday, I tried a very "hacky POC integration" (directly using wca in storybook's preview.js).
It took around 2~3 seconds to generate MD+JSON in the browser for 56 components but I was able to integrate the MD output in the notes addon and the JSON output in the docs addon.
The problem is: it's a bit slow. I don't need to run this on each reload for all components. The answer would be a webpack loader I guess, I need to dive into this soon...
Regarding the list of additional info I wanted to add (see last comment), I still want them the but now "docs for methods" is auto handled in the markdown output ;-)
We integrated the new addon docs page in our storybook and sill have the notes addon with wca's markdown output. We want to stop having this "double doc" but the markdown ouput has methods, event types, CSS custom props types and the docs page props table does not group properties and attributes :-(
I'll try to see how I can improve all of this and keep you up to date ;-)
I fell into the same trap having Storybook.js doc and inline JSDoc's. (Also a weird scroll hijacking bug I could no fix in Storybook.js).
I ultimately decided to bin off storybook.js and simply render out the documentation using remark
to custom build document pages.
@kylewelsby Nice looking docs page ;-)
@hsablonniere Did you manage to get any further with storybook and the wca plugin?
@reno1979 nope :-(