This is an example Todo App. Backend is written in Honoπ₯ and Frontend is written in Remix.
Both are deployed on Cloudflare Workers / Pages, and connected via Service Bindings and Hono RPC.
Architectural diagram can be seen here.
This architecture allows for independent and loosely coupled front-end and back-end implementations. On the other hand, the actual API calls are type-assisted by Hono RPC and communicated within Cloudflare via Service Bindings, making them secure and fast.
The resulting backend API call via Service Bindings looks like this. You can try this page at here.
import type { LoaderFunctionArgs } from "@remix-run/cloudflare";
import { useLoaderData } from "@remix-run/react";
export async function loader({ context }: LoaderFunctionArgs) {
const api = getApi({ context }); // this is factory for hono/client
return await api.hello
.$get()
.then((res) => res.json())
.catch((err) => {
console.error(err);
return { error: "Failed to fetch data", message: null };
});
}
export default function Route() {
const data = useLoaderData<typeof loader>();
return (
<div>
<h1>Response from backend</h1>
<pre>
<code>{JSON.stringify(data, null, 2)}</code>
</pre>
</div>
);
}
Demo app is available at here.
TODO: add gif
pnpm install
cd apps/frontend
cp example.dev.vars .dev.vars
# put cookie secret for deploy
pnpm exec wrangler secret put COOKIE_SECRET
cd apps/backend
pnpm exec wrangler d1 create <DATABASE_NAME>
apps/backend/wrangler.toml
.[[d1_databases]]
binding = "DB" # i.e. available in your Worker on env.DB
database_name = "<DATABASE_NAME>"
database_id = "<DATABASE_ID>"
dbCredentials
in apps/backend/drizzle.config.ts
.import { defineConfig } from "drizzle-kit";
export default defineConfig({
dbCredentials: {
dbName: "<DATABASE_NAME>", // edit here!!!
wranglerConfigPath: "./wrangler.toml",
},
driver: "d1",
out: "./migrations",
schema: "../../packages/module/src/schema.ts",
strict: true,
verbose: true,
});
pnpm exec wrangler secret put PASSWORD_SALT
Follow setup section.
Run pnpm run dev
at project root.
.
βββ apps
β βββ backend
β β βββ drizzle.config.ts -> Drizzle ORM configuration
β β βββ package.json
β β βββ src
β β β βββ index.ts -> exports backend entrypoint from packages/api/src/server.ts
β β βββ wrangler.toml -> backend worker configuration
β βββ frontend
β βββ app -> Remix app
β βββ lib
β β βββ api.ts -> exports api client from packages/api/src/client.ts
β βββ load-context.ts
β βββ package.json
β βββ worker-configuration.d.ts -> types generated from wrangler.toml
β βββ wrangler.toml -> frontend pages configuration
βββ packages
β βββ api
β β βββ package.json
β β βββ src -> backend api built with Hono
β βββ module
β βββ src -> core module interact with DB
βββ .gitignore
βββ .prettierignore
βββ eslint.config.mjs
βββ package.json
βββ README.md
βββ pnpm-lock.yaml
βββ pnpm-workspace.yaml
βββ prettier.config.mjs
βββ README.md
βββ tsconfig.json
βββ turbo.json