Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update cloudflare-d1 template to not use "@hiogawa/vite-node-miniflare" #63

Merged
merged 3 commits into from
Jan 22, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions cloudflare-d1/README.md
Original file line number Diff line number Diff line change
@@ -50,10 +50,24 @@ npm run build

Deployment is done using the Wrangler CLI.

To deploy directly to production:
First, you need to create a d1 database in Cloudflare.

```sh
npx wrangler deploy
npx wrangler d1 create <name-of-your-database>
```

Be sure to update the `wrangler.toml` file with the correct database name and id.

You will also need to [update the `drizzle.config.ts` file](https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit), and then run the production migration:

```sh
npm run db:migrate-production
```

To build and deploy directly to production:

```sh
npm run deploy
```

To deploy a preview URL:
12 changes: 4 additions & 8 deletions cloudflare-d1/app/routes/home.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { database } from "~/database/context";
import * as schema from "~/database/schema";

import type { Route } from "./+types/home";
@@ -11,7 +10,7 @@ export function meta({}: Route.MetaArgs) {
];
}

export async function action({ request }: Route.ActionArgs) {
export async function action({ request, context }: Route.ActionArgs) {
const formData = await request.formData();
let name = formData.get("name");
let email = formData.get("email");
@@ -25,18 +24,15 @@ export async function action({ request }: Route.ActionArgs) {
return { guestBookError: "Name and email are required" };
}

const db = database();
try {
await db.insert(schema.guestBook).values({ name, email });
await context.db.insert(schema.guestBook).values({ name, email });
} catch (error) {
return { guestBookError: "Error adding to guest book" };
}
}

export async function loader({ context }: Route.LoaderArgs) {
const db = database();

const guestBook = await db.query.guestBook.findMany({
const guestBook = await context.db.query.guestBook.findMany({
columns: {
id: true,
name: true,
@@ -45,7 +41,7 @@ export async function loader({ context }: Route.LoaderArgs) {

return {
guestBook,
message: context.VALUE_FROM_CLOUDFLARE,
message: context.cloudflare.env.VALUE_FROM_CLOUDFLARE,
};
}

17 changes: 0 additions & 17 deletions cloudflare-d1/database/context.ts

This file was deleted.

32 changes: 32 additions & 0 deletions cloudflare-d1/load-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { drizzle, type DrizzleD1Database } from "drizzle-orm/d1";
import * as schema from "./database/schema";
import type { ExecutionContext } from "@cloudflare/workers-types";
import type { AppLoadContext } from "react-router";

declare global {
interface CloudflareEnvironment extends Env {}
}

declare module "react-router" {
export interface AppLoadContext {
cloudflare: {
env: CloudflareEnvironment;
ctx: Omit<ExecutionContext, "props">;
};
db: DrizzleD1Database<typeof schema>;
}
}

type GetLoadContextArgs = {
request: Request;
context: Pick<AppLoadContext, "cloudflare">;
};

export function getLoadContext({ context }: GetLoadContextArgs) {
const db = drizzle(context.cloudflare.env.DB, { schema });

return {
cloudflare: context.cloudflare,
db,
};
}
2 changes: 1 addition & 1 deletion cloudflare-d1/package.json
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
"db:migrate-production": "dotenv -- drizzle-kit migrate",
"dev": "react-router dev",
"start": "wrangler dev",
"deploy": "npm run build && wrangler deploy",
"typecheck": "react-router typegen && tsc -b"
},
"dependencies": {
@@ -21,7 +22,6 @@
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20241112.0",
"@hiogawa/vite-node-miniflare": "0.1.1",
"@react-router/dev": "*",
"@types/node": "^20",
"@types/react": "^19.0.1",
4 changes: 3 additions & 1 deletion cloudflare-d1/tsconfig.cloudflare.json
Original file line number Diff line number Diff line change
@@ -6,7 +6,9 @@
"app/**/.server/**/*",
"app/**/.client/**/*",
"database/**/*",
"workers/**/*"
"workers/**/*",
"load-context.ts",
"worker-configuration.d.ts"
],
"compilerOptions": {
"composite": true,
8 changes: 7 additions & 1 deletion cloudflare-d1/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"extends": "./tsconfig.json",
"include": ["tailwind.config.ts", "vite.config.ts"],
"include": [
"tailwind.config.ts",
"vite.config.ts",
"database/**/*",
"load-context.ts",
"worker-configuration.d.ts"
],
"compilerOptions": {
"composite": true,
"strict": true,
15 changes: 4 additions & 11 deletions cloudflare-d1/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { vitePluginViteNodeMiniflare } from "@hiogawa/vite-node-miniflare";
import { reactRouter } from "@react-router/dev/vite";
import { cloudflareDevProxy } from "@react-router/dev/vite/cloudflare";
import autoprefixer from "autoprefixer";
import tailwindcss from "tailwindcss";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { getLoadContext } from "./load-context";

export default defineConfig(({ isSsrBuild }) => ({
build: {
@@ -21,7 +22,6 @@ export default defineConfig(({ isSsrBuild }) => ({
ssr: {
target: "webworker",
noExternal: true,
external: ["node:async_hooks"],
resolve: {
conditions: ["workerd", "browser"],
},
@@ -37,15 +37,8 @@ export default defineConfig(({ isSsrBuild }) => ({
},
},
plugins: [
vitePluginViteNodeMiniflare({
entry: "./workers/app.ts",
miniflareOptions: (options) => {
options.compatibilityDate = "2024-11-18";
options.compatibilityFlags = ["nodejs_compat"];
options.d1Databases = { DB: "your-database-id" };
// match where wrangler applies migrations to
options.d1Persist = ".wrangler/state/v3/d1";
},
cloudflareDevProxy({
getLoadContext,
}),
reactRouter(),
tsconfigPaths(),
6 changes: 6 additions & 0 deletions cloudflare-d1/worker-configuration.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Generated by Wrangler by running `wrangler types`

interface Env {
VALUE_FROM_CLOUDFLARE: "Hello from Cloudflare";
DB: D1Database;
}
28 changes: 7 additions & 21 deletions cloudflare-d1/workers/app.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
import { drizzle } from "drizzle-orm/d1";
import { getLoadContext } from "load-context";
import { createRequestHandler } from "react-router";

import { DatabaseContext } from "~/database/context";
import * as schema from "~/database/schema";

interface CloudflareEnvironment {
DB: D1Database;
}

declare module "react-router" {
export interface AppLoadContext {
VALUE_FROM_CLOUDFLARE: string;
}
}

const requestHandler = createRequestHandler(
// @ts-expect-error - virtual module provided by React Router at build time
() => import("virtual:react-router/server-build"),
import.meta.env.MODE
);

export default {
fetch(request, env) {
const db = drizzle(env.DB, { schema });
return DatabaseContext.run(db, () =>
requestHandler(request, {
VALUE_FROM_CLOUDFLARE: "Hello from Cloudflare",
})
);
fetch(request, env, ctx) {
const loadContext = getLoadContext({
request,
context: { cloudflare: { env, ctx } },
});
return requestHandler(request, loadContext);
},
} satisfies ExportedHandler<CloudflareEnvironment>;
3 changes: 3 additions & 0 deletions cloudflare-d1/wrangler.toml
Original file line number Diff line number Diff line change
@@ -5,6 +5,9 @@ compatibility_flags = ["nodejs_compat"]
main = "./build/server/index.js"
assets = { directory = "./build/client/" }

[vars]
VALUE_FROM_CLOUDFLARE = "Hello from Cloudflare"

[[d1_databases]]
binding = "DB"
database_name = "your-database-name"
4 changes: 2 additions & 2 deletions cloudflare/README.md
Original file line number Diff line number Diff line change
@@ -44,10 +44,10 @@ npm run build

Deployment is done using the Wrangler CLI.

To deploy directly to production:
To build and deploy directly to production:

```sh
npx wrangler deploy
npm run deploy
```

To deploy a preview URL:
1 change: 1 addition & 0 deletions cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
"build": "react-router build",
"dev": "react-router dev",
"start": "wrangler dev",
"deploy": "npm run build && wrangler deploy",
"typecheck": "react-router typegen && tsc -b"
},
"dependencies": {
1 change: 0 additions & 1 deletion cloudflare/workers/app.ts
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@ const requestHandler = createRequestHandler(

export default {
fetch(request, env, ctx) {
console.log("yo");
return requestHandler(request, {
cloudflare: { env, ctx },
});
Loading