Files
hamed e8e3d7bfd8 Add cache index and graph files for improved data handling
- Created stat-index.json to store metadata for various data files, including size, modification time, and hash.
- Added graph.html and graph.json files to the graphify-out directory for enhanced graph representation.
2026-07-06 10:12:59 +03:30

235 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ارتقای 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 فعلی (متادیتا داخل `<head>`، 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` روی `<Image>`، 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: /.*/` **باید بماند** — فیکس عمدی برای رندر متادیتا داخل `<head>` است (streaming metadata خاموش). بعد از ارتقا با `curl -s -A "Mozilla/5.0" http://yazd-nobat.localhost:3000/ | python3 -c "import sys; h=sys.stdin.read(); e=h.find('</head>'); print('HEAD' if 0<=h.find('rel=\"canonical\"')<e else 'BODY')"` تأیید کن هنوز `HEAD` است
- `images.minimumCacheTTL` در 16 پیش‌فرض ۴ ساعت شده — نیازی به تغییر نیست، فقط بدان
- `env.DEV_MODE` و CSP headers و `output: 'standalone'` دست نخورند
### ۹. تست نهایی و commit
```bash
npm run test # همه تست‌های vitest سبز
npm run build # build موفق با Turbopack
npm run lint # اجرای eslint بدون crash
```
بعد smoke test دستی با dev server:
- `/` — صفحه اصلی، جستجو، تصاویر next/image
- `/doctors` و `/doctor/[uuid]` — لیست و صفحه پزشک + JSON-LD
- `/blogs` و `/blog/[slug]`
- `/login` — فلوی OTP (فقط رندر فرم؛ ارسال واقعی لازم نیست)
- view-source صفحه اول: متادیتا (`keywords`, `canonical`, `og:*`, `twitter:*`) داخل `<head>`
Commitها را مرحله‌ای بزن (ارتقا پکیج‌ها / proxy / eslint / react compiler / cache components هرکدام جدا) تا در صورت مشکل، revert تکی ممکن باشد.
## نکات مهم
- **برنچ:** همه‌چیز روی `upgrade/next-16`؛ merge به `main` با کاربر است، خودت merge نکن.
- **SEO regression خط قرمز است:** canonical به `https://nobat724.com/<path>`، متادیتا در `<head>`، `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 اجرا شود.