اگر با Vue کار میکنید، احتمالاً پرسش اصلی شما درباره Nuxt 4 این نیست که چند قابلیت تازه دارد؛ میخواهید بدانید پروژه فعلی چقدر تغییر میکند، کدام دردسرها کمتر میشوند و برای پروژه بعدی چه انتخابی منطقی است. Nuxt همچنان روی Vue بنا شده و مسئولیتهایی مثل مسیریابی، رندر روی سرور، دریافت داده و آمادهسازی خروجی برای استقرار را کنار هم قرار میدهد. نسخه چهارم این رابطه را عوض نکرده؛ مرز بخشهای پروژه و رفتار بعضی APIها را روشنتر کرده است.
این راهنما وضعیت را تا ۱۰ اکتبر ۲۰۲۶ توضیح میدهد. انتشار اولیه Nuxt 4 در ۱۵ ژوئیه ۲۰۲۵ با نسخههای تازهتر شاخه 4.x یکسان نیست. هنگام نگارش، Nuxt 4.6.1 آخرین انتشار پایدار است. به همین دلیل، تغییر پوشه app را به انتشار اولیه مربوط میکنیم و قابلیت تازهای مثل import از nuxt/server را در جای خودش، یعنی نسخه 4.6، بررسی میکنیم. عبارتهایی مثل «بازنویسی کامل» یا «بهترین فریمورک برای همه پروژهها» تصویر دقیقی از این تغییرات نمیدهند.
Nuxt چه چیزی به Vue اضافه میکند؟
Vue کتابخانهای برای ساخت رابط کاربری واکنشپذیر است. وقتی پروژه بزرگتر میشود، باید درباره مسیرها، بارگذاری داده، رندر اولیه، تنظیمات محیط و انتشار برنامه هم تصمیم بگیرید. Nuxt برای این بخشها قرارداد و ابزار آماده فراهم میکند. مثلاً یک فایل در پوشه pages میتواند صفحه بسازد و یک فایل در server/api میتواند endpoint سمت سرور باشد. این قراردادها تعداد تصمیمهای تکراری را کم میکنند، اما جای طراحی معماری محصول را نمیگیرند.
Nuxt 4 به معنی انتشار Vue 4 نیست. شماره نسخه این دو پروژه مستقل است و قابلیتهایشان هم در یک زمان منتشر نمیشوند. همچنین داشتن Nuxt الزام نمیکند که تمام برنامه شما همیشه SSR باشد. نوع رندر را باید با نیاز صفحه، تازگی داده و محیط استقرار هماهنگ کنید. صفحه عمومی مقاله، داشبورد بعد از ورود و گزارش سنگین مدیریتی الزاماً رفتار یکسانی ندارند. پیش از انتخاب تنظیمات، مشخص کنید چه محتوایی باید در پاسخ اولیه دیده شود و کدام تعامل فقط در مرورگر اتفاق میافتد.
تغییر اصلی ساختار: پوشه app و مرز روشن سرور
در ساختار پیشفرض Nuxt 4، بخش مربوط به برنامه Vue داخل app قرار میگیرد. فایل app.vue، صفحهها، کامپوننتها و composableهای رابط کاربری در این محدوده هستند. پوشههای server، shared و public در ریشه پروژه قرار میگیرند. نتیجه این است که کد سرور با فایلهای صفحه در یک محدوده مبهم جمع نمیشود و ابزارهای توسعه بهتر میتوانند تشخیص دهند هر فایل در چه محیطی اجرا خواهد شد.
این تغییر را فقط جابهجایی ظاهری پوشهها نبینید. اگر پروژهای دارید که مسیرهای فایل را دستی نوشته، alias سفارشی تعریف کرده یا یک ماژول روی ساختار قدیمی تکیه دارد، باید آن ارتباطها را بررسی کنید. ابزار مهاجرت بخشی از کار را انجام میدهد، اما نمیتواند معنای همه مسیرهای اختصاصی تیم شما را حدس بزند. برنامهای که تازه میسازید بهتر است از قرارداد پیشفرض شروع کند؛ برای پروژه موجود، هدف حفظ رفتار درست با کمترین تغییر ضروری است.
shared محل مناسبی برای نوعها یا تابعهای مشترک است، به شرط آنکه به API مخصوص مرورگر یا اطلاعات محرمانه سرور وابسته نباشند. قرار دادن یک فایل در این پوشه بهتنهایی آن را امن یا قابل اجرا در هر محیطی نمیکند. برای مثال، نوع Article میتواند مشترک باشد، ولی تابعی که کلید خصوصی یک سرویس را میخواند باید سمت سرور بماند. public نیز برای فایلهایی است که قرار است مستقیم در دسترس کاربر باشند؛ محتوای محرمانه را آنجا نگذارید.
دریافت داده: چرا useFetch با $fetch فرق دارد؟
وقتی صفحه روی سرور رندر میشود، Nuxt میتواند داده را دریافت کند و همراه HTML در Payload اولیه به مرورگر بفرستد. useFetch و useAsyncData برای این چرخه طراحی شدهاند. مرورگر هنگام Hydration میتواند از داده منتقلشده استفاده کند؛ بنابراین برای همان داده اولیه معمولاً لازم نیست یک درخواست مشابه را دوباره انجام دهد. این ویژگی به نحوه فراخوانی و تنظیمات شما وابسته است و به معنی ممنوع شدن هر درخواست بعدی نیست.
$fetch برای ارسال درخواست کاربرد دارد، اما بهتنهایی مدیریت Payload صفحه را بر عهده نمیگیرد. استفاده مستقیم از آن در setup ممکن است باعث دریافت دوباره هنگام اجرای سمت مرورگر شود. در مقابل، برای عملی مثل ارسال فرم پس از کلیک کاربر، $fetch انتخاب طبیعیتری است. نخست زمان اجرای درخواست را مشخص کنید، بعد ابزار را انتخاب کنید: داده لازم برای رندر صفحه با دادهای که پس از یک تعامل ارسال میشود، مسئله یکسانی ندارد.

در Nuxt 4، داده useFetch و useAsyncData بهصورت پیشفرض با shallowRef نگهداری میشود. یعنی تغییر یک فیلد داخلی شیء، الزاماً همان واکنشپذیری عمیقی را ندارد که قبلاً انتظار داشتید. اگر واقعاً به دنبال کردن تغییرهای تو در تو نیاز دارید، deep: true را آگاهانه انتخاب کنید؛ راه دیگر جایگزین کردن مقدار داده با یک شیء یا آرایه تازه است. انتخاب مناسب به شیوه ویرایش داده بستگی دارد، نه به یک توصیه مطلق برای همه صفحات.
کلید دریافت داده هم بخشی از قرارداد برنامه است. فراخوانیهایی با کلید مشترک، وضعیت داده مشترک دارند؛ پس گزینههایی مانند deep و transform باید با هم سازگار باشند. برای دو منبع مستقل، کلید یکسان نگذارید. همچنین آرایه خالی را با پایان بارگذاری اشتباه نگیرید. اگر default شما آرایه خالی است، رابط باید ابتدا status و error را بررسی کند و بعد درباره نبودن نتیجه تصمیم بگیرد. نمونه زیر همین ترتیب را نشان میدهد.
مثال کامل: یک API و صفحه فهرست مقالهها
این مثال برای Nuxt 4.6.1 نوشته شده است و به حساب کاربری، پایگاه داده یا سرویس بیرونی نیاز ندارد. دو مقاله نمونه از API محلی دریافت میشوند. ابتدا پروژه را با دستور رسمی ساخت پروژه ایجاد کنید و سپس Nuxt را روی نسخه مشخص این راهنما نصب کنید. برای ابزار CLI همراه نسخه 4.6، حداقل Node.js سازگار را رعایت کنید: 22.21 یا بالاتر در شاخه 22، 24.11 یا بالاتر در شاخه 24، یا شاخه 26 و بالاتر. صرف داشتن هر نسخهای از Node 22 کافی نیست.
npm create nuxt@latest nuxt-articles
cd nuxt-articles
npm install nuxt@4.6.1
ساخت پروژه را کامل کنید تا وابستگیها و تنظیمات اولیه ایجاد شوند. اگر فایل پیشفرض صفحه خوشآمدگویی وجود دارد، آن را با app.vue زیر جایگزین کنید. فایل صفحه را در app/pages/index.vue و endpoint را در server/api/articles.get.ts بسازید. NuxtPage محل نمایش صفحه فعلی است؛ بدون آن، صرف ساخت فایل صفحه در این مثال کافی نیست.
فایل app/app.vue
<template>
<NuxtPage />
</template>
فایل server/api/articles.get.ts
پسوند get مشخص میکند این endpoint برای درخواست GET است. خروجی، آرایهای از مقالهها با id، title و summary است. import از nuxt/server به نسخه 4.6 و بعد از آن مربوط میشود؛ اگر پروژه قدیمیتر دارید، ابتدا نسخه را هماهنگ کنید و این خط را بدون توجه به نسخه کپی نکنید.
import { defineEventHandler } from 'nuxt/server'
export default defineEventHandler(() => [
{ id: 1, title: 'شروع کار با Nuxt', summary: 'ساختار پروژه و مسیرهای صفحه.' },
{ id: 2, title: 'دریافت داده در SSR', summary: 'انتقال داده اولیه از سرور به مرورگر.' },
])
فایل app/pages/index.vue
<script setup lang="ts">
const { data: articles, status, error, refresh } = await useFetch('/api/articles', {
key: 'home-articles',
default: () => [],
})
</script>
<template>
<main dir="rtl" class="page" :aria-busy="status === 'pending'">
<h1>مقالههای آموزشی</h1>
<p v-if="status === 'pending'" role="status">در حال دریافت مقالهها…</p>
<section v-else-if="error" role="alert">
<p>دریافت مقالهها انجام نشد.</p>
<button type="button" @click="refresh()">دوباره تلاش کن</button>
</section>
<p v-else-if="articles.length === 0">هنوز مقالهای ثبت نشده است.</p>
<ul v-else class="cards">
<li v-for="article in articles" :key="article.id" class="card">
<h2>{{ article.title }}</h2>
<p>{{ article.summary }}</p>
</li>
</ul>
</main>
</template>
<style scoped>
.page { max-width: 64rem; margin: 2rem auto; padding: 1rem; color: #172b24; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: 1rem; padding: 0; list-style: none; }
.card { padding: 1.25rem; border: 1px solid #b4c9bf; border-radius: 1rem; background: #f7fbf9; }
.card h2 { margin-top: 0; font-size: 1.25rem; }
button { padding: .6rem 1rem; cursor: pointer; }
</style>
حالا با npm run dev برنامه را اجرا کنید و صفحه اصلی را باز کنید. کد ابتدا بارگذاری، سپس خطا، سپس نتیجه خالی و در پایان فهرست را نشان میدهد. دکمه تلاش دوباره refresh را فراخوانی میکند. کلاسهای استفادهشده در markup نیز در همان فایل تعریف شدهاند؛ بنابراین نمونه به CSS پنهان یا کامپوننتی که معرفی نشده وابسته نیست. نوع پاسخ endpoint هم در پروژه Nuxt به استنتاج نوع داده کمک میکند.
در برنامه واقعی، متن خطا باید برای کاربر قابل فهم باشد و جزئیات فنی در مسیر گزارش خطای تیم بماند. اگر نتیجه واقعاً خالی است، پیام باید کار بعدی را روشن کند؛ مثلاً پیشنهاد ساخت اولین مقاله یا تغییر فیلتر. برای طراحی این بخش، راهنمای Empty State معنادار کمک میکند حالت خالی را با خطای شبکه یا انتظار برای پاسخ اشتباه نگیرید.
TypeScript و API تازه nuxt/server
Nuxt 4 محدودههای TypeScript مربوط به app، server، shared و ابزارهای ساخت را روشنتر کرده است. فایده عملی آن این است که خطاهای مربوط به استفاده از یک API در محیط نامناسب زودتر دیده شوند. این مرزبندی تضمین نمیکند داده ورودی معتبر است؛ TypeScript زمان اجرای درخواست را کنترل نمیکند. برای ورودی فرم، query یا پاسخ سرویس بیرونی همچنان به اعتبارسنجی Runtime نیاز دارید. مقاله اعتبارسنجی با Zod این تفاوت را با مثال توضیح میدهد.
در Nuxt 4.6، مسیر nuxt/server یک سطح API مشترک برای کد سرور فراهم میکند. هدف این است که handlerهای معمول کمتر به جزئیات موتور زیرین وابسته باشند. این موضوع را با جمله «Nuxt 4 کاملاً بر پایه Nitro 3 بازنویسی شده» جایگزین نکنید. نسخه 4.0 چنین تعریفی نداشت و مسیر تازه در نسخه 4.6 برای سازگاری با Nitro v2، Nitro v3 و مسیر آزمایشی Vite server طراحی شده است. برای پروژه جاری، نسخه نصبشده و تنظیمات آن را مبنا قرار دهید.
طبق معرفی رسمی 4.6، Nitro همچنان گزینه پیشنهادی پیشفرض است و مسیر Vite server ماهیت آزمایشی دارد. همچنین شماره Nuxt را مدرک فعال بودن Server Components ندانید. رندر سرور صفحه، Component Islands و قابلیتهای آزمایشی سرور مفاهیم متفاوتی هستند. اگر معماری شما به یکی از آنها وابسته است، مستندات همان قابلیت، محدودیتها و تنظیمات نسخه مورد استفاده را بخوانید؛ یک عنوان خبری برای تصمیم معماری کافی نیست.
مهاجرت از Nuxt 3: چه چیزهایی را باید حساب کرد؟
طبق یادداشت انتشار 4.6، پشتیبانی Nuxt 3 در ۳۱ ژوئیه ۲۰۲۶ پایان یافته است. بنابراین برای پروژه فعال، ماندن روی نسخه سه باید یک تصمیم موقت با برنامه مهاجرت مشخص باشد. قبل از ارتقا، سازگاری ماژولهای مهم مثل احراز هویت، مدیریت محتوا و ابزارهای استقرار را بررسی کنید. داشتن نسخه تازه Nuxt بهتنهایی مشکل ماژولی را که با آن سازگار نیست حل نمیکند.
راهنمای رسمی دستور npx nuxt upgrade --dedupe را برای ارتقا معرفی میکند و برای تغییرهای رایج نسخه چهار نیز codemod وجود دارد. ابزار خودکار کمک میکند کار تکراری کمتر شود، اما نتیجه آن باید با ساختار واقعی پروژه تطبیق داده شود. مسیر فایلها، aliasهای سفارشی، وضعیت shallowRef، کلیدهای مشترک داده و تنظیمات TypeScript مواردی هستند که بیشترین ارتباط را با کد روزمره دارند. ارتقا را همزمان با بازطراحی کامل محصول انجام ندهید؛ تفکیک این دو، علت خطاهای احتمالی را روشنتر میکند.
محیط انتشار را هم در برنامه مهاجرت بیاورید. نسخه Node روی رایانه توسعه، CI و سرور باید با نیاز نسخه جدید سازگار باشد. مسیرهایی که به ورود کاربر، cookie یا پاسخ متفاوت سرور وابستهاند، ارزش بررسی بیشتری دارند. اگر پروژه روی زیرساخت Serverless منتشر میشود، محدودیت محیط اجرا و وضعیت اتصال به داده را جدا از شماره Nuxt بررسی کنید. راهنمای تصمیمگیری درباره Serverless برای ارزیابی همین ملاحظات مفید است.
انتخاب بین Nuxt و Next.js
برتری قطعی Nuxt در تجربه توسعه نسبت به Next.js ادعایی نیست که بدون معیار بتوان پذیرفت. تیمی که Vue را خوب میشناسد، احتمالاً با Nuxt سریعتر به نتیجه میرسد؛ تیمی با محصول و کتابخانههای مبتنی بر React ممکن است از جابهجایی سودی نبرد. مهارت تیم، وابستگیهای فعلی، شیوه مدیریت محتوا و محیط انتشار، معیارهای قابل استفادهتری از رقابت میان نام فریمورکها هستند.
برای سایت محتوایی، دسترسی به محتوای اولیه، نشانی درست صفحه، metadata و مسیر ویرایش محتوا اهمیت دارند. برای داشبورد، مدیریت وضعیت، فرمها و تجربه تعامل بیشتر به چشم میآیند. Nuxt برای هر دو ابزار دارد، اما انتخاب آن هنوز نیازمند طراحی است. اگر در حال ساخت بخش مقاله هستید، راهنمای طراحی وبسایت محتوایی و بلاگ کمک میکند تصمیم فنی را با نیاز نویسنده و خواننده هماهنگ کنید.
ارزش Nuxt 4 برای توسعهدهنده Vue در قراردادهای روشنتر، مدیریت دقیقتر داده و جدا شدن مسئولیتهای پروژه است. از مثال کوچک شروع کنید، رفتار APIهای مورد استفاده را بشناسید و نسخههای جزئی را جداگانه دنبال کنید. تغییر ساختار app، shallowRef و مسیر تازه nuxt/server هرکدام مسئله مشخصی را حل میکنند؛ هیچکدام جای سنجیدن نیاز محصول و محدودیت زیرساخت شما را نمیگیرند.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!