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

من الصفر إلى الإنتاج: بناء تطبيق متكامل باستخدام SvelteKit و Supabase

المؤلفMajd Muhtaseb10‏/05‏/202515 دقيقة
من الصفر إلى الإنتاج: بناء تطبيق متكامل باستخدام SvelteKit و Supabase

مقدمة

سيرشدك هذا الدليل خلال بناء تطبيق أساسي متكامل باستخدام SvelteKit و Supabase. يوفر SvelteKit تجربة تطوير رائعة لبناء تطبيقات ويب سريعة وصديقة لمحركات البحث (SEO)، بينما يقدم Supabase واجهة خلفية قوية وسهلة الاستخدام كخدمة (Backend-as-a-Service).

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

  • Node.js (الإصدار 16 أو أعلى)
  • npm أو pnpm
  • حساب Supabase

إعداد مشروع SvelteKit الخاص بك

أولاً، قم بإنشاء مشروع SvelteKit جديد:

npm create svelte@latest my-sveltekit-app
cd my-sveltekit-app
npm install

تهيئة Supabase

  1. أنشئ مشروعًا جديدًا على Supabase (https://supabase.com/).
  2. بمجرد إنشاء مشروعك، انتقل إلى إعدادات المشروع وابحث عن عنوان URL للمشروع ومفتاح واجهة برمجة التطبيقات (API key) العامة. سنحتاج إليهما لاحقًا.
  3. أنشئ جدولاً في قاعدة بيانات Supabase الخاصة بك، وقم بتسميته على سبيل المثال todos، وأضف أعمدة مثل id (UUID، مفتاح أساسي)، و text (نص)، و completed (منطقي).

تكوين Supabase في SvelteKit

قم بتثبيت عميل JavaScript الخاص بـ Supabase:

npm install @supabase/supabase-js

أنشئ ملف .env في جذر مشروعك وأضف بيانات اعتماد Supabase الخاصة بك:

VITE_SUPABASE_URL="YOUR_SUPABASE_URL"
VITE_SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY"

أنشئ ملف supabaseClient.js في دليل src/lib الخاص بك:

// src/lib/supabaseClient.js
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

تنفيذ المصادقة

دعنا نضيف المصادقة باستخدام Supabase Auth UI. قم بتثبيت الحزمة الضرورية:

npm install @supabase/auth-ui-svelte @supabase/auth-ui-shared

أنشئ ملف +page.svelte داخل المجلد src/routes:

// src/routes/+page.svelte
<script>
  import { Auth } from '@supabase/auth-ui-svelte'
  import '@supabase/auth-ui-shared/dist/index.css'
	import { supabase } from '$lib/supabaseClient'
	import { onMount } from 'svelte';
  import { goto } from '$app/navigation';

  let session = null

	onMount(() => {
		supabase.auth.getSession().then(({ data: { session } }) => {
			if(session){
				goto('/todos');
			}
		})

		supabase.auth.onAuthStateChange((_event, _session) => {
			session = _session
			if(session){
				goto('/todos');
			}
		})
	})

</script>

{#if !session}
  <Auth supabaseClient={supabase} appearance={{ theme: 'dark' }} providers={[]} />
{/if}

الآن قم بإنشاء مسار /todos وملف +page.svelte داخل المجلد src/routes/todos:

// src/routes/todos/+page.svelte
<script>
    import { supabase } from '$lib/supabaseClient';
    import { onMount } from 'svelte';
    import { goto } from '$app/navigation';

    let todos = [];
    let newTodo = '';

    onMount(async () => {
        const { data, error } = await supabase
            .from('todos')
            .select('*')
            .order('id', { ascending: false });

        if (error) {
            console.error('Error fetching todos:', error);
            return;
        }

        todos = data;
    });

    async function addTodo() {
        const { data, error } = await supabase
            .from('todos')
            .insert([{ text: newTodo }])
            .select();

        if (error) {
            console.error('Error adding todo:', error);
            return;
        }

        todos = [...data, ...todos];
        newTodo = '';
    }

    async function toggleComplete(todo) {
        const { error } = await supabase
            .from('todos')
            .update({ completed: !todo.completed })
            .eq('id', todo.id);

        if (error) {
            console.error('Error updating todo:', error);
            return;
        }

		todos = todos.map((t) => {
			if(t.id === todo.id) {
				return {...t, completed: !t.completed}
			}
			return t;
		})
    }

    async function deleteTodo(todo) {
        const { error } = await supabase
            .from('todos')
            .delete()
            .eq('id', todo.id);

        if (error) {
            console.error('Error deleting todo:', error);
            return;
        }

        todos = todos.filter((t) => t.id !== todo.id);
    }

	async function signOut() {
		await supabase.auth.signOut()
		goto('/')
	}
</script>

<h1>مهامي</h1>

<input type="text" bind:value={newTodo} placeholder="أضف مهمة جديدة" />
<button on:click={addTodo}>أضف</button>

<ul>
    {#each todos as todo (todo.id)}
        <li>
            <input type="checkbox" checked={todo.completed} on:change={() => toggleComplete(todo)} />
            <span class:completed={todo.completed}>{todo.text}</span>
            <button on:click={() => deleteTodo(todo)}>حذف</button>
        </li>
    {/each}
</ul>

<button on:click={signOut}>تسجيل الخروج</button>

<style>
    .completed {
        text-decoration: line-through;
        color: gray;
    }
</style>

تشغيل التطبيق الخاص بك

npm run dev -- --open

يجب أن يكون تطبيقك قيد التشغيل الآن على http://localhost:5173.

خاتمة

لقد قمت بنجاح ببناء تطبيق متكامل باستخدام SvelteKit و Supabase. هذه مجرد البداية! استكشف SvelteKit و Supabase للمزيد من أجل بناء تطبيقات أكثر تعقيدًا وغنية بالميزات. تذكر تأمين تطبيقك، ومعالجة الأخطاء بأمان، وتحسين الأداء للإنتاج.