# Agents ## Repository Overview Fresh is a web framework for Deno built on Preact. This is a **Deno monorepo** with workspace members in `packages/*` and `www/`. ### Packages - **`packages/fresh/`** (`@fresh/core`): Core framework — routing, rendering, islands, build cache, middlewares, and client/server runtime. - **`packages/plugin-vite/`** (`@fresh/plugin-vite`): Vite integration plugin with dev server, SSR/client builds, and HMR. - **`packages/init/`** (`@fresh/init`): Project scaffolding (`deno run -Ar jsr:@fresh/init`). - **`packages/update/`** (`@fresh/update`): Automated Fresh 1.x to 2.x migration tool using ts-morph for AST transforms. - **`packages/build-id/`** (`@fresh/build-id`): Build/deployment ID generation. - **`packages/plugin-tailwindcss/`** (`@fresh/plugin-tailwind`): TailwindCSS v4 plugin. - **`packages/plugin-tailwindcss-v3/`** (`@fresh/plugin-tailwind-v3`): Legacy TailwindCSS v3 plugin. - **`packages/examples/`** (`@fresh/examples`): Example components for tests. ### Other directories - **`www/`**: Documentation website (usefresh.dev), built with Fresh + Vite + Tailwind. Has its own routes, islands, and vite.config.ts. - **`docs/`**: Markdown documentation organized by version (`latest/`, `1.x/`, `canary/`). - **`tools/`**: `release.ts` (version bumping), `check_docs.ts` (doc validation), `check_links.ts` (link checker). - **`vendor/`**: Vendored dependencies (`"vendor": true` in deno.json). ## Git Workflow - To check out a PR branch, use `gh pr checkout `. Do not set up remotes manually. - Always run `deno fmt` before pushing. - Do not commit `deno.lock` changes unless the PR is specifically about updating dependencies. Lockfile diffs tend to be noisy and environment-specific. - **Never amend commits or force push.** Always create new commits. ## Development - Run `deno task ok` before pushing — it runs the full local CI check (fmt, lint, type check, tests). - Run `deno install` if you get missing dependency errors. - Tests: `deno task test` (all tests, parallel). Tests use `@std/expect` for assertions and `linkedom` for DOM testing. - JSX is configured in "precompile" mode with Preact as the import source. ### Lockfile quirks The lockfile contains remote specifiers pointing to `refs/heads/main` (e.g. `raw.githubusercontent.com/.../refs/heads/main/...`). These hashes go stale when upstream pushes. When that happens, manually update the hash in `deno.lock` since `deno cache --reload` cannot fix it (see https://github.com/denoland/deno/issues/32991). ## Architecture ### Request lifecycle 1. `App.handler()` receives an HTTP request (`app.ts`) 2. URL is parsed and normalized (double slashes removed) 3. `UrlPatternRouter.match()` finds the matching route — static routes are checked first via direct `Map` lookup, then dynamic routes via `URLPattern` 4. A `Context` is created with request, params, and build cache 5. The middleware chain executes (built backwards as nested closures) 6. `ctx.render()` composes layouts and app wrapper around the page component 7. Preact's `renderToString()` generates HTML, with option hooks detecting islands along the way 8. `FreshScripts` component emits the inline boot script with island imports and serialized props 9. Response is returned with HTML and `Link` modulepreload headers ### Island architecture Islands are interactive Preact components that hydrate on the client while the rest of the page stays static HTML. **Server side** (`runtime/server/preact_hooks.ts`): - Preact's diff hook intercepts every VNode during SSR - When a component exists in `buildCache.islandRegistry`, it's wrapped in HTML comment markers: `...` - Island props are collected into a `RenderState.islandProps[]` array - JSX element props become **slots** — stored in `