# learnstorybook.com pins cheerio to a release candidate and patches dependencies on every install

> learnstorybook.com is the Gatsby site holding the Storybook tutorials: markdown content under a directory whose path encodes guide, framework, language and chapter, a component workshop that is built before the site integrates it, and a build step that extracts documentation metadata from the Storybook repository itself. It installs three analytics plugins, holds a production dependency on a pre-release, and applies committed patches on every install.

**chromaui/learnstorybook.com** — Static site and content for Storybook tutorials

- Repository: https://github.com/chromaui/learnstorybook.com
- Website: https://storybook.js.org/tutorials/
- Stars: 2,413 · Forks: 434
- Language: JavaScript
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/chromaui-learnstorybook-com

## A production dependency is a release candidate, held there by patches

One dependency in the manifest points at a pre-release.

The HTML parsing library is pinned to a release candidate of a 1.0 line rather than to a stable release, with a range that begins at that candidate. This is not an oversight: the library's later releases reorganised its module layout and broke a large number of consumers that expected the older CommonJS shape, so pinning to a candidate before that change is the standard workaround for staying on the old layout.

What holds the project together around that pin is a patch step. The manifest runs a patch tool on the post-install hook, and there is a committed directory of patches beside the source. So every install, on a contributor's machine and in continuous integration alike, applies local modifications to installed dependencies before the site builds.

That combination is a normal way to hold a large static-site stack together and an unusual thing to inherit. It means the repository contains code that is not the project's own and not any dependency's released code, and it means a lockfile update can be blocked by whether a patch still applies. Neither is a defect. Both are worth knowing before you spend an afternoon on a build failure that turns out to be a patch context mismatch.

## Three analytics plugins, two of them the same vendor's old and new product

The dependency list contains three analytics integrations for a tutorial site.

One is a documentation search stylesheet. Two are analytics: the original Google Analytics plugin, and a separate Google tag plugin, which is the newer measurement product from the same vendor. The third is a third-party, privacy-oriented analytics plugin.

Having both Google products present is the odd part. The original was the Universal Analytics property, which the vendor has been winding down, and the tag plugin is its replacement. Keeping both means the site carries two clients for one measurement goal, and only one of them can be receiving anything, so the other is either idle or configured for a property that no longer reports.

The development setup adds one more clue. The local environment instructions tell you to create a file with a single variable set to skip something called data collection. So the site does send usage data when built for production, and the local build is expected not to. That is the correct arrangement, but it also means the analytics configuration is invisible during development, which is exactly the arrangement in which a misconfigured tag goes unnoticed until someone reads the production report.

## The build fetches content from the Storybook repository itself

The local setup has four steps, and one of them is not about this repository.

```
1. Run `yarn install` to install dependencies
2. Run `yarn extract-sb-docs-metadata` to fetch content from the main Storybook repo
3. Set up a `.env.development` file with the following environment variables:

```plaintext
SKIP_DX_DATA=true
```

4. Run `yarn dev` to start the development server
```

So a meaningful part of what this site displays is extracted at build time from the main Storybook repository, by a shell script in the scripts directory. That is the single most important structural fact in the readme and it is a footnote in the setup steps.

It has three consequences. A contributor working offline cannot produce a full site even with every dependency installed, because the fetch has nothing to work from. A change to the other repository's documentation metadata changes this site without a commit here, so the output is not reproducible from this repository alone. And the build has hooks on both sides: a pre-build step that runs the extraction and creates an output directory, and a post-build step that runs a move script.

The extraction script is named after documentation metadata rather than after tutorials, which suggests it covers more of the documentation surface than the tutorial pages themselves.

## Adding a translation means editing application code

The content path is four segments, one of them optional:

```
/content/:guide/:framework?/:language/:chapter.md
```

A colon prefix marks a dynamic name you choose and a question mark marks an optional segment, so the framework directory exists only for guides organised by framework.

The language directory is where the coupling lives. The readme says the naming of that directory is important and should mirror what has been used in other guides for similar translations, and then it says a helper is used across the app to transform the language into a human readable name, and that you must update the helper if you are adding a language that has not been used before.

So a new locale is two kinds of change: content, which is a directory and some markdown, and code, which is an entry in a source file under the app. The page even invites an issue for a better way to produce the readable name, which is an admission that the current mechanism is a manual registry rather than a derivation.

That coupling is invisible from the file tree and is the thing most likely to surprise a first-time translator, who will reasonably expect to add a directory and be done. One translation in the set is machine-derived rather than written: the Traditional Chinese version is converted from the Simplified Chinese using a conversion tool, and the page asks for help correcting idiomatic errors. So that locale is known-imperfect by its own maintainers.

## A new chapter touches three files, and the order comes from hand-edited frontmatter

The chapter instructions contain the whole cost of a contribution, and it is not one file.

Step one decides whether the guide is organised by framework, which determines whether an extra directory goes in. Step two creates the language directory. Step three creates the chapter markdown. Step four is the one that surprises people: update the guide's table-of-contents frontmatter by hand.

The readme is explicit about why. Each time a chapter is added you must go back and update the guide's table of contents in order to populate the table as well as control the order of the chapters, and the entry you add is the name of the file you just created:

```
toc: [":chapter"]
```

So the chapter order lives in frontmatter that is maintained by hand and must be edited every time. Nothing derives it from the directory, and nothing validates it, which means a chapter that exists but is not listed is invisible, and a listed chapter whose file was renamed is a broken link.

A guide itself has the same shape at the top level. Adding one requires a directory, and an index file whose frontmatter has five required fields, a title, a hero description, a description, an overview and a theme colour. The readme then says to see the frontmatter reference for additional options, most of which you will want in order to create a guide that feels complete, which is a candid way of saying the required five are a minimum rather than a recipe.

## Five dependencies are pinned exactly, and they are the interface kit

Five of the roughly three dozen dependencies carry an exact version with no range. The rest float.

The exact five are two Storybook packages used by the component workshop, the shared design system, a theming package, a motion library, and the two React packages. Everything else in the list carries a caret range, including the whole Gatsby stack, the markdown remark plugins, and the image processing plugin.

The pattern is not random. The pinned entries are the ones that render the documentation's own interface: the workshop's components, the design system, the motion library, and the React pair itself. The floating entries are the ones that render content. So the site treats its interface kit as a fixed thing it has validated together, and its content pipeline as something it accepts movement in.

React is in the pinned group for a second reason. The static site generator is on the fourth major line, and that generation expects a specific React version, so pinning React rather than ranging it is what keeps the two aligned. It also means a React security update is a deliberate edit to the manifest rather than something a lockfile refresh brings in.

## Two development servers and a rule about which one to build in

There are two local workflows and the readme tells you which to use for what.

The first starts the component workshop, which contains every interface component the site uses, on port 6006. The second starts the site itself. The rule connecting them is stated as a process requirement rather than a technical one: interfaces are built from the bottom up, starting with components and ending with screens, and contributors should compose interfaces in the workshop before integration with the site application.

That is the component-driven development argument applied to the tutorial site's own tooling, which is a reasonable thing to require of contributors. It also means there are two build systems to learn, two ports, and a convention that one of them is upstream of the other. There is a shared linter, formatter and hook setup across both, with a commit hook configured, so the two halves are held to the same style.

The rest of the root is the usual accumulation: an editor configuration directory, a version file for the runtime with a second file also pinning the runtime version for a different tool, a linter configuration and its ignore list, a formatter configuration and its ignore list, a directory of build plugins, and a directory of committed patches. Two files pinning the same runtime version is the sort of duplication that survives because different tools read different ones.

## Conclusion

Use learnstorybook.com as the canonical source for the Storybook tutorials if that is what you are after, since it is the content behind the tutorials section of the documentation site and the readme states plainly who wrote and who runs it. Four things to know before contributing. That a chapter is three files, not one: the chapter itself, the guide's table of contents in frontmatter, which controls ordering and is maintained by hand, and the language helper in application code if the language has not been used before. That content and code are coupled, so a translation-only contribution cannot avoid touching a source file. That the build fetches from another repository, which means an offline contributor cannot produce a full site even with every dependency installed. And that the dependency set is held together with an exact pin to a pre-release plus a patch step on every install, which is a maintenance liability you inherit rather than choose. For a documentation site the last point is what to check first when the build starts failing after an unrelated dependency release.

## FAQ

### What is learnstorybook.com?

A static site and the markdown content for the Storybook tutorials, built with a static site generator and hosted as the tutorials section of the Storybook documentation. The text, code and production were contributed by Chromatic, and the tutorial was inspired by their GraphQL and React series.

### How do I run the Storybook tutorials site locally?

Run `yarn install`, then `yarn extract-sb-docs-metadata` to fetch content from the main Storybook repository, create a `.env.development` file containing `SKIP_DX_DATA=true`, and run `yarn dev`. The component workshop is a separate server on port 6006 started with `yarn storybook`.

### How do I add a tutorial chapter in a new language?

Create a language directory under the guide, naming it to match what other guides use, add the chapter markdown file, update the guide's table-of-contents frontmatter by hand to control ordering, and add the language to the helper that turns a code into a readable name. That last step is a code change.

### What is the content path format for learnstorybook.com?

`/content/:guide/:framework?/:language/:chapter.md`. A colon prefix marks a dynamic name you choose, and a question mark marks an optional segment, so the framework directory appears only for guides organised by framework.

## Sources

- [chromaui/learnstorybook.com on GitHub](https://github.com/chromaui/learnstorybook.com)
- [Issues](https://github.com/chromaui/learnstorybook.com/issues)
- [License: MIT](https://github.com/chromaui/learnstorybook.com/blob/master/LICENSE)
- [Project website](https://storybook.js.org/tutorials/)
- [README](https://github.com/chromaui/learnstorybook.com/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/chromaui-learnstorybook-com
