# ارتقای Next.js از 15 به 16 (آخرین نسخه) + فعال‌سازی امکانات جدید ## پروژه `nobat724_front` ## زمینه پروژه روی `next@15.5.7` و `react@18.3.1` است (React با `overrides` در `package.json` روی 18 پین شده). آخرین نسخه پایدار Next.js نسخه **16.3.x** است (16.2.10 LTS هم موجود است — هدف این ارتقا `next@latest` یعنی 16.3.x). Next 16 چند breaking change دارد (React 19 اجباری، حذف `next lint`، deprecate شدن `middleware` به نفع `proxy`، Turbopack به‌عنوان پیش‌فرض build/dev) و چند قابلیت جدید (Cache Components، React Compiler، Instant Navigations / Partial Prefetching در 16.3). **تمام کار باید روی برنچ جدا انجام شود** — `main` دست نخورد. ## مشکل / هدف 1. ارتقای `next` به آخرین نسخه (16.3.x) و `react`/`react-dom` به 19 2. رفع همه breaking changeها تا `npm run build` و `npm run test` سبز شود 3. فعال‌سازی امکانات جدید نسخه 16 که با معماری multi-domain پروژه سازگارند 4. رفتار SEO فعلی (متادیتا داخل ``، canonical، sitemap، robots) عیناً حفظ شود ## فایل‌های مرتبط | فایل | نقش | |------|-----| | `package.json` | نسخه‌ها، `overrides` پین React 18، اسکریپت `next lint` | | `next.config.js` | کانفیگ — شامل `htmlLimitedBots: /.*/` (فیکس SEO، **نباید حذف شود**)، `output: 'standalone'`، CSP headers | | `middleware.js` | تزریق هدر `x-pathname` برای canonical — در 16 باید به `proxy.js` تبدیل شود | | `app/layout.js` | `generateMetadata` مبتنی بر host (multi-domain) | | `lib/getStateInfo.js`, `lib/getCanonicalUrl.js`, `lib/auth.js` | خواندن `headers()`/`cookies()` — ۱۰ فایل از `next/headers` استفاده می‌کنند | | `app/doctor/[slug]/page.js`, `app/clinic/[slug]/page.js`, `app/blog/[slug]/page.js`, `app/sitemap.js` | fetch با `next: { revalidate: 3600, tags: [...] }` | | `Dockerfile`, `nixpacks.toml`, `liara.json` | deploy — خروجی standalone | | `vitest.config.mjs`, `test/` | تست‌ها با vitest + @testing-library/react | ## وضعیت فعلی ```json // package.json (بخش‌های مرتبط) "scripts": { "dev": "cross-env HOST=yazd-nobat.localhost PORT=3000 NODE_TLS_REJECT_UNAUTHORIZED=0 next dev", "build": "next build", "lint": "next lint" }, "dependencies": { "next": "^15.5.7", "@next/third-parties": "^15.5.7", "react": "^18.3.1", "react-dom": "^18.3.1", "@mui/material": "^5.18.0", "@mui/x-charts": "^7.29.1", "@mui/x-date-pickers": "^7.29.4" }, "overrides": { "react": "^18.3.1", "react-dom": "^18.3.1" } ``` ```js // middleware.js — کل فایل import { NextResponse } from 'next/server'; export function middleware(request) { const response = NextResponse.next(); response.headers.set('x-pathname', request.nextUrl.pathname); return response; } export const config = { matcher: [ '/((?!api|_next/static|_next/image|favicon.ico|panel|dashboard|login|login-verify).*)', ], }; ``` نکات پیش‌بررسی‌شده (لازم نیست دوباره جستجو شوند): - هیچ استفاده‌ای از `legacyBehavior`، `useFormState`، `publicRuntimeConfig`/`serverRuntimeConfig`، `getInitialProps`، `next/legacy/image`، prop سفارشی `quality` روی ``، custom webpack config، یا `export const dynamic/revalidate` در پروژه **وجود ندارد**. - `await params` از قبل در همه صفحات dynamic رعایت شده (الگوی Next 15). - هیچ فایل کانفیگ ESLint وجود ندارد (`next lint` بدون config اجرا می‌شده) و `eslint` در devDependencies نیست. - Node محلی v22 است (Next 16 حداقل 20.9 می‌خواهد — OK). ## وظایف ### ۱. ساخت برنچ ```bash cd nobat724_front git checkout -b upgrade/next-16 ``` همه commitها روی این برنچ. به `main` هیچ چیزی push نشود. ### ۲. ارتقای پکیج‌ها ```bash npx @next/codemod@latest upgrade latest ``` اگر codemod به هر دلیل کامل اجرا نشد، دستی: ```bash npm install next@latest react@latest react-dom@latest @next/third-parties@latest ``` - بخش `overrides` (پین React 18) از `package.json` **حذف شود** — دلیل پین، سازگاری قدیمی MUI بود؛ `@mui/material@5.18` و `@mui/x-*@7.29` هر دو peer-dep React 19 را پشتیبانی می‌کنند. - اگر پکیج‌های قدیمی (`react-google-map-picker`، `react-images-uploading`، `aos`) خطای peer-dep برای React 19 دادند: اول `npm install --legacy-peer-deps` را امتحان کن و در گزارش نهایی صریح ذکر کن؛ سپس در مرحله تست، صفحات استفاده‌کننده از این پکیج‌ها را در مرورگر چک کن (map picker در پنل، آپلود عکس، انیمیشن‌های AOS صفحه اصلی). - `@testing-library/react@16` و `vitest@2` با React 19 سازگارند؛ اگر تست‌ها خطای rendering دادند فقط نسخه `@testing-library/react` را به آخرین minor ارتقا بده. ### ۳. تبدیل `middleware.js` به `proxy.js` در Next 16 نام `middleware` deprecated و جایگزینش `proxy` است. فایل `middleware.js` را به `proxy.js` تغییر نام بده و تابع را rename کن: ```js // proxy.js import { NextResponse } from 'next/server'; export function proxy(request) { const response = NextResponse.next(); response.headers.set('x-pathname', request.nextUrl.pathname); return response; } export const config = { matcher: [ '/((?!api|_next/static|_next/image|favicon.ico|panel|dashboard|login|login-verify).*)', ], }; ``` **تست حیاتی بعد از این تغییر:** هدر `x-pathname` باید همچنان برسد — `curl -s http://yazd-nobat.localhost:3000/doctors | grep canonical` باید `https://nobat724.com/doctors` بدهد (اگر header نرسد، `getCanonicalUrl` مقدار `null` برمی‌گرداند و تگ canonical حذف می‌شود — این یعنی regression). ### ۴. جایگزینی `next lint` `next lint` در Next 16 حذف شده. چون هیچ کانفیگ ESLint موجود نیست: ```bash npm install -D eslint eslint-config-next ``` فایل `eslint.config.mjs` (flat config) بساز: ```js import { FlatCompat } from '@eslint/eslintrc'; const compat = new FlatCompat({ baseDirectory: import.meta.dirname }); export default [ ...compat.extends('next/core-web-vitals'), ]; ``` و در `package.json`: ```json "lint": "eslint app components lib services hooks context utils helper" ``` خطاهای lint موجود را فیکس نکن (خارج از scope) — فقط مطمئن شو دستور اجرا می‌شود؛ در صورت نیاز سطح خطاهای پرتکرار را در config به `warn` تنزل بده. ### ۵. Turbopack (پیش‌فرض جدید dev و build) Next 16 هم `next dev` و هم `next build` را با Turbopack اجرا می‌کند. پروژه custom webpack config ندارد، پس انتظار سازگاری می‌رود. فقط verify کن: - `npm run dev` بالا بیاید و صفحه اول، `/doctors`، `/doctor/[slug]` (یک uuid واقعی از خروجی `/doctors`) و `/panel` بدون خطای کنسول رندر شوند - `npm run build` موفق شود و خروجی `standalone` تولید کند (برای Docker/liara لازم است — `ls .next/standalone`) - استایل‌های emotion RTL (`stylis-plugin-rtl` در `mui/index.js` یا `ThemeRegistry`) درست کار کنند — یک صفحه را چک کن که دکمه‌ها/فرم‌ها RTL باشند اگر Turbopack با emotion/styled-components مشکل داشت، ابتدا `compiler.styledComponents: true` را در `next.config.js` امتحان کن؛ فقط به‌عنوان آخرین راه‌حل build را با فلگ `--webpack` برگردان و دلیل را در گزارش بنویس. ### ۶. فعال‌سازی React Compiler قابلیت پایدار نسخه 16 (و در 16.3 پشتیبانی Rust در Turbopack): ```bash npm install -D babel-plugin-react-compiler ``` ```js // next.config.js const nextConfig = { reactCompiler: true, // ... }; ``` بعد از فعال‌سازی، `npm run build` و تست‌های vitest باید سبز بمانند. اگر کامپایلر روی کامپوننت خاصی خطا داد (کامپوننت‌های کلاسی یا الگوهای غیراستاندارد)، همان کامپوننت را با `"use no memo"` مستثنا کن — کل قابلیت را خاموش نکن. ### ۷. Cache Components — ارزیابی محتاطانه (فعال‌سازی مشروط) `cacheComponents: true` مدل کش جدید نسخه 16 است (`"use cache"`, `cacheLife`, `cacheTag`) و پیش‌نیاز Partial Prefetching در 16.3. **هشدار معماری:** این پروژه multi-domain است — `generateMetadata` و layout و ده فایل دیگر به `headers()` (هدر `host`) وابسته‌اند؛ خروجی هر صفحه per-host متفاوت است. با `cacheComponents`، هر چیزی که `headers()` می‌خواند dynamic می‌ماند و کش کردنش باعث نشت محتوای یک شهر به دامنه شهر دیگر می‌شود. ترتیب کار: 1. ابتدا **بدون** فعال‌سازی، fetchهای موجود را دست‌نخورده بگذار — الگوی `next: { revalidate: 3600, tags: [...] }` در Next 16 همچنان پشتیبانی می‌شود 2. `cacheComponents: true` را روی یک commit جدا فعال کن و `npm run build` بگیر 3. اگر build خطای «uncached data access» برای مسیرهای متکی به `headers()` داد و رفعش نیاز به `Suspense`گذاری گسترده یا `"use cache"` روی توابع host-dependent داشت → **فعال‌سازی را revert کن** و در گزارش نهایی بنویس چرا (این قابلیت برای این معماری فعلاً امن نیست) 4. اگر build پاس شد → با دو host تست کن (`HOST=yazd-nobat.localhost` و یک شهر دیگر از `data/city.json` مثلاً با تغییر موقت HOST در اسکریپت dev) و مطمئن شو title/description/canonical هر دامنه مستقل است ### ۸. تمیزکاری‌های کانفیگ نسخه 16 در `next.config.js`: - `htmlLimitedBots: /.*/` **باید بماند** — فیکس عمدی برای رندر متادیتا داخل `` است (streaming metadata خاموش). بعد از ارتقا با `curl -s -A "Mozilla/5.0" http://yazd-nobat.localhost:3000/ | python3 -c "import sys; h=sys.stdin.read(); e=h.find(''); print('HEAD' if 0<=h.find('rel=\"canonical\"')` Commitها را مرحله‌ای بزن (ارتقا پکیج‌ها / proxy / eslint / react compiler / cache components هرکدام جدا) تا در صورت مشکل، revert تکی ممکن باشد. ## نکات مهم - **برنچ:** همه‌چیز روی `upgrade/next-16`؛ merge به `main` با کاربر است، خودت merge نکن. - **SEO regression خط قرمز است:** canonical به `https://nobat724.com/`، متادیتا در ``، `robots.js` و `sitemap.js` باید عیناً مثل قبل کار کنند. - ده فایل از `next/headers` استفاده می‌کنند — همه `await headers()` هستند (الگوی 15)؛ در 16 هم همین درست است. - `services/response.js` قرارداد API با backend (`clinicpro`) است — این ارتقا نباید هیچ تغییری در آن بدهد. - اسکریپت dev به `NODE_TLS_REJECT_UNAUTHORIZED=0` و `HOST` سفارشی وابسته است — بدون تغییر بماند. - اگر در حین کار مستندات لازم شد: راهنمای رسمی مهاجرت `https://nextjs.org/docs/app/guides/upgrading/version-16` و بلاگ‌های `nextjs.org/blog/next-16`, `next-16-1`, `next-16-2`, و 16.3. - بعد از اتمام: `graphify update .` در روت workspace اجرا شود.