tomato·bazeldocs v0 · latest
Docs/Reference/Modules/rules_storybook

rules_storybook

Bazel rules for Storybook: hermetic build, deterministic story manifest, sandbox-escaping dev runner.

Latest0.2.0
Versions2
CategoryBazel rules
Compat level1
MaintainersMatt Marshall
Registryhttps://registry.tbzl.dev/modules/rules_storybook/
Sourcegithub.com/tomato-bazel/rules_storybook
MODULE.bazelstarlark
bazel_dep(name = "rules_storybook", version = "0.2.0")

View source & releases on GitHub ↗

Bazel rules for Storybook. Hermetic storybook build, deterministic story-manifest generation, plus a storybook dev runner that escapes the sandbox for the HMR-driven dev loop.

  • storybook_build — runs storybook build as a Bazel action; output is the storybook-static/ tree. Forces STORYBOOK_DISABLE_TELEMETRY=1 + reproducibility env vars (TZ=UTC, SOURCE_DATE_EPOCH=0).
  • storybook_manifest — emits a deterministic JSON manifest of story file paths. Replaces the non-deterministic glob in .storybook/main.ts’s stories: [...] config; adding a story file now triggers an explicit Bazel-tracked input change.
  • storybook_devbazel run //path:dev macro: runs pnpm exec storybook dev against the live workspace source. Intentionally non-hermetic (HMR + watch + Vite on-demand optim need filesystem access outside the runfiles tree).

See docs/defs.md for the full rule reference.

Install

Add the registry to your .bazelrc:

common --registry=https://registry.fastverk.com/
common --registry=https://bcr.bazel.build/

In your MODULE.bazel:

bazel_dep(name = "rules_storybook", version = "0.1.0")

You’ll also need npm linking that exposes storybook as a js_binary-compatible target (typically via aspect_rules_js’s :node_modules/storybook/dir).

Quick start

load("@rules_storybook//storybook:defs.bzl", "storybook_build", "storybook_dev", "storybook_manifest")

# 1. The build (hermetic, CI-friendly).
storybook_build(
    name = "storybook",
    srcs = glob(["stories/**/*", ".storybook/**/*"]),
    deps = [
        "//packages/some-lib:lib",
        ":node_modules/storybook",
        ":node_modules/react",
    ],
    storybook_bin = ":node_modules/storybook/dir",
)

# 2. Manifest (drives .storybook/main.ts deterministically).
storybook_manifest(
    name = "stories_manifest",
    srcs = glob(["stories/**/*.stories.tsx"]),
    relative_to = ".storybook",
)

# 3. Dev server (escapes the sandbox; bazel run -> pnpm exec storybook dev).
storybook_dev(
    name = "dev",
    port = "6006",
)

Consume the manifest from .storybook/main.ts:

import manifest from "./stories-manifest.json";

export default {
  stories: manifest.stories,
  // ...
};

Hermeticity

storybook_build runs in a Bazel sandbox with:

  • STORYBOOK_DISABLE_TELEMETRY=1 — no phone-home.
  • NODE_ENV=production — production code paths.
  • TZ=UTC + SOURCE_DATE_EPOCH=0 — deterministic time-sensitive bundle metadata + emitted-artifact mtimes.

Determinism caveats:

  • All deps must be explicit. Storybook resolves modules via the package-local node_modules link, so deps must list every workspace lib whose stories live under your srcs, plus every npm dep those stories pull in.
  • The storybook_manifest rule expects pre-sorted srcs (handled internally — paths are lexically sorted before write) and re-emits only *.stories.ts(x) entries, so over-approximating the srcs glob is safe.

storybook_dev is not hermetic by design — Storybook’s dev server needs HMR + Vite on-demand bundle optim, both of which require live filesystem access outside the runfiles tree.

Compatibility

  • Bazel: 7.4+, bzlmod required.
  • Storybook: 7+ tested. Earlier versions may work; --output-dir + --quiet flag contracts have been stable.
  • Workspace shape: assumes pnpm for storybook_dev (shells out to pnpm exec storybook dev).

Contributing

Reference docs are stardoc-generated. After editing rule docstrings:

bazel run //docs:update

CI gates this via bazel test //docs/....

License

MIT.

Rules & providers#

Generated with Stardoc from the module's .bzl sources.

from docs/defs.md

User-facing rules for rules_storybook.

Three pieces:

  • storybook_build — runs storybook build as a Bazel action with explicit srcs + deps; output is the storybook-static/ tree. Forces STORYBOOK_DISABLE_TELEMETRY=1 + reproducibility env vars (TZ=UTC, SOURCE_DATE_EPOCH=0) so the action is deterministic across runners.
  • storybook_manifest — emits a deterministic JSON manifest of story file paths. .storybook/main.ts imports the manifest instead of globbing, so adding a story triggers an explicit Bazel-tracked input change.
  • storybook_dev — sh_binary macro: bazel run //path:dev invokes pnpm exec storybook dev against the live workspace source (HMR-friendly; not hermetic — intentional, for the dev loop).

Targets returning StorybookBuildInfo expose the build’s output tree programmatically so future rules (deploy targets, doc-site extractors) can consume builds without re-running storybook.

storybook_build

load("@rules_storybook//storybook:defs.bzl", "storybook_build")

storybook_build(name, deps, srcs, data, storybook_bin)

Run storybook build and emit storybook-static as a tree artifact.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
depsWorkspace + npm targets imported by stories. Brought into runfiles.List of labelsoptional[]
srcsAll Storybook config + story files.List of labelsrequired
dataAdditional runtime files (e.g. service worker bundle).List of labelsoptional[]
storybook_binStorybook CLI target, typically :node_modules/storybook/dir.Labelrequired

storybook_manifest

load("@rules_storybook//storybook:defs.bzl", "storybook_manifest")

storybook_manifest(name, srcs, out, relative_to)

Emit a deterministic JSON manifest of Storybook story files.

ATTRIBUTES

NameDescriptionTypeMandatoryDefault
nameA unique name for this target.Namerequired
srcsStory files to enumerate. May over-approximate; only *.stories.ts(x) entries land in the manifest.List of labelsrequired
outOutput filename. Defaults to <name>.json.Stringoptional""
relative_toPackage-relative root that consumed paths should be expressed against (matches Storybook’s stories: ['../foo.tsx'] convention from .storybook/main.ts).Stringoptional".storybook"

StorybookBuildInfo

load("@rules_storybook//storybook:defs.bzl", "StorybookBuildInfo")

StorybookBuildInfo(tree)

A storybook build output tree.

FIELDS

NameDescription
treeDirectory: the storybook-static output.

storybook_dev

load("@rules_storybook//storybook:defs.bzl", "storybook_dev")

storybook_dev(name, port, **kwargs)

bazel run //...:NAME invokes pnpm exec storybook dev.

Escapes the runfiles sandbox to run against the live workspace source for HMR. Intentionally NOT hermetic — that’s storybook_build’s job. This macro is the dev-loop counterpart.

PARAMETERS

NameDescriptionDefault Value
nametarget name.none
portdev server port. Defaults to 6006."6006"
kwargsforwarded to the underlying sh_binary (e.g. tags).none

Conformance#

No gate findings. 17 contested atoms. See how gating works or the full report.

Contested atoms

Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.

AtomResolved hereElsewhere
apple_support 1.24.2 2.2.0 ×1
aspect_bazel_lib 2.22.5 2.8.1 ×1
aspect_rules_js 3.1.2 2.1.3 ×1
bazel_lib 3.2.2 3.0.0 ×12
bazel_skylib 1.8.2 1.9.0 ×2
gawk 5.3.2.bcr.3 5.3.2.bcr.1 ×12
jq.bzl 0.4.0 0.1.0 ×12
nlohmann_json 3.6.1 3.12.0.bcr.1 ×1
package_metadata 0.0.2 0.0.5 ×3
protobuf 33.4 34.0.bcr.1 ×2
rules_jvm_external 6.7 6.8 ×4
rules_nodejs 6.7.4 6.3.0 ×16.7.3 ×1
rules_python 1.7.0 2.0.1 ×1
rules_swift 3.1.2 3.6.1 ×1
tar.bzl 0.10.4 0.5.1 ×110.6.0 ×1
upb 0.0.0-20220923-a547704 0.0.0-20230516-61a97ef ×1
yq.bzl 0.3.4 0.1.1 ×12

Dependencies#

rules_storybook in the registry graph — what it depends on (left) and what depends on it (right).

Depends on

platforms1.0.0bazel_skylib1.8.2aspect_bazel_lib2.22.5rules_shell0.6.1aspect_rules_js3.1.2rules_bun0.3.0rules_nodejs6.7.4devstardoc0.7.2dev

Versions#

2 published versions, newest first. Each resolves to an immutable, integrity-checked archive.

VersionIntegrity (sha256)Source archive
0.2.0 latest 9KIdIOWiniS5KEkV… tag archive ↗
0.1.0 IAf2Wor6yE4FzqAe… tag archive ↗

Changelog#

All notable changes to rules_storybook. The format is loosely Keep a Changelog — version headers mirror the published bazel-registry entries.

0.1.0 — initial release

  • Initial release of Bazel rules for [Storybook]: hermetic storybook build plus a deterministic story-manifest generator and a sandbox-escaping storybook dev runner for the HMR loop.
  • storybook_build runs storybook build as a Bazel action with STORYBOOK_DISABLE_TELEMETRY=1, TZ=UTC, and SOURCE_DATE_EPOCH=0 forced for reproducibility; output is the storybook-static/ tree.
  • storybook_manifest emits a deterministic JSON manifest of story file paths so .storybook/main.ts’s stories: [...] no longer relies on a non-deterministic glob; adding a story now triggers an explicit Bazel-tracked input change.
  • storybook_dev macro provides a bazel run entry point for pnpm exec storybook dev against the live workspace source (intentionally non-hermetic — HMR + watch + on-demand Vite optim).

← All modules