@drupal-canvas/workbench
v0.2.0
Published
Canvas Workbench is a local preview and development app for Drupal Canvas Code Components, inspired by Storybook. It scans your project, lists discovered components and pages, and renders previews in an isolated frame.
Readme
@drupal-canvas/workbench
Canvas Workbench is a local preview and development app for Drupal Canvas Code Components, inspired by Storybook. It scans your project, lists discovered components and pages, and renders previews in an isolated frame.
Workbench has no required configuration. If your project uses the default Canvas layout, you can run it from your project root:
npx @drupal-canvas/workbench@latestInstallation
Install Workbench:
npm install @drupal-canvas/workbenchThen run it from your project root:
npx canvas-workbenchThe canvas-workbench binary starts the packaged Workbench Vite runtime in your
current working directory.
Configuration
Workbench can run without a canvas.config.json file, but it is useful to add
one when your project does not use the default Canvas paths, or when you want
Workbench to match your CLI setup.
Create canvas.config.json in your project root and set only the options you
need:
{
"componentDir": "./components",
"pagesDir": "./pages",
"aliasBaseDir": "src",
"globalCssPath": "./src/components/global.css"
}Workbench reads these options:
| Property | Default | Used for |
| --------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| componentDir | process.cwd() | Root directory Workbench scans for component.yml, *.component.yml, source files, and mocks. |
| pagesDir | "./pages" | Directory Workbench scans for page specs such as pages/home.json. |
| aliasBaseDir | "src" | Base directory for resolving @/ imports inside component source files. |
| globalCssPath | "./src/components/global.css" | Global CSS entrypoint loaded into the preview iframe. This is where Workbench picks up shared styles and Tailwind setup. |
If canvas.config.json is not present, Workbench uses those defaults.
outputDir is part of the wider Canvas config surface, but Workbench does not
use it.
User docs
For end-user guidance, see: https://project.pages.drupalcode.org/canvas/code-components/workbench/
How the Workbench runtime works
Published output
dist/clientcontains the packaged browser app sources and static assets, including the copied client and shared source trees, and copied public assets.dist/servercontains the packaged Node-side runtime, including thecanvas-workbenchbinary and the published Vite config entry.
Packaged runtime
- The published binary resolves Vite from the installed package and launches it
against
dist/clientwith the packaged server config fromdist/server. - The server build bundles the internal helper packages
@drupal-canvas/discoveryand@drupal-canvas/vite-compat. - The packaged client is served from packaged source files through the Workbench Vite runtime, not from a standalone production-built browser bundle.
- The packaged runtime:
- Exposes discovery data at
/__canvas/discoveryas JSON for the UI. - Exposes preview manifest data at
/__canvas/preview-manifestas JSON for preview runtime decisions. - Uses routes:
/component/<component-id>for component previews./page/<slug>for discovered pages, whereslugcomes frompages/<slug>.json.
- Exposes discovery data at
- Watches the host project for relevant file changes (
component.yml,*.component.yml, and JS(X)/TS(X)/CSS files), sends targeted HMR update events, refreshes discovery when needed, and reloads only the preview iframe for source-only changes.
Strict preview MVP contract
Workbench preview currently uses a strict compatibility contract.
- Workbench renders previews in an iframe at
/__canvas/preview-frame. - A discovered component is previewable only when its JS entry exists and has a
supported extension (
.js,.jsx,.ts, or.tsx). - Workbench imports component modules through Vite
@fsURLs, from the Workbench Vite process. - The preview iframe requires a renderable
defaultexport from each component module. - Optional component CSS entries are loaded in the iframe document when present.
Compatibility notes
Workbench does not ingest arbitrary host Vite config/plugins automatically.
- Supported module resolution via
@drupal-canvas/vite-compat— seepackages/vite-compat/README.md - Tailwind entrypoint: Workbench loads the host's global CSS (default
src/components/global.css, configurable viaglobalCssPathincanvas.config.json) through a virtual Vite CSS module that imports the host CSS and includes explicit host@sourcescanning so Tailwind processing is applied in Workbench context.
Current architecture decision
Workbench currently uses one Vite dev server process for both:
- the Workbench UI shell, and
- the preview iframe runtime.
The published package keeps that same model. dist/server starts Vite against
the packaged client sources in dist/client, rather than serving a separately
built static browser bundle.
Why this is the current choice
- One startup command and one process simplify local DX while the feature set is still evolving.
- Discovery middleware, preview manifest APIs, and host compatibility behavior stay in one place.
- Shared dev-server context keeps iteration fast for early prototype work.
Trade-offs we accept for now
- Compatibility changes for host preview imports can still affect Workbench runtime behavior.
- Alias and module-resolution boundaries require explicit guardrails (
@wb/*vs host@/...). - Debugging can span Workbench UI, iframe runtime, host imports, and shared Vite config.
- Prebundle and dedupe choices are global to one server process and can introduce coupling.
Triggers to split architecture later
Move to stronger separation when one or more of these become recurring:
- frequent regressions from cross-impact between Workbench UI and host preview compatibility,
- the need for materially different plugin stacks between Workbench UI and preview runtime,
- recurring React/runtime duplication issues that are hard to contain with current guardrails,
- growing demand for clearer ownership boundaries and independent deployment/runtime controls.
Future: static export mode outline
Workbench does not currently support a Storybook-style static export of host
component previews. The current dist/client output is packaging-oriented for
the Workbench Vite runtime, not a deployable static export. This section
captures a potential direction for later work.
Goal
Produce a static directory that can be hosted without a running Vite dev server, while preserving a useful subset of Workbench preview behavior.
Current blockers
- Discovery and preview manifest are generated by dev middleware at request time.
- Preview module URLs are Vite dev
@fsURLs, not portable build artifacts. - Host component transforms currently depend on live Vite pipeline behavior.
Potential design direction
- Add a dedicated export command (for example,
canvas-workbench export). - Run discovery once at export time and write a static preview manifest JSON.
- Bundle each previewable host component into export artifacts and emit stable module URLs in the manifest.
- Emit a static global CSS asset strategy (instead of virtual-module runtime import).
- Build Workbench UI and preview iframe against those static manifest/assets.
