الوثائقأطر عمل Fullstack
من Nuxt إلى Nexy
في Nexy، يحتفظ مشروع Nuxt بصفحاته .vue وتخطيطاته ومكوناته، بينما تنتقل معالجات server/api والبرمجيات الوسيطة للخادم وتحميل البيانات إلى الملفات Python المجاورة لها.
يعرض كل قسم أدناه عادة Nuxt، ثم نفس الشيء في Nexy.
اختر الوضع أولاً
| تطبيق Nuxt الخاص بك هو | وضع نكسي | الصفحات هي |
|---|---|---|
| التطبيق مع الملاحة العميل | وضع العميل، useCSR = True |
.vue الملفات ضمن src/routes/ |
| في الغالب المحتوى، وبعض الأجزاء التفاعلية | وضع الخادم، الافتراضي | .nexy صفحة تحتوي على Vue جزيرة |
from nexy.core.models import NexyConfigModelfrom nexy.frontend import vue class NexyConfig(NexyConfigModel): useFF = vue() useCSR = True useAliases = {"@": "src"}nuxt.config.ts يصبح هذا الملف. تستخدم الأقسام أدناه وضع العميل ما لم تنص على خلاف ذلك.
pages/
<template> <h1>About</h1></template><template> <h1>About</h1></template>pages/index.vue هو src/routes/index.vue، pages/blog/index.vue هو src/routes/blog/index.vue.
الصفحات الديناميكية و useRoute().params
<script setup lang="ts">const route = useRoute();</script> <template> <h1>{{ route.params.slug }}</h1></template>تصل المقاطع إلى الصفحة كدعائم:
<script setup lang="ts">defineProps<{ slug: string }>();</script> <template> <h1>{{ slug }}</h1></template>في أي مكون آخر، useParams() من @nexy/client يُرجعها كمرجع محسوب. [...slug].vue هو ملف شامل، كما هو الحال في Nuxt.
layouts/default.vue و app.vue
<template> <header>My app</header> <main><slot /></main></template>لا يوجد <NuxtLayout> ولا app.vue: الجذر layout.vue يملك الوثيقة ويغلف كل صفحة، و layout.vue في مجلد فرعي يعشش بداخلها.
<template> <html> <body> <header>My app</header> <main><slot /></main> </body> </html></template>يصبح التخطيط المسمى، definePageMeta({ layout: "admin" })، مجلدًا به layout.vue خاص به، أو مجموعة توجيه مثل (admin)/layout.vue.
<NuxtLink> و navigateTo
<script setup lang="ts">const go = () => navigateTo("/dashboard");</script> <template> <NuxtLink to="/about" active-class="active">About</NuxtLink> <button @click="go">Dashboard</button></template><script setup lang="ts">import { Link, useRouter } from "@nexy/client"; const router = useRouter();</script> <template> <Link href="/about" active-class="active">About</Link> <button @click="router.push('/dashboard')">Dashboard</button></template>لا يتم استيراد المكونات تلقائيًا: قم باستيرادها حيث تستخدمها.
server/api
export default defineEventHandler((event) => { const id = Number(getRouterParam(event, "id")); return { id };});ملف Python واحد لكل عنوان URL، ووظيفة واحدة لكل طريقة، بدون اللاحقة .get:
async def GET(id: int): return {"id": id}readBody والتصديق
import { z } from "zod"; const NewItem = z.object({ name: z.string(), price: z.number().positive() }); export default defineEventHandler(async (event) => { const item = await readValidatedBody(event, NewItem.parse); setResponseStatus(event, 201); return item;});from pydantic import BaseModel, Field from nexy.http import JSONResponse class NewItem(BaseModel): name: str price: float = Field(gt=0) async def POST(item: NewItem): return JSONResponse(item.model_dump(), status_code=201)getQuery و createError
export default defineEventHandler((event) => { const id = Number(getRouterParam(event, "id")); const { currency = "EUR" } = getQuery(event); if (id > 100) throw createError({ statusCode: 404, statusMessage: "No such order" }); return { id, currency };});from nexy.http import HTTPException async def GET(id: int, currency: str = "EUR"): if id > 100: raise HTTPException(status_code=404, detail="No such order") return {"id": id, "currency": currency}useFetch و useAsyncData
<script setup lang="ts">const { data: users } = await useFetch("/api/users");</script> <template> <ul> <li v-for="user in users" :key="user.id">{{ user.name }}</li> </ul></template>في وضع العميل، تستدعي الصفحة المعالج من المتصفح:
async def GET(): return [{"id": 1, "name": "Ada"}, {"id": 2, "name": "Alan"}]<script setup lang="ts">import { onMounted, ref } from "vue"; const users = ref<{ id: number; name: string }[]>([]);onMounted(async () => { users.value = await (await fetch("/api/users")).json();});</script> <template> <ul> <li v-for="user in users" :key="user.id">{{ user.name }}</li> </ul></template>في وضع الخادم، يقوم الجزء الأمامي من صفحة .nexy بتحميل البيانات بينما يعرضها الخادم:
users = [{"id": 1, "name": "Ada"}, {"id": 2, "name": "Alan"}]<ul> {% for user in users %} <li>{{ user.name }}</li> {% endfor %}</ul>الطفرات: $fetch إلى طريق الخادم
<script setup lang="ts">const title = ref("");const add = () => $fetch("/api/todos", { method: "POST", body: { title: title.value } });</script>يتخطى الإجراء عنوان URL: يقوم Nexy بإنشاء عميل مكتوب من الدالة Python.
from pydantic import BaseModel from nexy.decorators import Action class Todo(BaseModel): title: str done: bool = False @Actionasync def add_todo(title: str) -> Todo: return Todo(title=title)<script setup lang="ts">import { ref } from "vue";import { useAction } from "@nexy/client";import { add_todo } from "@nexy/actions"; const title = ref("");const { run, pending, data } = useAction(add_todo, { onSuccess: () => (title.value = ""),});</script> <template> <form @submit.prevent="run({ title })"> <input v-model="title" /> <button :disabled="pending">Add</button> <p v-if="data">Added {{ data.title }}</p> </form></template>الوسيطة الخادم
export default defineEventHandler((event) => { setResponseHeader(event, "x-app", "demo");});from nexy.http import Request async def middleware(request: Request, call_next): response = await call_next(request) response.headers["x-app"] = "demo" return responseطريق الوسيطة
export default defineNuxtRouteMiddleware(() => { if (!useCookie("session").value) return navigateTo("/login");});يتم تشغيل middleware.py الموجود في المجلد على الخادم، قبل الصفحة أو المعالج:
from nexy.http import RedirectResponse, Request async def middleware(request: Request, call_next): if "session" not in request.cookies: return RedirectResponse("/login", status_code=307) return await call_next(request)async def GET(): return {"visits": 12}useHead و useSeoMeta
<script setup lang="ts">useSeoMeta({ title: "Blog", description: "Posts about Nexy" });</script>لا تحتوي الصفحة .vue على واجهة برمجة تطبيقات للبيانات الوصفية في Nexy: ضع العلامات في تخطيط الجذر. في وضع الخادم، تقوم صفحة .nexy بتعيينها، ويكتبها تخطيطها بـ {{ useMetadata().html() }}:
metadata = {"title": "Blog", "description": "Posts about Nexy"}<h1>Blog</h1>routeRules مع swr أو isr
export default defineNuxtConfig({ routeRules: { "/news": { swr: 60 } },});تنتقل القاعدة إلى الصفحة، في وضع الخادم:
revalidate = 60<h1>News</h1>Vue المكونات الموجودة في صفحات الخادم
<script setup lang="ts">import { ref } from "vue"; const props = defineProps<{ start?: number }>();const count = ref(props.start ?? 0);</script> <template> <button @click="count++">{{ count }}</button></template>في وضع الخادم، يكون المكون عبارة عن جزيرة من صفحة .nexy، مثل جزء <ClientOnly> من صفحة Nuxt التي يعرضها الخادم، مع توجيه لوقت الترطيب:
from "@/components/Counter.vue" import Counter<h1>Static heading</h1><Counter start=3 directive="client:visible" />error.vue
<script setup lang="ts">defineProps<{ error: { statusCode: number } }>();</script> <template> <h1>{{ error.statusCode }}</h1></template>src/routes/notfound.vue يجيب على عناوين URL غير المعروفة في وضع العميل، notfound.nexy في وضع الخادم، ويحصل عملاء API على {"detail": ...}.
runtimeConfig
export default defineNuxtConfig({ runtimeConfig: { databaseUrl: process.env.DATABASE_URL },});إعدادات الخادم هي متغيرات البيئة، اقرأ في Python:
import os DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///dev.db")الجري
| نوكست | نكسي |
|---|---|
npx nuxi init |
nx new، القالب web-fbr-vue |
nuxt dev |
nx dev |
nuxt build، ثم node .output/server/index.mjs |
nx build، ثم nx start |
nuxt generate |
لا يوجد تصدير ثابت: nx start يخدم الصفحات |
public/ |
public/، خدم في / |