# ارتقای 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 اجرا شود.