zudo-sg.config.mjs
Every field of the host zudo-sg.config.mjs file, its defaults, and the zfb composition snippet.
zudo-sg.config.mjs is the host project's config file, read by both the zudo-sg CLI (see CLI) and the zfb.config.ts composition helper below. It is plain data — a bare import() of its default export — so it never imports TypeScript or node: builtins.
Fields
interface ZudoSgConfig {
componentsRoots: Array<{ dir: string; importBase: string }>;
registryOut: string;
categoryOrder: string[];
uiPackageName?: string;
barrelIndex: string | null;
tokens?: { cssFiles: [string, string]; manifestOut: string };
previewStyles: string;
previewCssUrl?: string;
routes?: Record<string, string | false>;
catalog?: { title?: string; intro?: string };
}This is the shape read by the zudo-sg CLI. The same file is also passed as withZudoSg()'s second argument in zfb.config.ts, which accepts a few compose-only fields beyond this list — registry, externalPreview, chromeDefaults, headerTokenTrigger, zdtpApplyProxy — that the CLI never reads. See Descriptor mode & external preview for those.
| field | type | default | meaning |
|---|---|---|---|
componentsRoots | Array<{ dir, importBase }> | required | One entry per story corpus to scan. dir is project-root-relative (e.g. "packages/); importBase is the package-scoped import specifier prefix used in generated registry imports (e.g. "@zudo-). |
registryOut | string | required | Project-root-relative output path for the generated story registry (e.g. ".). This is also the routes plugin's registryModule. |
categoryOrder | string[] | required (may be []) | Display order for story categories. Categories not listed are appended alphabetically after these — never dropped, never an error. |
uiPackageName | string | omitted | npm package name components are imported from in generated usage snippets and catalog labels (e.g. "@zudo-sg/demo-ui"). When omitted, scaffolded usage snippets import from the component's own relative module. |
barrelIndex | string | null | required | Project-root-relative barrel file new-component inserts an export into, or null for a project with no barrel-file convention. |
tokens | { cssFiles, manifestOut } | omitted | Optional. Needed only for gen-token-manifest and the / dashboards. When omitted, gen-token-manifest exits with an error, zudoSg() passes no tokensManifestModule, and the / route renders its header with an empty-state note. gen-registry and new-component never read it. |
tokens.cssFiles | [string, string] | required when tokens is set | [tokensCssPath, colorsCssPath], project-root-relative. Position is significant: index 0 feeds spacing/font/size tokens, index 1 feeds the palette and semantic color tokens. |
tokens.manifestOut | string | required when tokens is set | Project-root-relative output path for the generated design-token manifest. |
previewStyles | string | required | Project-root-relative path to the host's preview stylesheet entry (compiled standalone by the preview-css plugin). |
previewCssUrl | string | / | URL the compiled preview stylesheet is served/emitted at. |
routes | Record<string, string | false> | see below | Overrides for the four catalog route patterns. componentsPreview and tokens also accept false to disable that route entirely; componentsIndex and componentsSlug cannot be disabled. |
catalog | { title?, intro? } | { title: "Component catalog" } | Catalog page heading text. |
routes defaults
| key | default pattern |
|---|---|
componentsIndex | / |
componentsSlug | / (must contain the [slug] segment) |
componentsPreview | / |
tokens | / |
A host pages/ file with the same URL shape silently shadows the injected route (zfb precedence) — this is the documented escape hatch, not a bug.
No route segment may start with _
zfb silently drops any route segment beginning with an underscore when it builds the static site — the page compiles with no error, but the route never appears in the output. This applies to every routes.* pattern here and to externalPreview.url (seeDescriptor mode & external preview) alike: a value like/ or / silently produces no route at all rather than failing the build. Tracked upstream atTakazudo/zudo-front-builder#3183.
Example
// zudo-sg.config.mjs
/** @type {import("@takazudo/zudo-sg/cli").ZudoSgConfig} */
export default {
componentsRoots: [{ dir: "packages/demo-ui/src", importBase: "@zudo-sg/demo-ui/src" }],
registryOut: "./src/styleguide/sg-registry.ts",
categoryOrder: ["Actions", "Typography", "Layout", "Forms"],
uiPackageName: "@zudo-sg/demo-ui", // optional: usage snippets and catalog labels
barrelIndex: "packages/demo-ui/src/index.ts",
tokens: {
cssFiles: ["packages/demo-ui/styles/tokens.css", "packages/demo-ui/styles/colors.css"],
manifestOut: "./src/config/ui-design-tokens-manifest.ts",
},
previewStyles: "./src/styles/preview-entry.css",
};Composing into zfb.config.ts
withZudoSg(presetFragment, sgConfig) (from @takazudo/) appends the engine's plugin descriptors and one componentDocs* content collection per componentsRoots entry to a zudo-doc preset fragment. Engine plugins are appended AFTER the preset's — the routes plugin requires the zudo-doc routes descriptor to already be present.
Component MDX docs per components root
Each componentsRoots[i] gets its own collection — componentDocs for index 0, componentDocs1, componentDocs2, … after it — rooted at that entry's dir and including **/*.mdx. An optional doc co-located with a story (<dir>/<path>/<name>.mdx next to <name>.stories.tsx) renders as a trailing section on that component's detail page. withZudoSg also passes the routes plugin a data-only componentDocs option — one { keyPrefix, collection } pair per root, where keyPrefix is the root's registry key prefix (dir with a leading packages/ removed, e.g. "packages/ → "demo-ui/src", "demo-ui" → "demo-ui") — so the detail route looks each story up in the collection of the root its registry key belongs to (the longest matching prefix wins). A routes plugin descriptor written by hand without componentDocs renders no component docs.
import { defineConfig } from "@takazudo/zfb/config";
import { zudoDocPreset } from "@takazudo/zudo-doc/preset";
import { withZudoSg } from "@takazudo/zudo-sg/config";
import zudoSgConfig from "./zudo-sg.config.mjs";
import { settings } from "./src/config/settings";
const preset = zudoDocPreset({ settings /* , ... */ });
export default defineConfig({
framework: "preact",
...preset,
...withZudoSg(
{ collections: preset.collections, plugins: preset.plugins },
zudoSgConfig,
),
});packageOwnedRoutes: true is required
The engine's routes plugin imports virtual:zudo-doc-route-context andvirtual:zudo-doc-chrome-bindings, which only zudo-doc's own routes plugin registers. The host's settings.packageOwnedRoutes must be true, and the zudo-doc preset's plugins must be listed before the engine's (whichwithZudoSg already guarantees).