Static builds¶
A static build packages your registered Story catalogue into a directory of plain files you can publish anywhere. Use it for design review, documentation previews, or artifact hosting where the reviewer should not need your dev server. It is the Story shell itself, with every variant's canvas, docs, controls and status, not a set of screenshots.
It takes an entry namespace, a build, a host page, and one script. The names
below continue the my-app from the installation recipe.
1. An entry namespace that mounts only the shell. A published catalogue
gets its own entry, src/my_app/story_static.cljs:
(ns my-app.story-static
(:require [re-frame.core :as rf]
[re-frame.story :as rf.story]
[re-frame.adapter.reagent :as reagent-adapter]
[my-app.stories]))
(defn run []
(rf/init! reagent-adapter/adapter)
(rf.story/mount-shell! (js/document.getElementById "app")))
2. A build for it, beside your app's build in shadow-cljs.edn:
:story-static/my-app
{:target :browser
:output-dir "out/story-static/my-app"
:asset-path "."
:compiler-options {:closure-defines {re-frame.story.config/static-mode? true}}
:modules {:main {:init-fn my-app.story-static/run}}}
A release already drops shadow-cljs's dev-server connection. The
static-mode? define drops Story's own dev-time behaviour: the shell stops
polling for new registrations and does not pop the first-visit help overlay at
your readers. :asset-path "." keeps the bundle's references relative, so the
site works under any URL prefix.
3. A host page, resources/story-static.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>my-app stories</title>
<style>html, body, #app { height: 100%; margin: 0; }</style>
</head>
<body>
<div id="app"></div>
<script src="main.js"></script>
</body>
</html>
4. A script in package.json that releases the build and puts the host page
beside the bundle as index.html:
"story:build": "shadow-cljs release story-static/my-app && node -e \"require('fs').copyFileSync('resources/story-static.html', 'out/story-static/my-app/index.html')\""
The copy is spelled in Node so the same line runs under Windows cmd and a
POSIX shell. npm run story:build is also the command the Share dialog's
Static build row copies.
Run npm run story:build. After the :advanced compile, out/story-static/my-app/ holds index.html, main.js, and
shadow-cljs's manifest.edn. That directory is the site: serve it with a static file server, or publish the
directory to GitHub Pages or another static host. The
generator template's .gitignore already ignores out/.
A variant selected in the published catalogue still writes itself into the
address bar, so a link copied from the static site opens on that variant. What
the site leaves out is everything that only makes sense beside a live compiler:
hot reload, the registration poll, the first-visit overlay, and open-in-editor,
because a published bundle must not carry a path from the machine that built
it. Subscription pins are compiled out too, so a variant that relies on
:sub-overrides renders its real subscription values there
(chapter 3), and the
published site carries no Xray.
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
Host page cannot load main.js |
The HTML and bundle were not published together | Publish the whole output directory; keep its relative asset path. |
| The published state differs from development | The variant relied on subscription pins | Use real setup or a db seed for published variants. |
| Xray or editor links are absent | These development tools are omitted | Diagnose in a dev build; publish the catalogue for review. |
| The catalogue is empty | Its entry did not load your stories | Require the registrations from story-static. |