Search
Code1,917
# React Hono Val Town Project Starter TemplateThe entrypoint of this app is `backend/index.ts`, which is the Hono HTTP server, which serves the HTML, CSS, and JS, which run client-side.If you'd like to make a template with other technologies choices (ie no Hono or no React), please create a new template and we can link to it from this one as another way to go. Eventually, we'd like to be many templates that show how to use Projects. The next one I'm personally excited about making is a fullstack React Router 7 one. [This one](https://www.val.town/x/just_be/reactRouter7) is a good start, but I'd like to rebuild the message board app from this template in that format.This template is a classic client-side-only React app. This HTML file has a `<div id="root"></div>`, which is where we mount the React app.This HTML file imports `/frontend/index.tsx` from `/public/index.tsx`, which is the **entrypoint** for all frontend JavaScript, including all the React. It is not a problem that it imports a file with a `.tsx` extension becaues browsers ignore file extensions. They only pay attention to content-types, which is great, because all these files will be returned as transpiled JS with the appropriate JS content type by [stevekrouse/utils/serve-public](https://www.val.town/x/stevekrouse/utils/branch/main/code/serve-public/README.md).)This file is the **entrypoint** for frontend JavaScript. It imports the React app from `/frontend/components/App.tsx` and mounts it on `<div id="root"></div>`.This directory is where the React components are stored. They're pretty standard client-side React components.This backend HTTP server is responsible for serving all static assets to the browser to render the app, including HTML, JavaScript (including all client-side React), CSS, and even the favicon SVG.In a normal server environment, you would likely use a middleware [like this one](https://hono.dev/docs/getting-started/nodejs#serve-static-files) to serve static files. Some frameworks or deployment platforms automatically make any content inside a `public/` folder public. We *bootstrap* `index.html` with some initial data from the server, so that it gets dynamically injected JSON data without having to make another round-trip request to the server to get that data on the frontend. This is a common pattern for client-side rendered apps.This app has two CRUD API routes: for reading and inserting into the messages table. They both speak JSON, which is standard. They import their functions from `/backend/database/queries.ts`. This routes are called from the React app to refresh and update data.Versions 0-17 of this val were done with Hono and server-rendering.Versions 18+ were generated with Townie and use client-side React.
## OverviewA dynamic web application that combines job postings and real-time community chat, built using React and Val Town's serverless platform.## π Technologies- React (Frontend)- Val Town (Hosting & Backend)- Blob Storage (Data Persistence)- Client-side & Server-side RenderingVersions 0-17 of this val were done with Hono and server-rendering.Versions 18+ were generated with Townie and use client-side React.
/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0";function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "Pretty please?", "Are you sure? Side effects may include regret and reconsideration.", "This is worse than running out of ibuprofen mid-shift.",function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "Pretty please?", "Are you sure? Side effects may include regret and reconsideration.", "This is worse than running out of ibuprofen mid-shift.",function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "What about a maybe..?", "Please don't do this to me, pleaseee reconsider",];function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "Even deep learning couldn't predict this heartbreak... π", "Please reconsider, my loss function is at its minimum with you! π", "Don't leave me stuck in a local minimum! π’",function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "Im going to have to just kidnap you then", "I wasnt joking , look outside ",];function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0"; "What do you mean no >:(", "Last chance to reconsider >:(((", "That's it I'm stealing your pc",function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0";from the moment i met you something inside me changed it was like my heart had been waiting for you without even knowing it like every piece of me that ever felt lost suddenly made sense when i saw you every moment with you feels like a dream but itβs real and thatβs the most beautiful part you are real you are mine and i am yours and that is the greatest gift life has ever given mefunction client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }/** @jsxImportSource https://esm.sh/react@18.2.0 */import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";import React, { useState } from "https://esm.sh/react@18.2.0";const NO_PHRASES = [ "Canβt you reconsider? ππ₯Ί", "Beers on me?? π₯Ί",function client() { createRoot(document.getElementById("root")).render(<App />);}if (typeof document !== "undefined") { client(); }