Public
Like
MolstarViewer
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.
Viewing readonly version of main branch: v569View latest version
This document describes the migration from a backend/ folder structure to a top-level routes structure, following the Val Town blog pattern.
MolstarViewer/
βββ index.tsx # Simple re-export
β βββ import app from "./backend/index.tsx"
βββ backend/
β βββ index.tsx # Main Hono app with all routes
β βββ routes/ # Empty directory
βββ frontend/
β βββ apps/ # App components
βββ shared/
MolstarViewer/
βββ index.tsx # Main Hono app (entry point)
βββ routes/ # Individual route modules
β βββ home.tsx
β βββ viewer.tsx
β βββ docking-viewer.tsx
β βββ mesoscale-explorer.tsx
β βββ mvs-stories.tsx
βββ frontend/
β βββ apps/ # App components (unchanged)
βββ shared/ # Shared code (unchanged)
βββ utils/ # Utility functions (new)
- Simpler Entry Point:
index.tsxis now the main app, not a re-export - Modular Routes: Each route is its own Hono app in a separate file
- Better Organization: Routes are at top level, making them easy to find
- Follows Val Town Conventions: Matches the pattern used by Val Town's own blog
- Easier to Extend: Adding new routes is as simple as creating a new file
/** @jsxImportSource https://esm.sh/react@18.2.0 */
import app from "./backend/index.tsx";
export default app;
/** @jsxImportSource https://esm.sh/react@18.2.0 */
import { Hono } from "jsr:@hono/hono@4";
import homeRoutes from "./routes/home.tsx";
import viewerRoute from "./routes/viewer.tsx";
import dockingViewerRoute from "./routes/docking-viewer.tsx";
import mesoscaleExplorerRoute from "./routes/mesoscale-explorer.tsx";
import mvsStoriesRoute from "./routes/mvs-stories.tsx";
const app = new Hono();
app.onError((err, c) => {
throw err;
});
app.route("/", homeRoutes);
app.route("/", viewerRoute);
app.route("/", dockingViewerRoute);
app.route("/", mesoscaleExplorerRoute);
app.route("/", mvsStoriesRoute);
export default app.fetch;
const app = new Hono();
app.get("/", (c) => {
return c.html(`<html>...</html>`);
});
app.get("/viewer", async (c) => {
const html = renderToString(<ViewerApp />);
return c.html(html);
});
app.get("/docking-viewer", (c) => {
const html = renderToString(<DockingViewerApp />);
return c.html(html);
});
// ... all routes in one file
/** @jsxImportSource https://esm.sh/react@18.2.0 */
import { Hono } from "jsr:@hono/hono@4";
import { renderToString } from "https://esm.sh/react-dom@18.2.0/server?deps=react@18.2.0,react-dom@18.2.0";
import { readFile } from "https://esm.town/v/std/utils@85-main/index.ts";
import ViewerApp from "../frontend/apps/viewer.tsx";
const app = new Hono();
app.get("/viewer", async (c) => {
const molstarCss = await readFile(
"/frontend/styles/molstar.css",
import.meta.url,
);
const html = renderToString(<ViewerApp molstarCss={molstarCss} />);
return c.html(html);
});
export default app;
Each route file:
- Creates its own Hono app instance
- Defines one or more related routes
- Imports necessary frontend components
- Handles server-side rendering
- Exports the app as default
The main index.tsx:
- Creates the top-level Hono app
- Imports all route modules
- Mounts routes using
app.route() - Sets up global error handling
- Exports
app.fetchfor Val Town
- Create
routes/directory - Move home route to
routes/home.tsx - Create
routes/viewer.tsx - Create
routes/docking-viewer.tsx - Create
routes/mesoscale-explorer.tsx - Create
routes/mvs-stories.tsx - Update
index.tsxto be main app - Import and mount all routes in
index.tsx - Create
utils/directory for future utilities - Update README.md with new structure
- Remove
backend/directory (kept for reference)
Once you're confident the migration is complete:
backend/index.tsx- Logic moved to routesbackend/routes/- Empty directorybackend/README.md- Outdated documentation
- Test home page at
/ - Test viewer at
/viewer - Test docking-viewer at
/docking-viewer - Test mesoscale-explorer at
/mesoscale-explorer - Test mvs-stories at
/mvs-stories - Verify Molstar initialization works
- Check that CSS loads properly
- Verify error handling shows full stack traces
- Test in Val Town: Deploy and verify all routes work
- Add More Features: Now easier to extend with new routes
- Create Utilities: Add shared functions to
utils/as needed - Clean Up: Remove old
backend/folder once confirmed working - Document Patterns: Add examples to
AGENTS.mdif needed
- Val Town Blog Structure - Inspiration
- Hono Routing Documentation
- Val Town Utils -
readFile,serveFile, etc.