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

13 KiB
Raw Permalink Blame History

ارتقای 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

وضعیت فعلی

// 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"
}
// 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).

وظایف

۱. ساخت برنچ

cd nobat724_front
git checkout -b upgrade/next-16

همه commitها روی این برنچ. به main هیچ چیزی push نشود.

۲. ارتقای پکیج‌ها

npx @next/codemod@latest upgrade latest

اگر codemod به هر دلیل کامل اجرا نشد، دستی:

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 کن:

// 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 موجود نیست:

npm install -D eslint eslint-config-next

فایل eslint.config.mjs (flat config) بساز:

import { FlatCompat } from '@eslint/eslintrc';

const compat = new FlatCompat({ baseDirectory: import.meta.dirname });

export default [
  ...compat.extends('next/core-web-vitals'),
];

و در package.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):

npm install -D babel-plugin-react-compiler
// 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

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 اجرا شود.