Build-Time HTML Composition
current specification npm · @vkdatta/stitch build-time only static HTML output host-native routing

Build one by one.
Stitch to bundle.

Stitch replaces runtime <stitch> imports with real HTML during deployment. Components are resolved at build time — the browser receives ordinary, finished HTML with no component-loader JavaScript.

download 01 / Install

Install Stitch

npm i @vkdatta/stitch -g

Stitch is a build tool for your website. Install it globally, then run it inside the project you build and deploy.

folder_open 02 / Structure

Keep your source organized

project/
├── src/
│   ├── index.html
│   ├── repo.html
│   ├── components/
│   │   ├── header.html
│   │   └── footer.html
│   ├── style.css
│   └── script.js
└── package.json

Stitch reads src/ and writes the deployable site to dist/. Static assets are copied into dist/stitch_assets/. HTML files are processed for Stitch imports.

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 HTML file containing the tag. This lets nested HTML files reference components relative to their own location. The referenced HTML may itself contain additional <stitch src> calls — composition is recursive.

Extension handling

When the referenced path has no extension, Stitch appends .html automatically.

<stitch src="/tags/opening"></stitch>
resolves as: src/tags/opening.html

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. The <stitch reusable> declaration itself never appears in generated HTML.

warning Interactive Warning

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.

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.

recycling 06 / Component Lifecycle

Only consumed components disappear

A file becomes a consumed component when another HTML file references it through <stitch src="...">. Its contents are embedded into the consumer, so that source component is omitted from dist/.

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 07 / Why Stitch

Runtime imports are convenient. Build-time imports are faster.

target Core Intent

Stitch is a build-time HTML composition processor. It allows a developer to split a large HTML project into modular files, recursively compose those files during the build, and deploy ordinary static HTML.

The problem with runtime composition

A runtime component processor improves source modularity but shifts composition work onto every visitor:

What Stitch gives you

Build time may increase slightly because Stitch performs assembly before deployment. That cost happens once per build instead of being paid by every visitor.

merge Fundamental Pipeline
SOURCE → ZAP BUILD → DIST → STATIC HOST / CDN → BROWSER

There is no Stitch component loader running in the deployed website.

compare 08 / 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 09 / 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
├── nested directories
├── reusable components
├── routed pages
├── CSS / JS / images / fonts / other assets
│
▼
ZAP BUILD
│
├── scan HTML files
├── build dependency graph
├── validate routes
├── detect cycles
├── recursively compose HTML
├── perform data-* substitution
├── strip Stitch directives
├── emit public HTML pages
├── centralize static assets  →  dist/stitch_assets/
├── rewrite local asset URLs
└── generate host routing rules  →  dist/_redirects
│
▼
dist/
│
├── index.html
├── routed HTML files
├── stitch_assets/
├── _redirects  (when routes exist)
└── host configuration files at root
│
▼
STATIC HOST / CDN  →  REAL BROWSER NAVIGATION
info Important

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

code 10 / Tag Reference

Stitch Tag Reference

<stitch src> — HTML Composition

Instructs Stitch to resolve another local HTML file and insert its processed contents at the exact position of the tag.

<stitch src="./header"></stitch>
<stitch src="./header.html" />
<stitch src="components/header"></stitch>

<stitch reusable> — Reusable Template Declaration

Marks a component as reusable with build-time {{slot}} substitution. The declaration never appears in generated HTML.

<stitch reusable></stitch>

<article>
  <h2>{{title}}</h2>
  <p>{{description}}</p>
</article>

<stitch route> — Public URL Declaration

Declares the public URL for a page. The route does not determine the source file's physical location — a file may exist anywhere inside src/.

<stitch route="/privacy"></stitch>

This declares the public URL https://example.com/privacy.

File name–based routing

Normal HTML files derive routes from their filenames without needing an explicit <stitch route>:

src/index.html       → /
src/terms.html       → /terms
src/docs/index.html  → /docs
gavel Absolute Rule

No <stitch ...> tag may remain in emitted HTML. All Stitch directives are processed and stripped before output.

Quick command reference

# Install
npm i @vkdatta/stitch -g

# Embed a component (relative or absolute path)
<stitch src="relative or absolute path to file"></stitch>

# File name–based routing
<stitch route="allow"></stitch>

# Explicit route (e.g. inside legal.html)
<stitch route="others/legal"></stitch>

# Build
npx stitch build

route 11 / 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.

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.
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.
shield Path Traversal Protection

A resolved component path must remain inside the source directory. Any reference that escapes the source root is a hard build error.

repeat 12 / Reusable Components

Reusable Components & Data Substitution

Rules

edit_note Source Modification Exception

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 13 / 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
compare_arrows Route and Filesystem Are Separate

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

link_off Warning — Reference Dropped

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 14 / 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

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
settings wrangler.toml

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 15 / Output Rules

What Goes Into dist/

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 16 / 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 exists but is not HTML Hard Error Stop — <stitch src> consumes HTML components only.
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.
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 17 / Package Structure

Recommended Package Shape

stitch/
├── package.json
├── bin/
│   └── stitch.js
└── lib/
     ├── index.js
     ├── utils.js
     ├── graph.js
     └── build.js

Responsibilities

File Responsibility
utils.js Stitch tag parsing, path resolution, tag stripping, local asset URL rewriting, and shared helpers.
graph.js HTML discovery, dependency graph construction, route validation, reusable metadata, and cycle detection.
build.js Composition orchestration, public HTML emission, asset copying, and route rule generation.
index.js Package exports and public API.
bin/stitch.js CLI entry point for commands such as npx stitch build.
delete_sweep Deliberately Removed Architecture

There is no need for manifest.js or runtime.js in the current architecture. They represented the removed browser-side route / resource runtime.

timeline 18 / Workflow

Developer Workflow

1. Develop in src/

src/
├── modular HTML
├── nested components
├── reusable templates
├── routed pages
├── CSS / JavaScript / images
└── deployment configuration

2. Build

npx stitch build

3. Deploy dist/

npx wrangler pages deploy dist

4. Browser

https://example.com/
https://example.com/privacy
https://example.com/fx_counter

These are normal browser navigations to ordinary static HTML output.

flag Primary Objective

Developers receive modular source files. Visitors receive already-assembled HTML.

science 19 / Testing

Minimum Regression Tests

Any modification to the build system should test at least:

  1. simple component composition;
  2. nested component composition;
  3. deep recursive component composition;
  4. the same component consumed from multiple callers;
  5. the same reusable component consumed with different data values;
  6. relative component paths;
  7. source-root component paths;
  8. leading-slash source-root shorthand;
  9. missing component errors;
  10. circular component errors;
  11. path traversal protection;
  12. duplicate route errors;
  13. invalid route errors;
  14. attempted consumption of routed pages;
  15. asset copying into stitch_assets/;
  16. asset URL rewriting from deeply nested HTML files;
  17. query string and fragment preservation during asset rewriting;
  18. external URL preservation;
  19. wrangler.toml preservation outside stitch_assets/;
  20. _redirects generation when routes exist;
  21. no <stitch> directives remaining in emitted HTML.

block 20 / Hard Rules

What Stitch Never Does

block Absolute Prohibitions
  • leave any <stitch> directive in generated HTML;
  • 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.toml into 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;
  • 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 HTML composition without an explicit requirement.
diamond Final Design Principle

Stitch should remain small, deterministic, dependency-light, and focused.

MODULAR SOURCE
+
BUILD-TIME COMPOSITION
+
STATIC OUTPUT
+
HOST-NATIVE ROUTING
=
ZAP