العودة للمقالات

بناء تطبيق SvelteKit كامل باستخدام إجراءات الخادم و Drizzle ORM

المؤلفMajd Muhtaseb30‏/04‏/202515 دقيقة
بناء تطبيق SvelteKit كامل باستخدام إجراءات الخادم و Drizzle ORM

مقدمة

يوضح هذا الدليل كيفية بناء تطبيق كامل باستخدام SvelteKit و Server Actions و Drizzle ORM. سنغطي إعداد بيئتك وتعريف المخطط الخاص بك وتنفيذ عمليات CRUD الأساسية.

المتطلبات الأساسية

  • Node.js (الإصدار 18 أو أعلى)
  • npm أو yarn
  • معرفة أساسية بـ SvelteKit و JavaScript

الإعداد

  1. إنشاء مشروع SvelteKit جديد:

    npm create svelte@latest my-sveltekit-app
    cd my-sveltekit-app
    npm install
    
  2. تثبيت Drizzle ORM والتبعيات الضرورية:

    npm install drizzle-orm @neondatabase/serverless pg pg-format dotenv
    npm install -D drizzle-kit
    
  3. إنشاء ملف .env:

    DATABASE_URL="رابط قاعدة بيانات Neon الخاصة بك" # مثال: postgres://user:password@host:port/database
    

تعريف المخطط الخاص بك

قم بإنشاء ملف src/lib/server/db/schema.ts:

// src/lib/server/db/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const posts = pgTable('posts', {
    id: serial('id').primaryKey(),
    title: text('title').notNull(),
    content: text('content'),
    createdAt: timestamp('created_at').defaultNow(),
});

export type Post = typeof posts.$inferSelect; // نوع الإرجاع عند تحديد البيانات
export type InsertPost = typeof posts.$inferInsert; // نوع الإدراج

الاتصال بقاعدة البيانات

قم بإنشاء ملف src/lib/server/db/index.ts:

// src/lib/server/db/index.ts
import { drizzle } from 'drizzle-orm/node-postgres';
import { Client } from 'pg';
import * as schema from './schema';
import { DATABASE_URL } from '$env/static/private'; // مهم للإنتاج

const client = new Client({
  connectionString: DATABASE_URL,
});

client.connect();

export const db = drizzle(client, { schema });

إنشاء عمليات الترحيل (Migrations)

  1. تكوين Drizzle Kit: أنشئ ملف drizzle.config.ts في جذر مشروعك.

    // drizzle.config.ts
    import type { Config } from "drizzle-kit";
    import { loadEnvConfig } from "@next/env";
    
    loadEnvConfig({ projectDir: "." });
    
    export default {
      schema: "./src/lib/server/db/schema.ts",
      out: "./drizzle",
      driver: "pg",
      dbCredentials: {
        connectionString: process.env.DATABASE_URL || "",
      },
      verbose: true,
      strict: true,
    } satisfies Config;
    
  2. إنشاء وتنفيذ عمليات الترحيل:

    npx drizzle-kit generate:pg
    npx drizzle-kit push:pg
    

تنفيذ إجراءات الخادم (Server Actions)

قم بإنشاء ملف src/lib/actions.ts:

// src/lib/actions.ts
'use server';

import { db } from './server/db';
import { posts } from './server/db/schema';
import { revalidatePath } from 'next/cache';
import {redirect} from 'sveltekit-flash-message/server';
import { message, superValidate } from 'sveltekit-flash-message/server';
import {postSchema} from './schemas'
import { fail } from '@sveltejs/kit';

export async function createPost(formData: FormData) {
  const schema = await superValidate(formData, postSchema);

	if (!schema.valid) {
    return fail(400, { schema })
	}
  
  const {title, content} = schema.data

  try {
    await db.insert(posts).values({ title: title, content: content });
  } catch (e: any) {
    console.error(e);
    return message(schema, 'فشل في إنشاء المنشور', { status: 500 });
  }


  revalidatePath('/');
  throw redirect(303, '/', { type: 'success', message: 'تم إنشاء المنشور بنجاح!' });
}

إنشاء النموذج وعرض المنشورات

عدل src/routes/+page.svelte:

<!-- src/routes/+page.svelte -->
<script>
  import { createPost } from '$lib/actions';
  import { enhance } from '$app/forms';
	import { superForm } from 'sveltekit-flash-message/client';
  import {postSchema} from '$lib/schemas'
  import { invalidateAll } from '$app/navigation';
	import type { PageData } from './$types';
	import { browser } from '$app/environment';

  export let data: PageData;
  $: ({ posts } = data)


  const { form, enhance: enhancedForm, errors, message } = superForm(postSchema, {
		onSubmit: async ({ result, submitter }) => {
			if (result.type === 'success') {
				if (browser) {
					invalidateAll();
				}
			}
		}
	});
</script>

{#if $message}
  <div class="alert alert-success">{$message.message}</div>
{/if}


<form method="POST" action="?/createPost" use:enhancedForm>
  <label for="title">العنوان:</label>
  <input type="text" id="title" name="title" bind:value={$form.title} aria-invalid={$errors.title ? 'true' : undefined}>
  {#if $errors.title}
    <div class="error">{$errors.title}</div>
  {/if}

  <label for="content">المحتوى:</label>
  <textarea id="content" name="content" bind:value={$form.content}></textarea>

  <button type="submit">إنشاء منشور</button>
  {#if $message && $message.message && $message.status === 500}
  <div class="error">{$message.message}</div>
  {/if}
</form>

<h2>المنشورات</h2>
{#each posts as post}
  <div>
    <h3>{post.title}</h3>
    <p>{post.content}</p>
  </div>
{/each}

عدل src/routes/+page.server.ts لتحميل المنشورات الأولية:

// src/routes/+page.server.ts
import { db } from '$lib/server/db';
import { posts } from '$lib/server/db/schema';
import type { PageServerLoad } from './$types';
import {createPost} from '$lib/actions'

export const load: PageServerLoad = async () => {
    const allPosts = await db.select().from(posts);
    return {
        posts: allPosts,
    };
};

export const actions = {createPost}

أخيرًا، قم بتثبيت sveltekit-flash-message و @sveltejs/adapter-auto لرسائل الفلاش. أضف import { dev } from '$app/environment'; في src/hooks.server.js و +layout.ts واستخدم sequence إذا لزم الأمر كما هو موضح في وثائق sveltekit-flash-message لإعداد رسائل الفلاش، وأضف المحول إلى svelte.config.js.

أيضًا قم بإنشاء مخططات src/lib/schemas.ts:

import { z } from 'zod';

export const postSchema = z.object({
	title: z.string().min(3).max(100),
	content: z.string().min(10)
});

خاتمة

يوفر هذا الدليل أساسًا لبناء تطبيقات SvelteKit كاملة باستخدام Server Actions و Drizzle ORM. يمكنك التوسع في هذا الأساس عن طريق إضافة المصادقة ونماذج بيانات أكثر تعقيدًا وميزات واجهة مستخدم متقدمة. تذكر دائمًا تأمين بيانات اعتماد قاعدة البيانات الخاصة بك والتحقق من صحة إدخال المستخدم بشكل صحيح في الإنتاج.