Как обновиться до версии 9

Для обновления до версии 9 выполните следующую команду:

Терминал
npm i next@9
Терминал
yarn add next@9
Терминал
pnpm up next@9
Терминал
bun add next@9

Полезно знать: Если вы используете TypeScript, убедитесь, что также обновили @types/react и @types/react-dom до соответствующих версий.

Проверьте ваш кастомный файл App (pages/_app.js)

Если вы ранее копировали пример Кастомного <App>, вы можете удалить свой getInitialProps.

Удаление getInitialProps из pages/_app.js (где это возможно) важно для использования новых возможностей Next.js!

Следующий getInitialProps ничего не делает и может быть удалён:

class MyApp extends App {
  // Удалите меня, я ничего не делаю!
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {}

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }

    return { pageProps }
  }

  render() {
    // ... и т.д.
  }
}

Критические изменения

@zeit/next-typescript больше не нужен

Next.js теперь игнорирует использование @zeit/next-typescript и предупредит вас о необходимости его удаления. Пожалуйста, удалите этот плагин из вашего next.config.js.

Удалите ссылки на @zeit/next-typescript/babel из вашего кастомного .babelrc (если есть).

Использование fork-ts-checker-webpack-plugin также должно быть удалено из вашего next.config.js.

Определения TypeScript теперь публикуются вместе с пакетом next, поэтому вам нужно удалить @types/next, так как они могут конфликтовать.

Типы изменились следующим образом:

Этот список был создан сообществом, чтобы помочь вам с обновлением. Если вы найдёте другие различия, пожалуйста, отправьте pull-request с дополнениями к этому списку, чтобы помочь другим пользователям.

Было:

import { NextContext } from 'next'
import { NextAppContext, DefaultAppIProps } from 'next/app'
import { NextDocumentContext, DefaultDocumentIProps } from 'next/document'

Стало:

import { NextPageContext } from 'next'
import { AppContext, AppInitialProps } from 'next/app'
import { DocumentContext, DocumentInitialProps } from 'next/document'

Ключ config теперь экспортируется на уровне страницы

Вы больше не можете экспортировать кастомную переменную с именем config из страницы (например, export { config } / export const config ...). Эта экспортируемая переменная теперь используется для указания конфигурации Next.js на уровне страницы, такой как Opt-in AMP и функции API Routes.

Вы должны переименовать экспорт config, не предназначенный для Next.js, во что-то другое.

next/dynamic больше не рендерит "loading..." по умолчанию во время загрузки

Динамические компоненты по умолчанию не будут рендерить ничего во время загрузки. Вы всё ещё можете настроить это поведение, установив свойство loading:

import dynamic from 'next/dynamic'

const DynamicComponentWithCustomLoading = dynamic(
  () => import('../components/hello2'),
  {
    loading: () => <p>Загрузка</p>,
  }
)

withAmp удалён в пользу экспортируемого объекта конфигурации

Next.js теперь имеет концепцию конфигурации на уровне страницы, поэтому компонент высшего порядка withAmp был удалён для единообразия.

Это изменение можно автоматически применить, выполнив следующие команды в корне вашего проекта Next.js:

Терминал
curl -L https://github.com/vercel/next-codemod/archive/master.tar.gz | tar -xz --strip=2 next-codemod-master/transforms/withamp-to-config.js npx jscodeshift -t ./withamp-to-config.js pages/**/*.js

Чтобы выполнить это изменение вручную или посмотреть, что сгенерирует codemod, см. ниже:

До

import { withAmp } from 'next/amp'

function Home() {
  return <h1>Моя AMP страница</h1>
}

export default withAmp(Home)
// или
export default withAmp(Home, { hybrid: true })

После

export default function Home() {
  return <h1>Моя AMP страница</h1>
}

export const config = {
  amp: true,
  // или
  amp: 'hybrid',
}

next export больше не экспортирует страницы как index.html

Раньше экспорт pages/about.js приводил к созданию out/about/index.html. Теперь поведение изменилось, и создаётся out/about.html.

Вы можете вернуть предыдущее поведение, создав next.config.js со следующим содержимым:

next.config.js
module.exports = {
  trailingSlash: true,
}

pages/api/ обрабатывается иначе

Страницы в pages/api/ теперь считаются API Routes. Страницы в этой директории больше не будут содержать клиентский бандл.

Устаревшие возможности

next/dynamic устарел для загрузки нескольких модулей одновременно

Возможность загружать несколько модулей одновременно в next/dynamic устарела, чтобы быть ближе к реализации React (React.lazy и Suspense).

Обновление кода, который полагается на это поведение, относительно простое! Мы предоставили пример до/после, чтобы помочь вам мигрировать ваше приложение:

До

import dynamic from 'next/dynamic'

const HelloBundle = dynamic({
  modules: () => {
    const components = {
      Hello1: () => import('../components/hello1').then((m) => m.default),
      Hello2: () => import('../components/hello2').then((m) => m.default),
    }

    return components
  },
  render: (props, { Hello1, Hello2 }) => (
    <div>
      <h1>{props.title}</h1>
      <Hello1 />
      <Hello2 />
    </div>
  ),
})

function DynamicBundle() {
  return <HelloBundle title="Dynamic Bundle" />
}

export default DynamicBundle

После

import dynamic from 'next/dynamic'

const Hello1 = dynamic(() => import('../components/hello1'))
const Hello2 = dynamic(() => import('../components/hello2'))

function HelloBundle({ title }) {
  return (
    <div>
      <h1>{title}</h1>
      <Hello1 />
      <Hello2 />
    </div>
  )
}

function DynamicBundle() {
  return <HelloBundle title="Dynamic Bundle" />
}

export default DynamicBundle