Start · application ownership
Project structure
Presolve gives every authored responsibility one canonical home. This is more than organization: it prevents document metadata, route topology, shared composition, global presentation, server values, and generated output from becoming competing sources of truth.
my-app/├── app/│ ├── app.tsx # application shell│ ├── app.css # exact global CSS input│ ├── index.html # compiler document frame│ ├── components/ # reusable application source│ └── routes/ # file-owned URL graph├── assets/ # explicit Vite integration inputs├── public/ # root-addressed static files├── server/ # server-owned source├── tests/ # application verification├── package.json├── pnpm-workspace.yaml # dependency trust policy└── tsconfig.jsonOwnership map
app/index.htmlStable document metadata and surrounding HTML. Presolve owns the three required insertion points.app/app.tsxShared navigation, providers, theme UI, footer, and the default route slot.app/routes/The compiler-discovered route graph. File paths define URLs; no second router table exists.app/components/Reusable components that do not create routes merely by being imported.app/app.cssGlobal selectors for shell, layout, route, and component classes; published at immutable and compatibility coordinates.public/Files copied to root URLs and included in the deployment inventory.assets/Inputs selected by an explicit Vite adapter entry. The directory is not automatically copied.server/Server-owned source. Location prevents browser ownership; it does not invent a server executor.pnpm-workspace.yamlSupply-chain policy. The scaffold explicitly admits only the audited installers required by Vite and Wrangler.dist/ · .presolve/Generated compiler and deployment products. Rebuild them; never edit them as source.1. Frame the document
app/index.html is a compiler template, not a browser entry module. The application owns stable metadata, icons, manifests, preloads, language, and surrounding markup. Presolve fills exactly one head, app, and runtime placeholder for each route.
<!doctype html><html lang="en"><head><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="icon" href="/favicon.svg">{{ head }}</head><body>{{ app }}{{ runtime }}</body></html>Keep the placeholders intact. Do not add a second runtime script, a manual global stylesheet link, or route-generated metadata beside them and assume both sources will stay synchronized.
2. Compose the application shell
app/app.tsx wraps every route and projects the selected page through its default slot. It owns shared application UI, but not <html>, <head>, <body>, or the page’s primary <main>.
import { Component, slot, type SlotContent } from "presolve";export class App extends Component {children: SlotContent = slot();render() {return (<div class="app-shell"> <header>Shared navigation</header> <slot /> <footer>Shared footer</footer></div>);}}3. Let files own routes
app/routes/index.tsx maps to /. app/routes/docs/getting-started.tsx maps to /docs/getting-started/. Each route exports a compiler component and owns one primary page landmark.
import { Component } from "presolve";export class Home extends Component {render() {return <main><h1>Hello, Presolve</h1></main>;}}4. Understand the build flow
pnpm 11 blocks undeclared dependency build scripts. The generated pnpm-workspace.yaml admits esbuild for Vite and workerd for Wrangler; do not replace that narrow list with a blanket lifecycle-script bypass. Review any additional installer before adding it.
allowBuilds:esbuild: trueworkerd: trueCanonical shell, route, document, CSS, public, and server inputs are selected.
TypeScript resolves symbols and signatures; Presolve derives semantic products.
Project Vite bundles only compiler-authorized external browser entries.
Complete route HTML, immutable CSS/runtime files, public assets, and one deployment inventory are emitted.
5. Develop against compiler output
pnpm dev runs the same development-profile publication, then watches authored inputs. Presolve never asks a browser bundler to rediscover routes or patch generated HTML. Each successful edit replaces the active compiler publication and its file-route manifest atomically.
| Edit | Browser result | State rule |
|---|---|---|
app/app.css or another CSS input | New CSS loads through a revisioned stable URL; the old link is removed after load. | Document, State, focus, and scroll remain intact. |
| TSX, document, route, public file, package, or configuration | The compiler rebuilds and the browser reloads the new publication. | Fail closed unless narrower HMR compatibility has been proven. |
| An edit that does not compile | The last good page stays visible with an accessible compiler diagnostic. | Recovery reloads only after the compiler succeeds. |
The generated dist/ pointer and its one active hidden publication directory are compiler output. They are excluded from file observation, so a rebuild cannot trigger itself.
Compatibility paths
app/layout.tsx and styles/ remain readable for older beta projects. They are compatibility inputs, not the recommended structure. A project cannot declare both app/app.tsx and app/layout.tsx. Move shared UI to app/app.tsx, global presentation to app/app.css, and directly addressed files to public/.