Integrasi Drizzle ORM dengan Cloudflare D1 dan Remix Vite: Panduan Lengkap

Halo sobat developer! Kali ini, saya ingin berbagi pengalaman seru tentang integrasi Drizzle ORM dengan Cloudflare D1 dan Remix-Vite. Yuk, kita eksplorasi bersama!

Apa Itu Drizzle ORM?

Drizzle ORM adalah alat keren untuk TypeScript yang memudahkan kita bekerja dengan database relasional. Keunggulannya:

  • Pembacaan dan penulisan data yang aman
  • Penanganan migrasi otomatis
  • Dukungan penuh untuk TypeScript

Kenapa Kita Perlu Tahu Ini?

  1. Type Safety: Mengurangi bug dan bikin kode lebih mudah di-maintain.
  2. Performa: Integrasi dengan Cloudflare D1 memberi kita database yang cepat dan scalable.
  3. Developer Experience: Remix + Vite = Pengembangan yang lebih cepat dan menyenangkan!

Langkah-Langkah Implementasi

1. Setup Proyek remix-d1

npx create-remix@latest --template remix-run/remix/templates/cloudflare

2. Instalasi Drizzle

bun install drizzle-orm
bun install -d drizzle-kit

3. Tulis Skema Database

Buat file app/db/schema.server.ts:

import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const resources = sqliteTable("resources", {
  id: integer("id").primaryKey(),
  title: text("title").notNull(),
  href: text("href").notNull(),
});

4. Setup Migrasi

Tambahkan script ini di package.json:

{
  "scripts": {
    "drizzle:update": "drizzle-kit generate --out ./app/db/migrations --schema ./app/db/schema.server.ts --dialect sqlite"
  }
}

Lalu jalankan:

bun run drizzle:update

5. Setup Database D1

npx wrangler d1 create remix-d1

Update wrangler.toml:

[[d1_databases]]
binding = "DB"
database_name = "db"
database_id = "uuid"
migrations_dir="./app/db/migrations"

6. Migrate Database Lokal

npx wrangler d1 migrations apply remix-d1

7. Beritahu Typescript tentang Database

bun run typegen

Bun akan membuat berkas baru worker-configuration.d.ts. Kita mungkin perlu me-restart server TypeScript untuk notify perubahan environment. Di VS Code, buka command palette dengan CMD+Shift+P dan pilih opsi Typescript: Restart TS Server.

8. Implementasi Baca Tulis

Buat berkas baru di app/routes/resources.tsx, tulis seperti ini:

import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
import { Form, json, useLoaderData } from "@remix-run/react";
import { drizzle } from "drizzle-orm/d1";
import { resources } from "~/db/schema.server";

export async function action({ request, context }: ActionFunctionArgs) {
  const env = context.cloudflare.env as Env
  const formData = await request.formData();
  const title = formData.get("title") as string;
  const href = formData.get("href") as string;
  const db = drizzle(env.DB);

  await db.insert(resources).values({ title, href }).execute();

  return json({ message: "Resource added" }, { status: 201 });
}

export async function loader({ context }: LoaderFunctionArgs) {
  const env = context.cloudflare.env as Env
  const db = drizzle(env.DB);
  const resourceList = await db
    .select({
      id: resources.id,
      title: resources.title,
      href: resources.href,
    })
    .from(resources)
    .orderBy(resources.id);

  return json({
    resourceList,
  });
}

export default function ResourcesPage() {
  const { resourceList } = useLoaderData<typeof loader>();
  return (
    <div>
      <h1>Welcome to Remix (with Drizzle, Vite and Cloudflare D1)</h1>
      <ol>
        {resourceList.map((resource) => (
          <li key={resource.id}>
            <a target="_blank" href={resource.href} rel="noreferrer">
              {resource.title}
            </a>
          </li>
        ))}
      </ol>
      <Form method="POST">
        <div>
          <label>
            Title: <input type="text" name="title" required />
          </label>
        </div>
        <div>
          <label>
            URL: <input type="url" name="href" required />
          </label>
        </div>
        <button type="submit">Add Resource</button>
      </Form>
    </div>
  );
}

9. Deploy ke Cloudflare

Build terlebih dahulu dengan:

bun run build

Baru bisa kita deploy ke Cloudflare dengan perintah:

bun run deploy

10. Binding Aplikasi Production ke Database

Buka halaman detail dari Cloudflare Pages yang barusan kita deploy:

  1. pilih menu Settings > Functions
  2. Scroll ke bawah hingga section D1 database bindings
  3. Klik tombol Add Binding
  4. Tulis Variable name dengan DB
  5. D1 Database pilih yang sesuai

Setelah binding ini, proyek Cloudflare Pages kita telah terkoneksi dengan D1 Database. Akan tetapi, ternyata migrations yang sebelumnya kita jalankan belum terimplementasi, jadi kita perlu membuat table manual melalui UI di Cloudflare.

  1. Pada menu Workers & Pages, pilih sub-menu D1
  2. Pilih database remix-d1, kita akan dialihkan ke halaman detail database
  3. Klik tombol Create Table
  4. Buat sesuai spesifikasi schema yang telah kita buat
Schema table resources di D1 Database untuk aplikasi Remix D1

Tips Tambahan

  1. Error Handling: Selalu bungkus operasi database dalam try-catch untuk menangani error dengan baik.
  2. Optimasi Query: Gunakan indeks dan limit jumlah data yang diambil untuk performa lebih baik.
  3. Testing: Jangan lupa tulis unit test untuk memastikan fungsi database berjalan dengan benar.

Kesimpulan

Integrasi Drizzle ORM dengan Cloudflare D1 dan Remix-Vite membuka banyak kemungkinan baru dalam pengembangan web. Dengan type safety, performa tinggi, dan developer experience yang menyenangkan, kita bisa membuat aplikasi web yang lebih baik dan lebih cepat.

Bagaimana menurut kalian? Sudah pernah coba stack ini? Share pengalaman kalian di komentar ya!

Jangan lupa follow saya di GitHub dan YouTube untuk update terbaru seputar web development. Sampai jumpa di artikel selanjutnya! 👋

Referensi: