• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
nichoth

nichoth

honovt

val.town + Hono
Public
Like
honovt
Home
Code
20
.claude
1
.git
10
.github
2
_public
1
public
1
src
3
.eslintignore
.eslintrc
.gitignore
.npmignore
.vtignore
AGENTS.md
README.md
build-css.js
deno.json
index.html
H
index.http.tsx
package-lock.json
package.json
tsconfig.json
Environment variables
Branches
1
Pull requests
Remixes
History
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
Code
/
Search
README.md

val.town + Hono

Use Hono framework with a val.town val.

Contents

  • Develop
    • Local Dev
  • Components
    • page.tsx
  • The Datastar SSR pattern

Test

Run tests

npm test

Open a browser with visual test results

npm run test:ui

Develop

Start a Vite server at localhost:8888.

npm start

Local Dev

Locally we are using Vite as server. In the vite config we use a plugin, @cloudflare/vite-plugin. It integrates the cloudflare worker (the Hono app) with the vite server. The @cloudflare/vite-plugin embeds a Cloudflare Worker runtime inside Vite's
dev server.

Vite gives us HMR and bundling. The Vite plugin runs the worker code, which is why the worker works locally.

Vite builds to public/, but we do not use that folder during development.

Components

In the worker file (./src/server/index.tsx), it checks if we are in local dev or production. In dev, ASSETS doesn't exist; it returns notFound() and Vite handles it. In production, ASSETS does exist, so it serves the static asset.

When you run npm start, the Cloudflare Vite plugin routes requests to your Hono server at src/server/index.tsx:126, which renders the Page component. This Page component uses the .tsx components (TimestampCard, GreetingCard, CounterCard, QuoteCard) which are server-side rendered.

page.tsx

The page.tsx is a layout skeleton that accepts props.

Create val
export const Page:FC<PropsWithChildren<PageProps>> = ({ title, signals = {}, children })

Any site pages should extend this template, and pass in content and signals. An example is ./src/components/home-page.tsx.


The Datastar SSR pattern

  • Server renders the full HTML with components
  • data-signals initializes the reactive state
  • Datastar library (loaded via CDN) handles client-side reactivity
  • API endpoints return SSE responses that update signals

Notes

I do not understand why we need to run vite build twice, but we do.

The empty object in public/client/vite-manifest.json is necessary because the server depends on it when we run the build process.

Create val
// package.json { "scripts": { "build": "rm -rf ./public && mkdir -p ./public/client && echo '{}' > ./public/client/vite-manifest.json && vite build && vite build", } }
Code
.claude.git.github_publicpublicsrc.eslintignore.eslintrc.gitignore.npmignore.vtignoreAGENTS.mdREADME.mdbuild-css.jsdeno.jsonindex.html
H
index.http.tsx
package-lock.jsonpackage.jsontsconfig.json
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.