Thanks for your interest. This file covers the moving parts of the
workspace; for engine architecture see CLAUDE.md, and
for the canonical behaviour spec see docs/spec.md.
- Node.js ≥ 20 (CI runs 22)
- pnpm ≥ 9
- A local Chromium for
mockup:all(Chrome works; otherwise pointPUPPETEER_EXECUTABLE_PATHat a Chromium binary)
git clone https://github.com/PurpleReverie/reactwright.git
cd reactwright
pnpm installThe repo is a pnpm + Turborepo monorepo. Workspace globs:
packages/* # engine, templates, adapters
examples/* # runnable sample documents (not published)
# whole workspace
pnpm test # 129 unit tests
pnpm check # typecheck every package
pnpm mockup:all # render every example
# per-package
pnpm --filter reactwright test
pnpm --filter @reactwright/template-ieee check
pnpm --filter @example/story-bible mockupThe Turbo task graph (turbo.json) declares ^build dependencies, so
pnpm test builds upstream packages before running downstream tests.
See CLAUDE.md §"Where to add / modify" for the
touchpoint table. The two long checklists you'll most often consult:
- New IR primitive — IR type → factory + grammar/dispatch entry → resolver → renderer. See §"Where to add / modify".
- Making a node selectable by
<rule>— five touchpoints. See §"className propagation checklist".
Templates live in packages/template-*/src/. Each exports a
Template component (plus optional helpers like IEEEFrontMatter).
A template package's responsibility is the look — no engine-internal
imports beyond reactwright/jsx and the public types.
Each example is a workspace package (@example/*) with a mockup
script that drives the engine CLI against its entry .tsx. To add a
new example:
- Create
examples/<name>/with<name>.tsxand apackage.jsonmatching the existing examples (@example/<name>, private, workspace dependencies). - Add a one-paragraph
README.mddescribing what it demonstrates. pnpm install(registers the new workspace package).pnpm --filter @example/<name> mockup— must produce healthy.htmland.pdfoutputs inbuild/.
pnpm --filter reactwright testThe engine's tests live in packages/reactwright/tests/. Use
node --test's built-in assertions; no Jest, no Vitest. For changes
that touch the styling dialect, add a one-line case to
tests/styles-integration.test.tsx as well.
For HTML-emit refactors that should be byte-stable, snapshot
build/mockups/*.html before the change and diff after.
Reactwright uses Changesets.
Every PR that changes published behaviour needs a changeset.
pnpm changesetThe CLI asks which packages changed and the bump kind (patch,
minor, major); it writes a .changeset/<random>.md file
containing the prompt for that release's changelog. Commit it
alongside your code.
On merge to main, the release workflow:
- Sees the pending changesets and opens (or updates) a "Version
Packages" PR that runs
changeset version— bumpingpackage.jsons, regeneratingCHANGELOG.mds, and deleting the consumed changeset files. - When that PR merges, the workflow runs
changeset publish, which pushes the bumped packages to npm.
If you're only changing internal tooling, examples, docs, or CI configuration, no changeset is needed.
- Imperative subject, under 70 characters when possible.
- Body wraps at ~72 columns and explains the why.
- Group related changes per commit; avoid blob commits that touch many unrelated files.
When reporting a bug, please include:
- A minimal
.tsxreproduction (the smaller, the faster a fix lands). - The exact
pnpm, Node, and OS versions. - For PDF-rendering issues: the Chromium build / Chrome version Puppeteer connected to.
Be kind. Be specific. Be willing to read someone else's code with charity. If a maintainer asks for a change, please assume there's a reason; if you disagree, say so and we'll discuss it.