Codemods

Les codemods sont des transformations qui s'exécutent de manière programmatique sur votre codebase. Cela permet d'appliquer un grand nombre de modifications sans avoir à parcourir manuellement chaque fichier.

Next.js fournit des transformations Codemod pour vous aider à mettre à jour votre codebase Next.js lorsqu'une API est mise à jour ou dépréciée.

Utilisation

Dans votre terminal, naviguez (cd) dans le dossier de votre projet, puis exécutez :

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

En remplaçant <transform> et <path> par les valeurs appropriées.

  • transform - nom de la transformation
  • path - fichiers ou répertoire à transformer
  • --dry Effectue une simulation, aucun code ne sera modifié
  • --print Affiche les modifications pour comparaison

Codemods

15.0

Transformer la valeur runtime de la configuration des segments de route App Router de experimental-edge à edge

app-dir-runtime-config-experimental-edge

Remarque : Ce codemod est spécifique à App Router.

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

Ce codemod transforme la valeur experimental-edge de la configuration des segments de route runtime en edge.

Par exemple :

export const runtime = 'experimental-edge'

Se transforme en :

export const runtime = 'edge'

Migrer vers les APIs dynamiques asynchrones

Les APIs qui ont opté pour le rendu dynamique et qui prenaient en charge un accès synchrone sont désormais asynchrones. Vous pouvez en savoir plus sur ce changement majeur dans le guide de mise à niveau.

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

Ce codemod transformera les APIs dynamiques (cookies(), headers() et draftMode() de next/headers) qui sont désormais asynchrones pour qu'elles soient correctement attendues ou enveloppées avec React.use() si applicable. Lorsqu'une migration automatique n'est pas possible, le codemod ajoutera soit un typecast (si c'est un fichier TypeScript) soit un commentaire pour informer l'utilisateur qu'une revue et une mise à jour manuelles sont nécessaires.

Par exemple :

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')
}

Se transforme en :

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')
}

Lorsque nous détectons un accès aux propriétés des props params ou searchParams dans les entrées de page / route (page.js, layout.js, route.js, ou default.js) ou les APIs generateMetadata / generateViewport, il tentera de transformer le site d'appel d'une fonction synchrone en une fonction asynchrone, et d'attendre l'accès à la propriété. Si cela ne peut pas être rendu asynchrone (comme avec un composant client), il utilisera React.use pour déballer la promesse.

Par exemple :

// 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}`,
  }
}

Se transforme en :

// 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}`,
  }
}

Bon à savoir : Lorsque ce codemod identifie un endroit qui pourrait nécessiter une intervention manuelle, mais que nous ne sommes pas en mesure de déterminer la correction exacte, il ajoutera un commentaire ou un typecast au code pour informer l'utilisateur qu'une mise à jour manuelle est nécessaire. Ces commentaires sont préfixés par @next/codemod, et les typecasts sont préfixés par UnsafeUnwrapped. Votre build échouera jusqu'à ce que ces commentaires soient explicitement supprimés. En savoir plus.

Remplacer les propriétés geo et ip de NextRequest par @vercel/functions

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

Ce codemod installe @vercel/functions et transforme les propriétés geo et ip de NextRequest avec les fonctionnalités correspondantes de @vercel/functions.

Par exemple :

import type { NextRequest } from 'next/server'

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

Se transforme en :

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

Migrer les imports de ImageResponse

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

Ce codemod déplace les imports de next/server vers next/og pour l'utilisation de la Génération dynamique d'images OG.

Par exemple :

import { ImageResponse } from 'next/server'

Se transforme en :

import { ImageResponse } from 'next/og'

Utiliser l'export viewport

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

Ce codemod migre certaines métadonnées viewport vers l'export viewport.

Par exemple :

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

Se transforme en :

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

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

13.2

Utiliser la police intégrée

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

Ce codemod désinstalle le package @next/font et transforme les imports de @next/font en next/font intégré.

Par exemple :

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

Se transforme en :

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

13.0

Renommer les imports Next Image

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

Renomme en toute sécurité les imports next/image dans les applications Next.js 10, 11 ou 12 existantes en next/legacy/image dans Next.js 13. Renomme également next/future/image en next/image.

Par exemple :

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>
  )
}

Se transforme en :

pages/index.js
// 'next/image' devient 'next/legacy/image'
import Image1 from 'next/legacy/image'
// 'next/future/image' devient '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>
  )
}

Migrer vers le nouveau composant Image

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

Migre de manière risquée de next/legacy/image vers le nouveau next/image en ajoutant des styles en ligne et en supprimant les props inutilisés.

  • Supprime la prop layout et ajoute style.
  • Supprime la prop objectFit et ajoute style.
  • Supprime la prop objectPosition et ajoute style.
  • Supprime la prop lazyBoundary.
  • Supprime la prop lazyRoot.
Terminal
npx @next/codemod@latest new-link .

Supprime les balises <a> à l'intérieur des composants Link, ou ajoute une prop legacyBehavior aux Links qui ne peuvent pas être corrigés automatiquement.

Par exemple :

<Link href="/about">
  <a>About</a>
</Link>
// se transforme en
<Link href="/about">
  About
</Link>

<Link href="/about">
  <a onClick={() => console.log('clicked')}>About</a>
</Link>
// se transforme en
<Link href="/about" onClick={() => console.log('clicked')}>
  About
</Link>

Dans les cas où la correction automatique ne peut pas être appliquée, la prop legacyBehavior est ajoutée. Cela permet à votre application de continuer à fonctionner en utilisant l'ancien comportement pour ce lien particulier.

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

<Link href="/about">
  <Component />
</Link>
// devient
<Link href="/about" legacyBehavior>
  <Component />
</Link>

11

Migrer depuis CRA

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

Migre un projet Create React App vers Next.js ; crée un Pages Router et la configuration nécessaire pour correspondre au comportement. Le rendu côté client uniquement est utilisé initialement pour éviter de casser la compatibilité due à l'utilisation de window pendant le SSR et peut être activé de manière transparente pour permettre l'adoption progressive des fonctionnalités spécifiques à Next.js.

Merci de partager tout retour lié à cette transformation dans cette discussion.

10

Ajouter les imports React

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

Transforme les fichiers qui n'importent pas React pour inclure l'import afin que la nouvelle transformation JSX React fonctionne.

Par exemple :

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

Se transforme en :

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

9

Transformer les composants anonymes en composants nommés

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

Versions 9 et supérieures.

Transforme les composants anonymes en composants nommés pour s'assurer qu'ils fonctionnent avec Fast Refresh.

Par exemple :

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

Se transforme en :

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

Le composant aura un nom en camelCase basé sur le nom du fichier, et cela fonctionne également avec les fonctions fléchées.

8

Transformer le HOC AMP en configuration de page

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

Transforme le HOC withAmp en configuration de page Next.js 9.

Par exemple :

// Avant
import { withAmp } from 'next/amp'

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

export default withAmp(Home)
// Après
export default function Home() {
  return <h1>My AMP Page</h1>
}

export const config = {
  amp: true,
}

6

Utiliser withRouter

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

Transforme la propriété url automatiquement injectée et dépréciée sur les pages de niveau supérieur en utilisant withRouter et la propriété router qu'elle injecte. En savoir plus ici : https://nextjs.org/docs/messages/url-deprecated

Par exemple :

De
import React from 'react'
export default class extends React.Component {
  render() {
    const { pathname } = this.props.url
    return <div>Current pathname: {pathname}</div>
  }
}
Vers
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>
    }
  }
)

Ceci est un cas. Tous les cas qui sont transformés (et testés) peuvent être trouvés dans le répertoire __testfixtures__.