- 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.
13 KiB
ارتقای 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 دست نخورد.
مشکل / هدف
- ارتقای
nextبه آخرین نسخه (16.3.x) وreact/react-domبه 19 - رفع همه breaking changeها تا
npm run buildوnpm run testسبز شود - فعالسازی امکانات جدید نسخه 16 که با معماری multi-domain پروژه سازگارند
- رفتار 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 میماند و کش کردنش باعث نشت محتوای یک شهر به دامنه شهر دیگر میشود.
ترتیب کار:
- ابتدا بدون فعالسازی، fetchهای موجود را دستنخورده بگذار — الگوی
next: { revalidate: 3600, tags: [...] }در Next 16 همچنان پشتیبانی میشود cacheComponents: trueرا روی یک commit جدا فعال کن وnpm run buildبگیر- اگر build خطای «uncached data access» برای مسیرهای متکی به
headers()داد و رفعش نیاز بهSuspenseگذاری گسترده یا"use cache"روی توابع host-dependent داشت → فعالسازی را revert کن و در گزارش نهایی بنویس چرا (این قابلیت برای این معماری فعلاً امن نیست) - اگر 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 اجرا شود.