Codemods

Codemods هي تحويلات تعمل على قاعدة الكود الخاصة بك برمجيًا. هذا يسمح بتطبيق عدد كبير من التغييرات برمجيًا دون الحاجة إلى المرور يدويًا عبر كل ملف.

يوفر Next.js تحويلات Codemod للمساعدة في ترقية قاعدة كود Next.js عند تحديث API أو إيقاف استخدامه.

الاستخدام

في طرفيتك، انتقل (cd) إلى مجلد مشروعك، ثم قم بتشغيل:

Terminal
npx @next/codemod <transform> <path>

استبدل <transform> و <path> بقيم مناسبة.

  • transform - اسم التحويل
  • path - الملفات أو المجلد المراد تحويلها
  • --dry تشغيل تجريبي، لن يتم تعديل أي كود
  • --print طباعة المخرجات المتغيرة للمقارنة

Codemods

15.0

تحويل قيمة runtime في Route Segment Config من experimental-edge إلى edge

app-dir-runtime-config-experimental-edge

ملاحظة: هذا التحويل خاص بـ App Router.

Terminal
npx @next/codemod@latest app-dir-runtime-config-experimental-edge .

يحول هذا التحويل قيمة Route Segment Config runtime من experimental-edge إلى edge.

على سبيل المثال:

export const runtime = 'experimental-edge'

يتحول إلى:

export const runtime = 'edge'

الهجرة إلى Dynamic APIs غير المتزامنة

أصبحت APIs التي اختارت العرض الديناميكي والتي كانت تدعم الوصول المتزامن سابقًا غير متزامنة. يمكنك قراءة المزيد عن هذا التغيير الجذري في دليل الترقية.

next-async-request-api
Terminal
npx @next/codemod@latest next-async-request-api .

سيحول هذا التحويل Dynamic APIs (cookies(), headers() و draftMode() من next/headers) التي أصبحت الآن غير متزامنة ليتم انتظارها بشكل صحيح أو تغليفها بـ React.use() إذا كان ذلك مناسبًا. عندما لا يكون الهجرة التلقائية ممكنة، سيضيف التحويل إما تحويل نوع (إذا كان ملف TypeScript) أو تعليق لإعلام المستخدم أنه يحتاج إلى مراجعة وتحديث يدوي.

على سبيل المثال:

import { cookies, headers } from 'next/headers'
const token = cookies().get('token')

function useToken() {
  const token = cookies().get('token')
  return token
}

export default function Page() {
  const name = cookies().get('name')
}

function getHeader() {
  return headers().get('x-foo')
}

يتحول إلى:

import { use } from 'react'
import {
  cookies,
  headers,
  type UnsafeUnwrappedCookies,
  type UnsafeUnwrappedHeaders,
} from 'next/headers'
const token = (cookies() as unknown as UnsafeUnwrappedCookies).get('token')

function useToken() {
  const token = use(cookies()).get('token')
  return token
}

export default async function Page() {
  const name = (await cookies()).get('name')
}

function getHeader() {
  return (headers() as unknown as UnsafeUnwrappedHeaders).get('x-foo')
}

عند اكتشاف وصول إلى خاصية في params أو searchParams داخل مدخلات الصفحة / المسار (page.js, layout.js, route.js, أو default.js) أو APIs generateMetadata / generateViewport, سيحاول التحويل تحويل موقع الاستدعاء من دالة متزامنة إلى غير متزامنة، وانتظار وصول الخاصية. إذا لم يكن من الممكن جعلها غير متزامنة (كما في حالة مكون العميل)، سيستخدم React.use لفك الوعد.

على سبيل المثال:

// page.tsx
export default function Page({
  params,
  searchParams,
}: {
  params: { slug: string }
  searchParams: { [key: string]: string | string[] | undefined }
}) {
  const { value } = searchParams
  if (value === 'foo') {
    // ...
  }
}

export function generateMetadata({ params }: { params: { slug: string } }) {
  const { slug } = params
  return {
    title: `My Page - ${slug}`,
  }
}

يتحول إلى:

// page.tsx
export default async function Page(props: {
  params: Promise<{ slug: string }>
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
  const searchParams = await props.searchParams
  const { value } = searchParams
  if (value === 'foo') {
    // ...
  }
}

export async function generateMetadata(props: {
  params: Promise<{ slug: string }>
}) {
  const params = await props.params
  const { slug } = params
  return {
    title: `My Page - ${slug}`,
  }
}

جيد أن تعرف: عندما يحدد هذا التحويل مكانًا قد يحتاج إلى تدخل يدوي، ولكننا غير قادرين على تحديد الإصلاح الدقيق، سيضيف تعليقًا أو تحويل نوع إلى الكود لإعلام المستخدم أنه يحتاج إلى تحديث يدوي. تبدأ هذه التعليقات بـ @next/codemod، وتبدأ تحويلات النوع بـ UnsafeUnwrapped. سينتج خطأ في البناء حتى يتم إزالة هذه التعليقات بشكل صريح. اقرأ المزيد.

استبدال خصائص geo و ip لـ NextRequest بـ @vercel/functions

next-request-geo-ip
Terminal
npx @next/codemod@latest next-request-geo-ip .

يقوم هذا التحويل بتثبيت @vercel/functions وتحويل خصائص geo و ip لـ NextRequest إلى ميزات @vercel/functions المقابلة.

على سبيل المثال:

import type { NextRequest } from 'next/server'

export function GET(req: NextRequest) {
  const { geo, ip } = req
}

يتحول إلى:

import type { NextRequest } from 'next/server'
import { geolocation, ipAddress } from '@vercel/functions'

export function GET(req: NextRequest) {
  const geo = geolocation(req)
  const ip = ipAddress(req)
}

14.0

هجرة استيرادات ImageResponse

next-og-import
Terminal
npx @next/codemod@latest next-og-import .

يحول هذا التحويل الاستيرادات من next/server إلى next/og لاستخدام Dynamic OG Image Generation.

على سبيل المثال:

import { ImageResponse } from 'next/server'

يتحول إلى:

import { ImageResponse } from 'next/og'

استخدام تصدير viewport

metadata-to-viewport-export
Terminal
npx @next/codemod@latest metadata-to-viewport-export .

يحول هذا التحويل بعض بيانات واجهة العرض (viewport metadata) إلى تصدير viewport.

على سبيل المثال:

export const metadata = {
  title: 'My App',
  themeColor: 'dark',
  viewport: {
    width: 1,
  },
}

يتحول إلى:

export const metadata = {
  title: 'My App',
}

export const viewport = {
  width: 1,
  themeColor: 'dark',
}

13.2

استخدام الخط المدمج

built-in-next-font
Terminal
npx @next/codemod@latest built-in-next-font .

يقوم هذا التحويل بإلغاء تثبيت حزمة @next/font وتحويل استيرادات @next/font إلى next/font المدمج.

على سبيل المثال:

import { Inter } from '@next/font/google'

يتحول إلى:

import { Inter } from 'next/font/google'

13.0

إعادة تسمية استيرادات Next Image

next-image-to-legacy-image
Terminal
npx @next/codemod@latest next-image-to-legacy-image .

يعيد تسمية استيرادات next/image بأمان في تطبيقات Next.js 10 أو 11 أو 12 الحالية إلى next/legacy/image في Next.js 13. كما يعيد تسمية next/future/image إلى next/image.

على سبيل المثال:

pages/index.js
import Image1 from 'next/image'
import Image2 from 'next/future/image'

export default function Home() {
  return (
    <div>
      <Image1 src="/test.jpg" width="200" height="300" />
      <Image2 src="/test.png" width="500" height="400" />
    </div>
  )
}

يتحول إلى:

pages/index.js
// 'next/image' تصبح 'next/legacy/image'
import Image1 from 'next/legacy/image'
// 'next/future/image' تصبح 'next/image'
import Image2 from 'next/image'

export default function Home() {
  return (
    <div>
      <Image1 src="/test.jpg" width="200" height="300" />
      <Image2 src="/test.png" width="500" height="400" />
    </div>
  )
}

الهجرة إلى مكون الصورة الجديد

next-image-experimental
Terminal
npx @next/codemod@latest next-image-experimental .

يهاجر بشكل محفوف بالمخاطر من next/legacy/image إلى next/image الجديد عن طريق إضافة أنماط مضمنة وإزالة الخصائص غير المستخدمة.

  • يزيل خاصية layout ويضيف style.
  • يزيل خاصية objectFit ويضيف style.
  • يزيل خاصية objectPosition ويضيف style.
  • يزيل خاصية lazyBoundary.
  • يزيل خاصية lazyRoot.
Terminal
npx @next/codemod@latest new-link .

قم بإزالة وسم <a> داخل مكونات Link، أو أضف خاصية legacyBehavior إلى Links التي لا يمكن إصلاحها تلقائيًا.

على سبيل المثال:

<Link href="/about">
  <a>About</a>
</Link>
// يتحول إلى
<Link href="/about">
  About
</Link>

<Link href="/about">
  <a onClick={() => console.log('clicked')}>About</a>
</Link>
// يتحول إلى
<Link href="/about" onClick={() => console.log('clicked')}>
  About
</Link>

في الحالات التي لا يمكن فيها تطبيق الإصلاح التلقائي، تتم إضافة خاصية legacyBehavior. هذا يسمح لتطبيقك بالاستمرار في العمل باستخدام السلوك القديم لهذا الرابط المحدد.

const Component = () => <a>About</a>

<Link href="/about">
  <Component />
</Link>
// يصبح
<Link href="/about" legacyBehavior>
  <Component />
</Link>

11

الهجرة من CRA

cra-to-next
Terminal
npx @next/codemod cra-to-next

يهاجر مشروع Create React App إلى Next.js؛ بإنشاء Pages Router والإعدادات اللازمة لمطابقة السلوك. يتم استخدام عرض جانب العميل فقط في البداية لمنع كسر التوافق بسبب استخدام window أثناء SSR ويمكن تمكينه بسلاسة للسماح بتبني تدريجي لميزات Next.js المحددة.

يرجى مشاركة أي ملاحظات متعلقة بهذا التحويل في هذه المناقشة.

10

إضافة استيرادات React

add-missing-react-import
Terminal
npx @next/codemod add-missing-react-import

يحول الملفات التي لا تستورد React لتشمل الاستيراد من أجل عمل تحويل JSX الجديد لـ React.

على سبيل المثال:

my-component.js
export default class Home extends React.Component {
  render() {
    return <div>Hello World</div>
  }
}

يتحول إلى:

my-component.js
import React from 'react'
export default class Home extends React.Component {
  render() {
    return <div>Hello World</div>
  }
}

9

تحويل المكونات المجهولة إلى مكونات مسماة

name-default-component
Terminal
npx @next/codemod name-default-component

الإصدارات 9 وما فوق.

يحول المكونات المجهولة إلى مكونات مسماة للتأكد من عملها مع Fast Refresh.

على سبيل المثال:

my-component.js
export default function () {
  return <div>Hello World</div>
}

يتحول إلى:

my-component.js
export default function MyComponent() {
  return <div>Hello World</div>
}

سيكون للمكون اسم بحالة الجمل (camel-case) بناءً على اسم الملف، ويعمل أيضًا مع دوال السهم.

8

تحويل HOC AMP إلى تكوين الصفحة

withamp-to-config
Terminal
npx @next/codemod withamp-to-config

يحول HOC withAmp إلى تكوين صفحة Next.js 9.

على سبيل المثال:

// قبل
import { withAmp } from 'next/amp'

function Home() {
  return <h1>My AMP Page</h1>
}

export default withAmp(Home)
// بعد
export default function Home() {
  return <h1>My AMP Page</h1>
}

export const config = {
  amp: true,
}

6

استخدام withRouter

url-to-withrouter
Terminal
npx @next/codemod url-to-withrouter

يحول خاصية url التي تم حقنها تلقائيًا والمهملة في الصفحات الرئيسية إلى استخدام withRouter وخاصية router التي تحقنها. اقرأ المزيد هنا: https://nextjs.org/docs/messages/url-deprecated

على سبيل المثال:

من
import React from 'react'
export default class extends React.Component {
  render() {
    const { pathname } = this.props.url
    return <div>Current pathname: {pathname}</div>
  }
}
إلى
import React from 'react'
import { withRouter } from 'next/router'
export default withRouter(
  class extends React.Component {
    render() {
      const { pathname } = this.props.router
      return <div>Current pathname: {pathname}</div>
    }
  }
)

هذه حالة واحدة. جميع الحالات التي يتم تحويلها (واختبارها) يمكن العثور عليها في دليل __testfixtures__.