download 01 / Install
Install Stitch
npm i @vkdatta/stitch -g
Stitch is a build tool for your website — and for any project made of text files. Install it globally, then run it inside the project you build and deploy.
stitch build # compose src/ into dist/
stitch dev # build, serve, and rebuild on every change
stitch reverse # rebuild src/ from a built dist/
stitch help
folder_open 02 / Structure
Keep your source organized
project/
├── src/
│ ├── index.html
│ ├── repo.html
│ ├── components/
│ │ ├── header.html
│ │ └── footer.html
│ ├── data/
│ │ └── version.txt
│ ├── style.css
│ └── script.js
└── package.json
Stitch reads src/ and writes the deployable site to dist/. Static assets are copied into dist/stitch_assets/. Every text file — HTML, JavaScript, CSS, plain text, source code in any language — is processed for Stitch directives; binary files are copied as they are.
extension 03 / Components
Consume a component
<stitch src="components/header.html"></stitch>
<main>
<h1>Hello</h1>
</main>
<stitch src="components/footer.html"></stitch>
Paths are resolved relative to the file containing the tag. This lets nested files reference components relative to their own location. The referenced file may itself contain additional <stitch src> calls — composition is recursive.
Extension handling
When the referenced path has no extension, Stitch tries .html first, then a file with exactly that name (such as Makefile). A path with an extension is used as written — and it may be any text file, not only HTML. See Any Language.
<stitch src="/tags/opening"></stitch>
resolves as: src/tags/opening.html
<stitch src="data/version.txt"></stitch>
resolves as: src/data/version.txt
data_object 04 / Data
Reuse one component with different values
A reusable component declares placeholders:
<stitch reusable></stitch>
<article class="card">
<span>{{icon}}</span>
<h2>{{title}}</h2>
</article>
A caller supplies values through data-* attributes:
<stitch src="components/card.html"
data-title="API"
data-icon="bolt"></stitch>
Stitch produces:
<article class="card">
<span>bolt</span>
<h2>API</h2>
</article>
Substitution happens at build time. The same component can be consumed repeatedly with different values. Substitution may occur in text or attributes, in any file type, and values can be passed by id too: $stitch-drop('card', data-title="API"). The <stitch reusable> declaration itself never appears in generated output.
If a caller supplies data-* values but the target does not declare <stitch reusable>, Stitch pauses the build and asks whether the target should be marked reusable. The user may approve the conversion or abort.
build 05 / Build
Build your site
npx stitch build
The generated dist/ directory is the deployable output. Deploy dist/, not src/. Manual changes to generated files are not durable — always modify src/, then rebuild.
npx stitch build --src src --out dist # explicit folders
npx stitch build --no-reverse # clean production output (no markers, no manifest)
npx stitch build --asset-dir . # non-HTML files at the output root
npx stitch dev # build + serve + rebuild on change
By default a build also records what stitch reverse needs and verifies it. Use --no-reverse for the files you actually ship.
Before → after
Source
<header>
...
</header>
<stitch src="components/footer.html"></stitch>
Generated output
<header>
...
</header>
<footer>
...
</footer>
The browser does not need to understand <stitch>. It receives finished HTML directly with no component-fetching requests and no runtime component parser.
bolt 06 / Dev Server
stitch dev — build, serve, rebuild
npx stitch dev
npx stitch dev --port 8080
npx stitch dev --src website --out public --port 4000 --host 0.0.0.0
Builds your project once, serves the output directory, watches src/ recursively, and rebuilds on every change. Pages that are open in the browser reload by themselves.
What it does
- serves
dist/athttp://localhost:3000(change with--port/--host); - watches every directory under
src/, including ones you create while it runs, and debounces bursts of saves into one rebuild; - injects a tiny live-reload script into the served HTML only — the files in
dist/stay clean; - emulates the generated
_redirectsrules, so routes such as/privacywork locally; - works for every file type Stitch builds — editing a fragment such as
version.txtrebuilds the files that include it.
Errors do not stop the server
A build error — a duplicate id, a missing file, a cycle — is printed in the terminal and the server keeps serving the last good output. Fix the file and save; the next rebuild clears the error.
🔴 STITCH DEV BUILD ERROR
Duplicate stitch id found. Every <stitch id="..."> must be unique:
id "version" is declared 2 times:
- src/a/version.txt:1
- src/b/version.txt:1
stitch dev builds with reverse markers and a manifest (see stitch reverse). Ship the output of stitch build --no-reverse.
terminal 07 / Any Language
Not just HTML — stitch any text file
Stitch directives are plain text, so they work in any text file: .js, .mjs, .css, .c, .h, .py, .txt, .json, .md, and files with no extension at all. Split a file into as many pieces as you like and drag them back together with a tag.
src/main.js
window.DELLUNA_SITE = {
version: "<stitch src='version.txt'></stitch>",
registry: "<stitch src='registry.txt'></stitch>",
base: "<stitch src='base.txt'></stitch>"
};
plus version.txt, registry.txt and base.txt, each holding one value.
dist/stitch_assets/main.js
window.DELLUNA_SITE = {
version: "v0.0.111",
registry: "https://cdn.jsdelivr.net/gh/vkdatta/delluna@v0.0.111/registry",
base: "https://cdn.jsdelivr.net/gh/vkdatta/delluna@v0.0.111"
};
The tag is replaced exactly where it stands — inside a string, a comment, or on a line of its own.
How it behaves in non-HTML files
- Fragments are not emitted. A file consumed by
<stitch src>or$stitch-droplives inside its consumers, exactly like a consumed HTML component. Only the host is written todist/. - Hosts keep their path.
src/main.jsbecomesdist/stitch_assets/main.js, like every other non-HTML file. - One trailing newline is trimmed from an included text file (and a leading BOM dropped), so the newline your editor adds at the end of
version.txtnever breaks the string it lands in. - Includes nest. A fragment may include other fragments, in any language mix: a
.jsfile may include an.htmlsnippet, an HTML page may include a.cssor.jsfile inside<style>/<script>. - Slots work everywhere.
<stitch reusable>with{{slot}}anddata-*values is not HTML-specific. - Only text is stitched. Binary files (images, fonts, archives, anything with NUL bytes or invalid UTF-8) are copied untouched and cannot be included.
- Other text is left alone. In a non-HTML file only tags carrying a Stitch attribute (
src,id,reusable,off) are directives.routeandloaderhave no meaning outside HTML and produce a warning.
Building a project that is not a website
By default non-HTML output goes under stitch_assets/. For a C, Python or any other project, emit it at the output root instead:
src/
├── main.c ← <stitch src="body.c"></stitch>
├── body.c
└── config.h
npx stitch build --src src --out build --asset-dir .
build/
├── main.c ← composed
└── config.h
body.c was consumed, so it is not emitted. Run your compiler on build/.
tag 08 / id & stitch-drop
Name a file once, drop it anywhere
Give any source file — reusable or not, HTML or not — an id at its head. Then drop it by that name from any other file, without caring where it lives.
src/version.txt
<stitch id="version"></stitch>
v0.0.111
src/main.js
window.DELLUNA_SITE = {
version: "$stitch-drop('version')",
registry: "$stitch-drop('registry')",
base: "$stitch-drop('base')"
};
dist/stitch_assets/main.js
window.DELLUNA_SITE = {
version: "v0.0.111",
registry: "https://cdn.jsdelivr.net/gh/vkdatta/delluna@v0.0.111/registry",
base: "https://cdn.jsdelivr.net/gh/vkdatta/delluna@v0.0.111"
};
registry.txt and base.txt are headed with <stitch id="registry"> and <stitch id="base"> the same way.
The two forms are equivalent
| By path | By id |
|---|---|
<stitch src="version.txt"></stitch> |
$stitch-drop('version') |
<stitch src="card.html" data-title="API"></stitch> |
$stitch-drop('card', data-title="API") |
Pick by path when the file location is the point; pick by id when callers should survive a file being moved or renamed.
Rules
- an id declaration is
<stitch id="name"></stitch>; the whole file is what gets dropped; - when the declaration sits alone on its line, the whole line disappears, so the first line of
version.txtdoes not become a stray blank line; - the argument may be quoted with
',"or`, or left bare:$stitch-drop(version); - after the id,
data-*values are passed to reusable files, separated by commas or spaces; - an id is a name without spaces, quotes, parentheses, commas or angle brackets;
- a file declares one id; a tag cannot combine
srcwithid; - dropped files are fragments: they are not emitted on their own, and they may drop further ids (cycles are a hard error);
- ids work in HTML files too, and are removed from the output like every other declaration.
Every id must be unique across the entire source tree, HTML and text files together. A duplicate fails the build and lists every declaration with its file and line:
Duplicate stitch id found. Every <stitch id="..."> must be unique:
id "version" is declared 2 times:
- src/a/version.txt:1
- src/b/version.txt:2
Dropping an id nobody declared is also a hard error, with a "did you mean" suggestion and the list of declared ids.
toggle_off 09 / off
off — leave a directive as plain text
Add off to a directive and Stitch ignores it completely: it is not resolved, not stitched, not stripped, and not rewritten — even if the file it names really exists.
<stitch src="location" off></stitch>
<stitch id="version" off></stitch>
$stitch-drop('version', off)
What happens to it
- the text appears in the output exactly as written, including the
offattribute; - it takes no part in the dependency graph, so a missing target is not an error and an
offid never collides with a real one; - it works on every directive:
src,id,reusable,route,loaderand$stitch-drop; off="false",off="0"andoff="no"mean not off.
When to use it
- writing documentation about Stitch inside a Stitch project (Markdown, text, source comments);
- switching an include off temporarily without deleting the line;
- a string in your own code that happens to look like a directive.
No <stitch> directive may remain in generated output — except a directive you explicitly marked off. In HTML, an off tag stays as an unknown element the browser ignores. To print a directive on an HTML page without any leftover, escape it as you always have: <stitch ...> and $stitch-drop(...).
undo 10 / Reverse
stitch reverse — turn dist back into src
npx stitch build # src -> dist (+ dist/.stitch/manifest.json)
npx stitch reverse --src restored # dist -> restored/ (byte-identical to src)
npx stitch reverse --check # compare dist's source against ./src, write nothing
Every stitch build records how each output was produced, so the built output can be turned back into the exact source files. This works for HTML and for every other text file Stitch composed.
What a build records
- Markers in built HTML:
<!--stitch:begin 12 path/to/part.html-->…<!--stitch:end 12-->around every inlined HTML component, and<!--stitch:drop N-->where a routed target was dropped. Non-HTML files never get markers — a comment in HTML is not a comment in JavaScript or C. - A manifest at
dist/.stitch/manifest.json: the original tags, a lossless patch per transformation (asset-URL rewriting,{{slot}}substitution, tag stripping, inlined text), file modes, and the full content of files that never reachdist/— orphan components and text fragments such asversion.txt.
Options
| Flag | Meaning |
|---|---|
--out <dir> | The built directory to read. Default dist. |
--src <dir> | Where to restore the source. Default src. |
--check | Compare the restored source with --src; write nothing; exit 1 on any difference. |
--overwrite | Allow writing into a non-empty --src. Without it Stitch refuses. |
--manifest <file> | Manifest location, if it was kept outside dist/. |
build --no-reverse | Produce clean output: no markers, no manifest. Use it for production. |
Guarantees
- every build re-runs the reverse in memory and prints
✔ Reverse check— or lists the files that would not restore identically; - edits made to built files after the build flow back into the right source file, and Stitch warns when it sees them;
- an edit that destroys generated content is reported as an error instead of silently restoring the wrong text.
recycling 11 / Component Lifecycle
Only consumed components disappear
A file becomes a consumed component when another file references it through <stitch src="..."> or $stitch-drop('id'). Its contents are embedded into the consumer, so that source file is omitted from dist/. This holds for any text file: a version.txt dropped into main.js is not emitted on its own.
Unused HTML files and ordinary assets remain. CSS, JavaScript, images, fonts, manifests, JSON, PDFs, and other files are copied — non-HTML static source files go into dist/stitch_assets/.
lightbulb 12 / Why Stitch
Runtime imports are convenient. Build-time imports are faster.
Stitch is a build-time composition processor. It allows a developer to split a large project — HTML first, but equally JavaScript, CSS, or source code in any language — into modular files, recursively compose those files during the build, and deploy ordinary static output.
The problem with runtime composition
A runtime component processor improves source modularity but shifts composition work onto every visitor:
- component HTML may require additional network requests;
- component assembly begins only after the browser starts loading;
- runtime JavaScript must locate and process component tags;
- every visitor repeats the same composition work;
- the deployed website depends on a custom component runtime.
What Stitch gives you
- Easy file management
- Reusable components with build-time data substitution
- Recursive nested composition, in HTML and in any other text file
- Files named by
idand dropped anywhere with$stitch-drop - Lossless
stitch reverseand a livestitch devserver - Fast sites — no component-loader JavaScript shipped to visitors
- Host-native routing via
_redirects
Build time may increase slightly because Stitch performs assembly before deployment. That cost happens once per build instead of being paid by every visitor.
SOURCE → ZAP BUILD → DIST → STATIC HOST / CDN → BROWSER
There is no Stitch component loader running in the deployed website.
compare 13 / Comparison
How Stitch compares to other approaches
Rough conceptual ranges assuming the network response has already arrived. Network latency can dominate all of these numbers.
| Method | Assembly happens | Initial network requests | Time to usable page* | Browser CPU | HTML transfer size | Best for |
|---|---|---|---|---|---|---|
| Stitch (build-time) | Once during build | 1 page + assets | ~10–100 ms browser-side assembly | Very low | Higher | Static sites / docs |
| Plain static HTML | Developer manually | 1 page + assets | ~10–100 ms | Very low | Higher | Small / simple sites |
| JS fetch components | Every visitor | Many / additional | ~100–1000+ ms | Medium–high | Lower initial HTML | Rarely ideal for static sites |
| JS <template> cloning | Every visitor | 1 HTML + JS | ~20–300 ms | Medium | Lower HTML | Large dynamic repeated UI |
| Web Components | Every visitor | HTML + JS | ~30–500 ms | Medium | Lower HTML | Reusable interactive UI |
| Server-side includes (SSI) | Every request | 1 page + assets | ~5–100 ms server assembly | Very low | Normal | Traditional server sites |
| SSR / server rendering | Every request or cache miss | 1 page + assets | ~20–500+ ms server work | Low | Normal | Dynamic / user-specific pages |
| Edge rendering | At CDN edge / cache miss | 1 page + assets | ~10–200 ms | Low | Normal | Personalized / global apps |
| Static site generator | Once during build | 1 page + assets | ~10–100 ms | Very low | Higher | Static sites / docs |
| Hybrid: static + JS enhancement | Static at build, dynamic parts runtime | 1 page + JS | ~10–150 ms | Low | Balanced | Modern content-heavy sites |
* Time to usable page is a rough conceptual range assuming the network response has arrived.
account_tree 14 / Architecture
Current Architecture
Stitch is intentionally a build-time system. Its responsibility ends when the final deployable files have been generated.
src/
│
├── modular HTML files
├── text files in any language (JS, CSS, C, Python, TXT ...)
├── nested directories
├── reusable components, ids
├── routed pages
├── images / fonts / other binary assets
│
▼
ZAP BUILD
│
├── scan every text file for directives
├── validate routes and ids (ids must be unique)
├── build dependency graph (src= and $stitch-drop)
├── detect cycles
├── recursively compose HTML and text files
├── perform data-* substitution
├── strip Stitch directives (except those marked off)
├── emit public HTML pages
├── emit composed text files; consumed fragments are not emitted
├── centralize static assets → dist/stitch_assets/
├── rewrite local asset URLs
├── record markers + manifest for stitch reverse
└── generate host routing rules → dist/_redirects
│
▼
dist/
│
├── index.html
├── routed HTML files
├── stitch_assets/
├── .stitch/manifest.json (unless --no-reverse)
├── _redirects (when routes exist)
└── host configuration files at root
│
▼
STATIC HOST / CDN → REAL BROWSER NAVIGATION
Stitch does not replace browser navigation. Clicking a normal internal link performs normal navigation. The host serves the destination page. The browser loads and renders that page as an ordinary HTML document.
What Stitch does not need
- no route runtime;
- no route manifest;
- no client-side page fetcher;
- no body replacement;
- no navigation interception;
- no route cache;
- no transition loader;
- no lazy / JIT route resource system;
- no automatically injected Stitch runtime JavaScript.
route 16 / Path Resolution
Component Path Resolution
Stitch resolves component paths relative to the file containing the <stitch src> call, unless the path explicitly indicates the source root. This applies to every file type — a .js, .css or .c file resolves its includes the same way an HTML file does.
| Style | Example | Resolution |
|---|---|---|
| Relative | ./header |
Relative to the current HTML file. |
| Parent relative | ../shared/header |
Relative to the parent directory of the current file. |
| Source-root | tags/header |
Resolved from the source root. If nothing exists there, the file next to the one containing the tag is tried, so sibling files can simply be named. |
| Explicit source-root | src/tags/header |
The src/ prefix is removed; resolution starts at the source root. |
| Leading slash shorthand | /tags/header |
Source-root shorthand — resolved inside src/, not the OS filesystem root. |
Extensions
| Written | Stitch looks for |
|---|---|
header | header.html, then a file named exactly header |
Makefile | Makefile.html, then Makefile |
version.txt | exactly version.txt — any text extension works |
A directive can point only at a text file. Pointing at an image or any other binary file is a hard error. $stitch-drop('id') needs no path at all: it finds the file by its id.
A resolved component path must remain inside the source directory. Any reference that escapes the source root is a hard build error.
repeat 17 / Reusable Components
Reusable Components & Data Substitution
Rules
- substitution happens during the build;
- the same component may be consumed multiple times with different values;
- raw component source must not be permanently cached as one rendered result;
- substitution may occur in text or attributes;
- reusable components may consume other components recursively;
- reusable works in any text file, and values can be supplied through
$stitch-drop('id', data-name="value")as well as<stitch src>; - values are inserted literally — characters such as
$&or$1in a value are never treated specially; - the reusable declaration is removed from output.
Source files are normally read-only from Stitch's perspective. The explicit user-approved reusable conversion (triggered by the interactive warning) is the only exception.
fork_right 18 / Routing
Static Host Routing
Routing is a deployment concern, not a browser-side Stitch runtime concern.
How explicit routes work
src/fx/fx_counter.html
contains: <stitch route="/fx_counter"></stitch>
Stitch emits:
dist/fx/fx_counter.html
And generates the host rule:
/fx_counter /fx/fx_counter.html 200
Result:
example.com/fx_counter → host routing → dist/fx/fx_counter.html → browser
The route controls the public URL. The source file's relative location controls where the generated HTML is written inside dist/.
_redirects generation
When one or more explicit routes exist, Stitch generates dist/_redirects. Each route uses an HTTP 200 rewrite so the visible URL remains the route while the host serves the generated HTML file.
Route validation rules
- an explicit route must begin with
/; - duplicate route values are forbidden (hard error);
- routes are URL paths, not output directories;
- routed files are standalone public pages.
A routed HTML file cannot be consumed inline through <stitch src>. Stitch emits a warning, removes that reference from the caller, and continues building. The correct way to reach a routed page is ordinary navigation: <a href="/privacy">Privacy</a>.
storage 19 / Static Assets
Centralized Asset Output
Non-HTML static source files are copied into a single owned output directory:
src/style.css → dist/stitch_assets/style.css
src/script.js → dist/stitch_assets/script.js
src/images/logo.svg → dist/stitch_assets/images/logo.svg
Text files that use directives are written composed, at the same relative path. Text files consumed by another file are fragments and are not written at all. With --asset-dir . everything lands at the output root instead of stitch_assets/ (for non-web projects).
Asset URL rewriting
Because assets are centralized during the build, Stitch resolves each local asset reference and rewrites the generated URL to the final public asset path.
<link rel="stylesheet" href="../style.css">
→ <link rel="stylesheet" href="/stitch_assets/style.css">
<img src="../../images/logo.svg">
→ <img src="/stitch_assets/images/logo.svg">
URL suffix preservation
Query strings and fragments are preserved during rewriting: ../style.css?v=3 → /stitch_assets/style.css?v=3
External URLs not rewritten
URLs beginning with https://, http://, //, data:, javascript:, mailto:, tel:, or a bare #fragment are never modified.
Resource-bearing attributes rewritten
link[href] script[src] img[src] source[src] video[src]
video[poster] audio[src] iframe[src] embed[src] object[data]
track[src] input[src] srcset
wrangler.toml is deployment configuration, not a browser asset. It must not be copied into stitch_assets/ — it is preserved at the root of dist/.
output 20 / Output Rules
What Goes Into dist/
- root
src/index.htmlis emitted asdist/index.html; - HTML files with explicit
<stitch route>are emitted at their mirrored relative locations; - consumed component files are not emitted as standalone public HTML;
- non-HTML static assets are copied under
dist/stitch_assets/(or the output root with--asset-dir .); - text files that use
<stitch src>/$stitch-dropare emitted composed; - text files consumed by another file are fragments and are not emitted;
dist/.stitch/manifest.jsonis written forstitch reverseunless--no-reverseis used;- deployment configuration files that must remain at the deployment root are preserved appropriately.
Full example
src/
├── index.html
├── style.css
├── script.js
├── wrangler.toml
├── tags/
│ ├── opening.html
│ └── closing.html
├── pages/
│ ├── privacy.html ← <stitch route="/privacy">
│ └── support.html
└── fx/
├── fx_counter.html ← <stitch route="/fx_counter">
└── fx_clamp.html ← <stitch route="/fx_clamp">
↓ npx stitch build ↓
dist/
├── index.html
├── _redirects
├── wrangler.toml
├── stitch_assets/
│ ├── style.css
│ └── script.js
├── pages/
│ ├── privacy.html
│ └── support.html
└── fx/
├── fx_counter.html
└── fx_clamp.html
error 21 / Validation
Errors & Warnings
| Situation | Severity | Behaviour |
|---|---|---|
<stitch src> target does not exist |
Hard Error | Stop the build; clearly show the caller and resolved missing path. |
| Target is a binary file | Hard Error | Stop — only text files can be stitched; binary files are rejected. |
Duplicate <stitch id> |
Hard Error | Stop and list every duplicated id with each file and line. |
$stitch-drop of an undeclared id |
Hard Error | Stop; show the caller, a "did you mean" hint and the declared ids. |
Invalid id, more than one id per file, src combined with id, malformed $stitch-drop(...) |
Hard Error | Stop and show the file and line. |
| Circular component dependency | Hard Error | Stop and show the complete dependency chain. |
| Path escapes source root | Hard Error | Stop with a path traversal error. |
| Duplicate explicit route | Hard Error | Stop and show both source files. |
Route does not begin with / |
Hard Error | Stop and show the invalid route and source file. |
<stitch src> points to a routed HTML file |
Warning | Warn, drop the inline reference, continue building. |
route / loader in a non-HTML file |
Warning | Warn, ignore the tag, continue building. |
data-* supplied to non-reusable target |
Interactive Warning | Offer reusable conversion or abort the build. |
Cycle detection
a.html → b.html → c.html → a.html ← HARD ERROR
Stitch stops and reports the full cycle. Recursive composition has a maximum supported nesting depth of 32. Exceeding the limit fails clearly rather than risking uncontrolled recursion.
inventory_2 22 / Package Structure
Recommended Package Shape
├── package.json
├── bin/
│ └── stitch.js
└── lib/
├── index.js
├── directives.js
├── utils.js
├── graph.js
├── build.js
├── dev.js
├── manifest.js
├── patch.js
└── reverse.js
Responsibilities
| File | Responsibility |
|---|---|
directives.js |
Finds <stitch> tags and $stitch-drop calls in any text file, honours off, strips consumed directives. |
utils.js |
Path resolution, text/binary detection, fragment handling, local asset URL rewriting, and shared helpers. |
graph.js |
Text-file discovery, dependency graph construction, route and id validation (unique ids), reusable metadata, and cycle detection. |
build.js |
Composition orchestration, public HTML emission, composed text files, asset copying, and route rule generation. |
dev.js |
The stitch dev server: watch, rebuild, live reload. |
manifest.js, patch.js, reverse.js |
Build markers, the reverse manifest, lossless patches, and stitch reverse. |
index.js |
Package exports and public API. |
bin/stitch.js |
CLI entry point for commands such as npx stitch build, stitch dev and stitch reverse. |
The manifest.js here is the build-time reverse manifest. The removed browser-side route / resource runtime (runtime.js) is still gone: nothing Stitch-specific ships to visitors.
timeline 23 / Workflow
Developer Workflow
1. Develop in src/
src/
├── modular HTML
├── nested components
├── reusable templates
├── routed pages
├── CSS / JavaScript / images
└── deployment configuration
2. Develop live, then build
npx stitch dev # serve + rebuild on every change
npx stitch build --no-reverse # clean production output
3. Deploy dist/
npx wrangler pages deploy dist
Recover the source from a build
npx stitch reverse --src restored
4. Browser
https://example.com/
https://example.com/privacy
https://example.com/fx_counter
These are normal browser navigations to ordinary static HTML output.
Developers receive modular source files. Visitors receive already-assembled HTML.
science 24 / Testing
Minimum Regression Tests
Any modification to the build system should test at least:
- simple component composition;
- nested component composition;
- deep recursive component composition;
- the same component consumed from multiple callers;
- the same reusable component consumed with different data values;
- relative component paths;
- source-root component paths;
- leading-slash source-root shorthand;
- missing component errors;
- circular component errors;
- path traversal protection;
- duplicate route errors;
- invalid route errors;
- attempted consumption of routed pages;
- asset copying into
stitch_assets/; - asset URL rewriting from deeply nested HTML files;
- query string and fragment preservation during asset rewriting;
- external URL preservation;
wrangler.tomlpreservation outsidestitch_assets/;_redirectsgeneration when routes exist;- no
<stitch>directives remaining in emitted output; <stitch src>in non-HTML files (JS, CSS, C, Python, TXT), with fragments not emitted;<stitch id>with$stitch-drop, all quoting styles anddata-*values;- duplicate ids failing with every file and line listed;
- unknown ids, malformed drops and drop cycles;
offleaving directives untouched even when the target exists;- text and HTML files including each other without markers leaking;
stitch reverserestoring every file byte-for-byte, including edits made to built files;--asset-dir .for non-web output.
block 25 / Hard Rules
What Stitch Never Does
- leave any
<stitch>directive or$stitch-dropcall in generated output, unless it is markedoff; - reintroduce a browser-side Stitch component loader;
- reintroduce runtime route processing;
- reintroduce a route manifest for browser navigation;
- fetch component HTML in the deployed browser;
- intercept ordinary navigation merely to implement Stitch routing;
- replace the browser's document body as a routing mechanism;
- hide routed page content while waiting for a removed runtime;
- generate lazy / JIT route loading infrastructure;
- move deployment configuration such as
wrangler.tomlinto browser assets; - copy HTML components into
stitch_assets/; - change external URLs during local asset rewriting;
- allow component paths to escape the source root;
- silently ignore circular dependencies;
- silently resolve duplicate routes or duplicate ids;
- remap physical output locations based solely on route values;
- modify source files without explicit behaviour that authorizes it;
- treat
dist/as a second hand-maintained source project; - add architecture unrelated to build-time composition without an explicit requirement.
Stitch should remain small, deterministic, dependency-light, and focused.
MODULAR SOURCE
+
BUILD-TIME COMPOSITION
+
STATIC OUTPUT
+
HOST-NATIVE ROUTING
=
ZAP