Обновление до версии 9

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

Terminal
npm i next@9
Terminal
yarn add next@9
Terminal
pnpm up next@9
Terminal
bun add next@9

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

Продуктовое развертывание на Vercel

Если вы ранее настраивали routes в файле vercel.json для динамических маршрутов, эти правила можно удалить при использовании новой функции динамической маршрутизации в Next.js 9.

Динамические маршруты Next.js 9 автоматически настраиваются на Vercel и не требуют никакой кастомизации в vercel.json.

Подробнее о динамической маршрутизации можно прочитать здесь.

Проверьте ваш кастомный файл приложения (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:

Terminal
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