بناء تطبيق SvelteKit كامل باستخدام إجراءات الخادم و Drizzle ORM
مقدمة
يوضح هذا الدليل كيفية بناء تطبيق كامل باستخدام SvelteKit و Server Actions و Drizzle ORM. سنغطي إعداد بيئتك وتعريف المخطط الخاص بك وتنفيذ عمليات CRUD الأساسية.
المتطلبات الأساسية
- Node.js (الإصدار 18 أو أعلى)
- npm أو yarn
- معرفة أساسية بـ SvelteKit و JavaScript
الإعداد
-
إنشاء مشروع SvelteKit جديد:
npm create svelte@latest my-sveltekit-app cd my-sveltekit-app npm install
-
تثبيت Drizzle ORM والتبعيات الضرورية:
npm install drizzle-orm @neondatabase/serverless pg pg-format dotenv npm install -D drizzle-kit
-
إنشاء ملف
.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)
-
تكوين 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;
-
إنشاء وتنفيذ عمليات الترحيل:
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. يمكنك التوسع في هذا الأساس عن طريق إضافة المصادقة ونماذج بيانات أكثر تعقيدًا وميزات واجهة مستخدم متقدمة. تذكر دائمًا تأمين بيانات اعتماد قاعدة البيانات الخاصة بك والتحقق من صحة إدخال المستخدم بشكل صحيح في الإنتاج.