upgrade: Next.js 16 + React 19, codemod transforms (async APIs, middleware→proxy, ESLint flat config)
This commit is contained in:
parent
c496863180
commit
7533f8c97c
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "next/typescript"]
|
||||
}
|
||||
12
eslint.config.mjs
Normal file
12
eslint.config.mjs
Normal file
@ -0,0 +1,12 @@
|
||||
import { defineConfig } from "eslint/config";
|
||||
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
|
||||
import nextTypescript from "eslint-config-next/typescript";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export default defineConfig([{
|
||||
extends: [...nextCoreWebVitals, ...nextTypescript],
|
||||
}]);
|
||||
@ -5,6 +5,7 @@ import withBundleAnalyzer from '@next/bundle-analyzer';
|
||||
const nextConfig = {
|
||||
output: 'standalone',
|
||||
reactStrictMode: false,
|
||||
turbopack: {},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
|
||||
3513
package-lock.json
generated
3513
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@ -6,7 +6,7 @@
|
||||
"dev": "start cmd.exe /k \"C:/laragon/bin/mysql/mysql-8.0.30-winx64/bin/mysqld.exe\" && start cmd.exe /k \"cd C:/Users/p.aghaei/Desktop/Work/parsa/parsaaghayi/backend && php artisan serve\" && start cmd.exe /k \"cd C:/Users/p.aghaei/Desktop/Work/parsa/parsaaghayi/frontend && next dev --port 3001\"",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"analyze": "cross-env ANALYZE=true next build",
|
||||
"test": "vitest run",
|
||||
@ -15,33 +15,37 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"cookies-next": "^4.3.0",
|
||||
"next": "14.2.11",
|
||||
"next": "16.2.9",
|
||||
"nextjs-toploader": "^3.7.15",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react": "19.2.7",
|
||||
"react-dom": "19.2.7",
|
||||
"react-loading-skeleton": "^3.5.0",
|
||||
"sharp": "^0.33.5",
|
||||
"tailwindcss": "^0.0.0-insiders.e8614a2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^14.2.13",
|
||||
"@next/bundle-analyzer": "16.2.9",
|
||||
"@types/negotiator": "^0.6.3",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"cypress": "^15.17.0",
|
||||
"eslint": "^8",
|
||||
"eslint": "^9",
|
||||
"jsdom": "^29.1.1",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"vitest": "^4.1.9",
|
||||
"eslint-config-next": "14.2.11",
|
||||
"eslint-config-next": "16.2.9",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-tailwindcss": "^0.6.6",
|
||||
"typescript": "^5",
|
||||
"webpack-bundle-analyzer": "^4.10.2"
|
||||
},
|
||||
"overrides": {
|
||||
"@types/react": "19.2.17",
|
||||
"@types/react-dom": "19.2.3"
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ export const metadata: Metadata = {
|
||||
};
|
||||
|
||||
export default async function Home() {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
const socialLinks = [
|
||||
{ href: "#", src: "/images/icons/facebook.svg", alt: "facebook" },
|
||||
{ href: "#", src: "/images/icons/twitter.svg", alt: "twitter" },
|
||||
|
||||
@ -2,12 +2,13 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
interface PropsType {
|
||||
params: {
|
||||
params: Promise<{
|
||||
notFound: string[];
|
||||
};
|
||||
}>;
|
||||
}
|
||||
|
||||
export default function NotFound({ params }: PropsType) {
|
||||
export default async function NotFound(props: PropsType) {
|
||||
const params = await props.params;
|
||||
const imageUrl = `/images/404/${Math.floor(Math.random() * 5) + 1}.jpg`;
|
||||
|
||||
return (
|
||||
|
||||
@ -6,7 +6,7 @@ import "react-loading-skeleton/dist/skeleton.css";
|
||||
|
||||
export default async function AboutMe() {
|
||||
const aboutMeData: AboutMeDataType = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/website/about-me/1/translation/${cookies().get("selectedLocale")?.value ? cookies().get("selectedLocale")?.value : cookies().get("defaultLocale")?.value}`,
|
||||
`${process.env.NEXT_PUBLIC_API_URL}/website/about-me/1/translation/${(await cookies()).get("selectedLocale")?.value ? (await cookies()).get("selectedLocale")?.value : (await cookies()).get("defaultLocale")?.value}`,
|
||||
).then((res) => res.json());
|
||||
|
||||
return (
|
||||
|
||||
@ -5,7 +5,7 @@ import { getDefaultLocale } from "@/app/lib/functions/utils";
|
||||
import Link from "next/link";
|
||||
|
||||
export default async function Footer() {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex flex-col items-center gap-[50px] bg-[#F8F8F8] py-[50px]">
|
||||
|
||||
@ -7,7 +7,7 @@ import { getDictionary } from "@/app/lib/functions/dictionaries";
|
||||
import { getDefaultLocale } from "@/app/lib/functions/utils";
|
||||
|
||||
export default async function Header() {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -66,8 +66,8 @@ export default async function Header() {
|
||||
{dict.website.header.Blog}
|
||||
</Link>
|
||||
<SelectLanguage
|
||||
selectedLocale={cookies().get("selectedLocale")}
|
||||
defaultLocale={cookies().get("defaultLocale")}
|
||||
selectedLocale={(await cookies()).get("selectedLocale")}
|
||||
defaultLocale={(await cookies()).get("defaultLocale")}
|
||||
/>
|
||||
</ul>
|
||||
<div className="flex gap-1">
|
||||
|
||||
@ -2,12 +2,13 @@ import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
interface PropsType {
|
||||
params: {
|
||||
params: Promise<{
|
||||
notFound: string[];
|
||||
};
|
||||
}>;
|
||||
}
|
||||
|
||||
export default function NotFound({ params }: PropsType) {
|
||||
export default async function NotFound(props: PropsType) {
|
||||
const params = await props.params;
|
||||
const imageUrl = `/images/404/${Math.floor(Math.random() * 5) + 1}.jpg`;
|
||||
|
||||
return (
|
||||
|
||||
@ -26,9 +26,8 @@ async function fetchCategoryData(
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: categorySlugPropsType): Promise<Metadata> {
|
||||
export async function generateMetadata(props: categorySlugPropsType): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const categoryData: CategoryDataType = await fetchCategoryData(
|
||||
params.categorySlug,
|
||||
new URLSearchParams(),
|
||||
@ -45,11 +44,10 @@ export async function generateMetadata({
|
||||
};
|
||||
}
|
||||
|
||||
export default async function SingleCategory({
|
||||
params,
|
||||
searchParams,
|
||||
}: categorySlugPropsType) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
export default async function SingleCategory(props: categorySlugPropsType) {
|
||||
const searchParams = await props.searchParams;
|
||||
const params = await props.params;
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
|
||||
const categoryData: CategoryDataType = await fetchCategoryData(
|
||||
params.categorySlug,
|
||||
|
||||
@ -25,7 +25,8 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export default async function Categories({ searchParams }: categoryPropsType) {
|
||||
export default async function Categories(props: categoryPropsType) {
|
||||
const searchParams = await props.searchParams;
|
||||
const CategoriesData: CategoriesListType = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_BLOG_API_URL}/categories?per_page=${searchParams.per_page ? searchParams.per_page : process.env.NEXT_PUBLIC_CATEGORIES_PER_CATEGORY_PAGE}${searchParams.page ? `&page=${searchParams.page}` : ""}`,
|
||||
{
|
||||
@ -33,7 +34,7 @@ export default async function Categories({ searchParams }: categoryPropsType) {
|
||||
},
|
||||
).then((res) => res.json());
|
||||
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
|
||||
return (
|
||||
<div className="my-10 flex w-full max-w-[1280px] flex-wrap justify-center">
|
||||
|
||||
@ -5,7 +5,7 @@ import Image from "next/image";
|
||||
import React from "react";
|
||||
|
||||
export default async function Footer() {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="absolute bottom-0 flex w-full flex-wrap items-center justify-around gap-5 bg-white px-1 py-5">
|
||||
<Image
|
||||
|
||||
@ -10,7 +10,7 @@ import { getDictionary } from "@/app/lib/functions/dictionaries";
|
||||
import { getDefaultLocale } from "@/app/lib/functions/utils";
|
||||
|
||||
export default async function Header() {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
|
||||
return (
|
||||
<div className="fixed z-50 flex w-full items-center justify-center bg-blog-background py-10">
|
||||
@ -29,8 +29,8 @@ export default async function Header() {
|
||||
<NavLinks className="hidden md:flex" dict={dict} />
|
||||
<SelectLanguage
|
||||
className="hidden md:flex"
|
||||
selectedLocale={cookies().get("selectedLocale")}
|
||||
defaultLocale={cookies().get("defaultLocale")}
|
||||
selectedLocale={(await cookies()).get("selectedLocale")}
|
||||
defaultLocale={(await cookies()).get("defaultLocale")}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-center gap-1 sm:gap-5">
|
||||
|
||||
@ -9,7 +9,7 @@ interface CategoriesProps {
|
||||
}
|
||||
|
||||
export default async function Categories({ data }: CategoriesProps) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="mb-5 flex w-full max-w-[95%] flex-wrap gap-10">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
|
||||
@ -9,7 +9,7 @@ interface FilteredPostsProps {
|
||||
}
|
||||
|
||||
export default async function FilteredPosts({ data }: FilteredPostsProps) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="mb-5 flex max-w-[95%] flex-wrap gap-10">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
|
||||
@ -9,7 +9,7 @@ interface NewProps {
|
||||
}
|
||||
|
||||
export default async function New({ data }: NewProps) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="flex w-full max-w-[95%] flex-wrap justify-between gap-5">
|
||||
<div className="relative flex h-[300px] w-full flex-col justify-center overflow-hidden rounded-md border sm:h-[400px] md:h-auto md:w-[60%]">
|
||||
|
||||
@ -9,7 +9,7 @@ interface RandomProps {
|
||||
}
|
||||
|
||||
export default async function Random({ data }: RandomProps) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
return (
|
||||
<div className="mb-10 flex w-full max-w-[90%] flex-wrap gap-10">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
|
||||
@ -33,7 +33,7 @@ const Pagination: React.FC<PaginationProps> = ({ meta, baseUrl, dict }) => {
|
||||
return `${baseUrl}?${params.toString()}`; // استفاده از baseUrl
|
||||
};
|
||||
|
||||
const renderPageNumbers = (): (JSX.Element | string)[] => {
|
||||
const renderPageNumbers = (): (React.JSX.Element | string)[] => {
|
||||
const delta = 1; // تعداد صفحات اطراف صفحه فعلی که نمایش داده شوند
|
||||
const range: number[] = [];
|
||||
const rangeWithDots: (number | string)[] = [];
|
||||
|
||||
@ -23,13 +23,12 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export default async function FilteredPosts({
|
||||
params,
|
||||
searchParams,
|
||||
}: FilteredPostsPagepropsType) {
|
||||
export default async function FilteredPosts(props: FilteredPostsPagepropsType) {
|
||||
const searchParams = await props.searchParams;
|
||||
const params = await props.params;
|
||||
let filteredPostApiUrl: string;
|
||||
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
|
||||
switch (params.filter.replaceAll(/%20|-|_/g, " ").toLowerCase()) {
|
||||
case "new":
|
||||
|
||||
@ -24,9 +24,8 @@ async function fetchPostData(postSlug: string): Promise<PostSlugPagePostType> {
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: PostSlugPagepropsType): Promise<Metadata> {
|
||||
export async function generateMetadata(props: PostSlugPagepropsType): Promise<Metadata> {
|
||||
const params = await props.params;
|
||||
const post: PostSlugPagePostType = await fetchPostData(params.postSlug);
|
||||
|
||||
return {
|
||||
@ -40,8 +39,9 @@ export async function generateMetadata({
|
||||
};
|
||||
}
|
||||
|
||||
export default async function SinglePost({ params }: PostSlugPagepropsType) {
|
||||
const dict = await getDictionary(getDefaultLocale());
|
||||
export default async function SinglePost(props: PostSlugPagepropsType) {
|
||||
const params = await props.params;
|
||||
const dict = await getDictionary(await getDefaultLocale());
|
||||
const postData: PostSlugPagePostType = await fetchPostData(params.postSlug);
|
||||
|
||||
return (
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
type propsType = {
|
||||
params: { slug: string };
|
||||
params: Promise<{ slug: string }>;
|
||||
};
|
||||
|
||||
export default function SingleTag({ params }: propsType) {
|
||||
export default async function SingleTag(props: propsType) {
|
||||
const params = await props.params;
|
||||
return <div>{params.slug}</div>;
|
||||
}
|
||||
|
||||
@ -8,14 +8,15 @@ const mikhak = localFont({
|
||||
weight: "100 900",
|
||||
});
|
||||
|
||||
export default function RootLayout({
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const defaultLocale = await getDefaultLocale();
|
||||
|
||||
return (
|
||||
<html lang={getDefaultLocale()} dir={getDefaultLocale() === "fa" ? "rtl" : "ltr"}>
|
||||
<html lang={defaultLocale} dir={defaultLocale === "fa" ? "rtl" : "ltr"}>
|
||||
<body
|
||||
suppressHydrationWarning={true}
|
||||
className={`${mikhak.variable} relative flex h-full w-full flex-col items-center justify-between antialiased`}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const getDefaultLocale = () => {
|
||||
const defaultLocaleCookie = cookies().get("defaultLocale");
|
||||
export const getDefaultLocale = async () => {
|
||||
const cookieStore = await cookies();
|
||||
const defaultLocaleCookie = cookieStore.get("defaultLocale");
|
||||
const defaultLocale: string = defaultLocaleCookie
|
||||
? defaultLocaleCookie.value
|
||||
: "en";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
export function proxy(request: NextRequest) {
|
||||
const response = NextResponse.next();
|
||||
const acceptLanguage = request.headers.get("accept-language");
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
@ -11,7 +15,7 @@
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
@ -19,9 +23,21 @@
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "tailwind.config.ts", "src/middleware.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
"tailwind.config.ts",
|
||||
"src/proxy.ts",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user