BackНазад к блогу

Next.js 14

В Next.js 14 включены улучшения производительности, стабилизация Server Actions, новый курс по изучению App Router и многое другое.

Как мы объявили на Next.js Conf, Next.js 14 — это наше самое сфокусированное обновление, включающее:

  • Turbopack: 5000 успешных тестов для App & Pages Router
    • На 53% быстрее запуск локального сервера
    • На 94% быстрее обновление кода с Fast Refresh
  • Server Actions (Стабильная версия): Прогрессивно улучшенные мутации
    • Интеграция с кэшированием и ревалидацией
    • Простые вызовы функций или нативная работа с формами
  • Частичный пререндеринг (Превью): Быстрый статический ответ + потоковая передача динамического контента
  • Next.js Learn (Новый курс): Бесплатный курс по App Router, аутентификации, базам данных и многому другому.

Обновитесь сегодня или начните работу с:

Terminal
npx create-next-app@latest

Компилятор Next.js: Ускоренный

Начиная с Next.js 13, мы работали над улучшением производительности локальной разработки в Next.js как для Pages, так и для App Router.

Ранее мы переписывали next dev и другие части Next.js для поддержки этих усилий. С тех пор мы изменили подход, сделав его более инкрементным. Это означает, что наш компилятор на основе Rust скоро достигнет стабильности, так как мы переориентировались на поддержку всех функций Next.js в первую очередь.

5000 интеграционных тестов для next dev теперь проходят с Turbopack, нашим движком на Rust. Эти тесты включают 7 лет исправлений ошибок и их воспроизведений.

При тестировании на vercel.com, крупном приложении Next.js, мы наблюдали:

  • До 53.3% быстрее запуск локального сервера
  • До 94.7% быстрее обновление кода с Fast Refresh

Этот бенчмарк — практический результат улучшений производительности, которые вы можете ожидать в крупном приложении (и с большим графом модулей). Сейчас 90% тестов для next dev проходят успешно, поэтому вы должны видеть более быструю и надежную производительность при использовании next dev --turbo.

Как только мы достигнем 100% успешных тестов, мы переведем Turbopack в стабильную версию в одном из следующих минорных релизов. Мы также продолжим поддерживать использование webpack для пользовательских конфигураций и плагинов экосистемы.

Вы можете следить за процентом успешных тестов на areweturboyet.com.

Формы и мутации

Next.js 9 представил API Routes — способ быстро создавать бэкенд-эндпоинты вместе с фронтенд-кодом.

Например, вы могли создать новый файл в директории api/:

pages/api/submit.ts
import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  const data = req.body;
  const id = await createItem(data);
  res.status(200).json({ id });
}

Затем на клиентской стороне вы могли использовать React и обработчик событий, например onSubmit, чтобы сделать fetch к вашему API Route.

pages/index.tsx
import { FormEvent } from 'react';
 
export default function Page() {
  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
 
    const formData = new FormData(event.currentTarget);
    const response = await fetch('/api/submit', {
      method: 'POST',
      body: formData,
    });
 
    // Обработка ответа при необходимости
    const data = await response.json();
    // ...
  }
 
  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

Теперь с Next.js 14 мы хотим упростить опыт разработчика при создании мутаций данных. Кроме того, мы хотим улучшить пользовательский опыт при медленном сетевом соединении или отправке формы с маломощного устройства.

Server Actions (Стабильная версия)

Что, если вам не нужно вручную создавать API Route? Вместо этого вы могли бы определить функцию, которая выполняется безопасно на сервере, вызываясь напрямую из ваших React-компонентов.

App Router построен на канале React canary, который стабилен для фреймворков для внедрения новых функций. Начиная с v14, Next.js обновился до последней версии React canary, которая включает стабильные Server Actions.

Предыдущий пример из Pages Router можно упростить до одного файла:

app/page.tsx
export default function Page() {
  async function create(formData: FormData) {
    'use server';
    const id = await createItem(formData);
  }
 
  return (
    <form action={create}>
      <input type="text" name="name" />
      <button type="submit">Submit</button>
    </form>
  );
}

Server Actions должны быть знакомы разработчикам, которые ранее использовали сервер-центричные фреймворки. Они построены на веб-основах, таких как формы и FormData Web API.

Хотя использование Server Actions через форму полезно для прогрессивного улучшения, это не является обязательным требованием. Вы также можете вызывать их напрямую как функцию, без формы. При использовании TypeScript это дает вам полную сквозную типобезопасность между клиентом и сервером.

Мутация данных, перерисовка страницы или редирект могут произойти за один сетевой цикл, гарантируя корректное отображение данных на клиенте, даже если вышестоящий провайдер медленный. Кроме того, вы можете комбинировать и повторно использовать различные действия, включая множество разных действий в одном маршруте.

Кэширование, ревалидация, редиректы и многое другое

Server Actions глубоко интегрированы во всю модель App Router. Вы можете:

  • Ревалидировать кэшированные данные с revalidatePath() или revalidateTag()
  • Перенаправлять на разные маршруты через redirect()
  • Устанавливать и читать куки через cookies()
  • Обрабатывать оптимистичные UI-обновления с useOptimistic()
  • Ловить и отображать ошибки с сервера с useFormState()
  • Отображать состояния загрузки на клиенте с useFormStatus()

Узнайте больше о формах и мутациях с Server Actions или о модели безопасности и лучших практиках для Server Components и Server Actions.

Частичный пререндеринг (Превью)

Мы рады поделиться превью частичного пререндеринга — оптимизации компилятора для динамического контента с быстрым начальным статическим ответом — над которым мы работаем для Next.js.

Частичный пререндеринг основан на десятилетиях исследований и разработок в области рендеринга на стороне сервера (SSR), генерации статических сайтов (SSG) и инкрементальной статической ревалидации (ISR).

Мотивация

Мы услышали ваши отзывы. Сейчас существует слишком много сред выполнения, вариантов конфигурации и методов рендеринга, которые нужно учитывать. Вы хотите скорость и надежность статики, но также поддержку полностью динамических, персонализированных ответов.

Отличная производительность глобально и персонализация не должны достигаться за счет сложности.

Нашей задачей было создать лучший опыт разработчика, упростив существующую модель без введения новых API для изучения. Хотя частичное кэширование серверного контента существовало, эти подходы все еще не соответствуют целям опыта разработчика и компоновки, к которым мы стремимся.

Частичный пререндеринг не требует изучения новых API.

Построено на React Suspense

Частичный пререндеринг определяется вашими границами Suspense. Вот как это работает. Рассмотрим следующую страницу интернет-магазина:

app/page.tsx
export default function Page() {
  return (
    <main>
      <header>
        <h1>My Store</h1>
        <Suspense fallback={<CartSkeleton />}>
          <ShoppingCart />
        </Suspense>
      </header>
      <Banner />
      <Suspense fallback={<ProductListSkeleton />}>
        <Recommendations />
      </Suspense>
      <NewProducts />
    </main>
  );
}

При включенном частичном пререндеринге эта страница генерирует статическую оболочку на основе ваших границ <Suspense />. fallback из React Suspense пререндерится.

Затем фолбэки Suspense в оболочке заменяются динамическими компонентами, например, чтение куков для определения корзины или показ баннера на основе пользователя.

При запросе статическая HTML-оболочка сразу же отдается:

<main>
  <header>
    <h1>My Store</h1>
    <div class="cart-skeleton">
      <!-- Hole -->
    </div>
  </header>
  <div class="banner" />
  <div class="product-list-skeleton">
    <!-- Hole -->
  </div>
  <section class="new-products" />
</main>

Поскольку <ShoppingCart /> читает cookies для проверки сессии пользователя, этот компонент затем стримится как часть того же HTTP-запроса, что и статическая оболочка. Дополнительные сетевые циклы не требуются.

app/cart.tsx
import { cookies } from 'next/headers'
 
export default function ShoppingCart() {
  const cookieStore = cookies()
  const session = cookieStore.get('session')
  return ...
}

Для наиболее детализированной статической оболочки может потребоваться добавление дополнительных границ Suspense. Однако, если вы уже используете loading.js сегодня, это неявная граница Suspense, поэтому изменения для генерации статической оболочки не потребуются.

Скоро

Частичный предварительный рендеринг (Partial Prerendering) находится в активной разработке. Мы поделимся дополнительными обновлениями в одном из следующих минорных релизов.

Улучшения метаданных

Прежде чем контент страницы может быть передан потоком с сервера, в браузер необходимо отправить важные метаданные о viewport, цветовой схеме и теме.

Обеспечение отправки этих тегов meta вместе с первоначальным содержимым страницы способствует плавному пользовательскому опыту, предотвращая мерцание страницы из-за изменения цвета темы или смещения макета из-за изменений viewport.

В Next.js 14 мы разделили блокирующие и неблокирующие метаданные. Только небольшое подмножество опций метаданных является блокирующим, и мы хотим гарантировать, что неблокирующие метаданные не помешают частично предварительно отрендеренной странице отдавать статическую оболочку.

Следующие опции метаданных теперь устарели и будут удалены из metadata в следующей мажорной версии:

  • viewport: Устанавливает начальный масштаб и другие свойства viewport
  • colorScheme: Устанавливает поддерживаемые режимы (светлый/темный) для viewport
  • themeColor: Устанавливает цвет, которым должно отображаться окружение viewport

Начиная с Next.js 14, появились новые опции viewport и generateViewport для замены этих устаревших параметров. Все остальные опции metadata остаются без изменений.

Вы можете начать использовать эти новые API уже сегодня. Существующие опции metadata продолжат работать.

Курс Next.js Learn

Сегодня мы выпускаем совершенно новый бесплатный курс на Next.js Learn. Этот курс обучает:

  • App Router в Next.js
  • Стилизацию и Tailwind CSS
  • Оптимизацию шрифтов и изображений
  • Создание макетов и страниц
  • Навигацию между страницами
  • Настройку базы данных Postgres
  • Получение данных с серверными компонентами
  • Статический и динамический рендеринг
  • Потоковую передачу (Streaming)
  • Частичный предварительный рендеринг (опционально)
  • Добавление поиска и пагинации
  • Мутацию данных
  • Обработку ошибок
  • Улучшение доступности
  • Добавление аутентификации
  • Добавление метаданных

Next.js Learn обучил миллионы разработчиков основам фреймворка, и мы с нетерпением ждем ваших отзывов о нашем новом дополнении. Перейдите на nextjs.org/learn, чтобы пройти курс.

Другие изменения

  • [Критическое] Минимальная версия Node.js теперь 18.17
  • [Критическое] Удалена WASM-цель для сборки next-swc (PR)
  • [Критическое] Прекращена поддержка @next/font в пользу next/font (Codemod)
  • [Критическое] Изменен импорт ImageResponse с next/server на next/og (Codemod)
  • [Критическое] Команда next export удалена в пользу конфигурации output: 'export' (Документация)
  • [Устарело] onLoadingComplete для next/image устарел в пользу onLoad
  • [Устарело] domains для next/image устарел в пользу remotePatterns
  • [Функция] Можно включить более подробное логирование кэширования fetch (Документация)
  • [Улучшение] Размер функций уменьшен на 80% для базового приложения create-next-app
  • [Улучшение] Улучшено управление памятью при использовании edge-рантайма в разработке

Участники

Next.js — результат совместной работы более 2900 разработчиков, отраслевых партнеров, таких как Google и Meta, и нашей основной команды в Vercel. Присоединяйтесь к сообществу на GitHub Discussions, Reddit и Discord.

Этот релиз стал возможен благодаря:

А также вкладу: @05lazy, @0xadada, @2-NOW, @aarnadlr, @aaronbrown-vercel, @aaronjy, @abayomi185, @abe1272001, @abhiyandhakal, @abstractvector, @acdlite, @adamjmcgrath, @AdamKatzDev, @adamrhunter, @ademilter, @adictonator, @adilansari, @adtc, @afonsojramos, @agadzik, @agrattan0820, @akd-io, @AkifumiSato, @akshaynox, @alainkaiser, @alantoa, @albertothedev, @AldeonMoriak, @aleksa-codes, @alexanderbluhm, @alexkirsz, @alfred-mountfield, @alpha-xek, @andarist, @Andarist, @andrii-bodnar, @andykenward, @angel1254mc, @anonrig, @anthonyshew, @AntoineBourin, @anujssstw, @apeltop, @aralroca, @aretrace, @artdevgame, @artechventure, @arturbien, @Aryan9592, @AviAvinav, @aziyatali, @BaffinLee, @Banbarashik, @bencmbrook, @benjie, @bennettdams, @bertho-zero, @bigyanse, @Bitbbot, @blue-devil1134, @bot08, @bottxiang, @Bowens20832, @bre30kra69cs, @BrennanColberg, @brkalow, @BrodaNoel, @Brooooooklyn, @brunoeduardodev, @brvnonascimento, @carlos-menezes, @cassidoo, @cattmote, @cesarkohl, @chanceaclark, @charkour, @charlesbdudley, @chibicode, @chrisipanaque, @ChristianIvicevic, @chriswdmr, @chunsch, @ciruz, @cjmling, @clive-h-townsend, @colinhacks, @colinking, @coreyleelarson, @Cow258, @cprussin, @craigwheeler, @cramforce, @cravend, @cristobaldominguez95, @ctjlewis, @cvolant, @cxa, @danger-ahead, @daniel-web-developer, @danmindru, @dante-robinson, @darshanjain-entrepreneur, @darshkpatel, @davecarlson, @David0z, @davidnx, @dciug, @delbaoliveira, @denchance, @DerTimonius, @devagrawal09, @DevEsteves, @devjiwonchoi, @devknoll, @DevLab2425, @devvspaces, @didemkkaslan, @dijonmusters, @dirheimerb, @djreillo, @dlehmhus, @doinki, @dpnolte, @Drblessing, @dtinth, @ducanhgh, @DuCanhGH, @ductnn, @duncanogle, @dunklesToast, @DustinsCode, @dvakatsiienko, @dvoytenko, @dylanjha, @ecklf, @EndangeredMassa, @eps1lon, @ericfennis, @escwxyz, @Ethan-Arrowood, @ethanmick, @ethomson, @fantaasm, @feikerwu, @ferdingler, @FernandVEYRIER, @feugy, @fgiuliani, @fomichroman, @Fonger, @ForsakenHarmony, @franktronics, @FSaldanha, @fsansalvadore, @furkanmavili, @g12i, @gabschne, @gaojude, @gdborton, @gergelyke, @gfgabrielfranca, @gidgudgod, @Gladowar, @Gnadhi, @gnoff, @goguda, @greatSumini, @gruz0, @Guilleo03, @gustavostz, @hanneslund, @HarshaVardhanReddyDuvvuru, @haschikeks, @Heidar-An, @heyitsuzair, @hiddenest, @hiro0218, @hotters, @hsrvms, @hu0p, @hughlilly, @HurSungYun, @hustLer2k, @iamarpitpatidar, @ianldgs, @ianmacartney, @iaurg, @ibash, @ibrahemid, @idoob, @iiegor, @ikryvorotenko, @imranbarbhuiya, @ingovals, @inokawa, @insik-han, @isaackatayev, @ishaqibrahimbot, @ismaelrumzan, @itsmingjie, @ivanhofer, @IvanKiral, @jacobsfletch, @jakemstar, @jamespearson, @JanCizmar, @janicklas-ralph, @jankaifer, @JanKaifer, @jantimon, @jaredpalmer, @javivelasco, @jayair, @jaykch, @Jeffrey-Zutt, @jenewland1999, @jeremydouglas, @JesseKoldewijn, @jessewarren-aa, @jimcresswell, @jiwooIncludeJeong, @jocarrd, @joefreeman, @JohnAdib, @JohnAlbin, @JohnDaly, @johnnyomair, @johnta0, @joliss, @jomeswang, @joostdecock, @Josehower, @josephcsoti, @josh, @joshuabaker, @JoshuaKGoldberg, @joshuaslate, @joulev, @jsteele-stripe, @JTaylor0196, @JuanM04, @jueungrace, @juliusmarminge, @Juneezee, @Just-Moh-it, @juzhiyuan, @jyunhanlin, @kaguya3222, @karlhorky, @kevinmitch14, @keyz, @kijikunnn, @kikobeats, @Kikobeats, @kleintorres, @koba04, @koenpunt, @koltong, @konomae, @kosai106, @krmeda, @kvnang, @kwonoj, @ky1ejs, @kylemcd, @labyrinthitis, @lachlanjc, @lacymorrow, @laityned, @Lantianyou, @leerob, @leodr, @leoortizz, @li-jia-nan, @loettz, @lorenzobloedow, @lubakravche, @lucasassisrosa, @lucasconstantino, @lucgagan, @LukeSchlangen, @LuudJanssen, @lycuid, @M3kH, @m7yue, @manovotny, @maranomynet, @marcus-rise, @MarDi66, @MarkAtOmniux, @martin-wahlberg, @masnormen, @matepapp, @matthew-heath, @mattpr, @maxleiter, @MaxLeiter, @maxproske, @meenie, @meesvandongen, @mhmdrioaf, @michaeloliverx, @mike-plummer, @MiLk, @milovangudelj, @Mingyu-Song, @mirismaili, @mkcy3, @mknichel, @mltsy, @mmaaaaz, @mnajdova, @moetazaneta, @mohanraj-r, @molebox, @morganfeeney, @motopods, @mPaella, @mrkldshv, @mrxbox98, @nabsul, @nathanhammond, @nbouvrette, @nekochantaiwan, @nfinished, @Nick-Mazuk, @nickmccurdy, @niedziolkamichal, @niko20, @nikolovlazar, @nivak-monarch, @nk980113, @nnnnoel, @nocell, @notrab, @nroland013, @nuta, @nutlope, @obusk, @okcoker, @oliviertassinari, @omarhoumz, @opnay, @orionmiz, @ossan-engineer, @patrick91, @pauek, @peraltafederico, @Phiction, @pn-code, @pyjun01, @pythagoras-yamamoto, @qrohlf, @raisedadead, @reconbot, @reshmi-sriram, @reyrodrigez, @ricardofiorani, @rightones, @riqwan, @rishabhpoddar, @rjsdnql123, @rodrigofeijao, @runjuu, @Ryan-Dia, @ryo-manba, @s0h311, @sagarpreet-xflowpay, @sairajchouhan, @samdenty, @samsisle, @sanjaiyan-dev, @saseungmin, @SCG82, @schehata, @Schniz, @sepiropht, @serkanbektas, @sferadev, @ShaunFerris, @shivanshubisht, @shozibabbas, @silvioprog, @simonswiss, @simPod, @sivtu, @SleeplessOne1917, @smaeda-ks, @sonam-serchan, @SonMooSans, @soonoo, @sophiebits, @souporserious, @sp00ls, @sqve, @sreetamdas, @stafyniaksacha, @starunaway, @steebchen, @stefanprobst, @steppefox, @steven-tey, @suhaotian, @sukkaw, @SukkaW, @superbahbi, @SuttonJack, @svarunid, @swaminator, @swarnava, @syedtaqi95, @taep96, @taylorbryant, @teobler, @Terro216, @theevilhead, @thepatrick00, @therealrinku, @thomasballinger, @thorwebdev, @tibi1220, @tim-hanssen, @timeyoutakeit, @tka5, @tknickman, @tomryanx, @trigaten, @tristndev, @tunamagur0, @tvthatsme, @tyhopp, @tyler-lutz, @UnknownMonk, @v1k1, @valentincostam, @valentinh, @valentinpolitov, @vamcs, @vasucp1207, @vicsantizo, @vinaykulk621, @vincenthongzy, @visshaljagtap, @vladikoff, @wherehows, @WhoAmIRUS, @WilderDev, @Willem-Jaap, @williamli, @wiredacorn, @wiscaksono, @wojtekolek, @ws-jm, @wxh06, @wyattfry, @wyattjoh, @xiaolou86, @y-tsubuku, @yagogmaisp, @yangshun, @yasath, @Yash-Singh1, @yigithanyucedag, @ykzts, @Yovach, @yutsuten, @yyuemii, @zek, @zekicaneksi, @zignis, и @zlrlyy