За последние полгода, после представления Next js 13, основные усилия были сосредоточены на создании основ для будущего «маршрутизатора приложений» Next.js.

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

4 мая 2023 года команда Next js официально запустила версию Next js 13.4, что ознаменовало начало практической реализации долгожданного маршрутизатора приложений. Это означает, что теперь вы можете приступить к включению App Router в свои производственные рабочие процессы.

Следующий маршрутизатор приложений js

В 2016 году был представлен Next js с целью упростить процесс серверного рендеринга приложений React.

Главной целью было проложить путь к более яркому, персонализированному и взаимосвязанному веб-опыту в глобальном масштабе.

Достигнув своего шестилетнего юбилея, Next js с гордостью отстаивает свои оригинальные принципы дизайна.

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

Целенаправленные усилия были вложены в разработку предстоящей версии Next js, и с появлением версии 13.4 это следующее поколение достигло стабильного состояния и готово к широкому внедрению.

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

Использовать файловую систему в качестве API (нулевая установка)

Включение маршрутизации на основе файловой системы было фундаментальным и неотъемлемым аспектом Next js с момента его создания.

// Pages Router
// pages/about.js

import React from 'react';
export default () => <h1>About us</h1>;

На ранних этапах для маршрутизации в Next js не требовалась дополнительная настройка. Было бы достаточно простого действия по удалению файла в каталоге pages/, а маршрутизатор Next js легко справился бы с остальным.

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

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

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

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

// New: App Router ✨
// app/layout.js
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

// app/page.js
export default function Page() {
  return <h1>Hello, Next.js!</h1>;
}

Скрытая сущность превосходит по значимости видимый фасад. Этот новый маршрутизатор, который можно постепенно охватить через каталог app/, демонстрирует совершенно особую структуру, основанную на компонентах React Server и Suspense.

Благодаря этой основе они успешно устранили специфичные для Next js API, которые изначально были разработаны для улучшения основных элементов React. В результате вам больше не нужно использовать настраиваемый файл _app для персонализации глобального общего макета.

Скрытая сущность превосходит по значимости видимый фасад. Этот новый маршрутизатор, который можно постепенно охватить через каталог app/, демонстрирует совершенно особую структуру, основанную на компонентах React Server и Suspense.

Благодаря этой основе они успешно устранили специфичные для Next js API, которые изначально были разработаны для улучшения основных элементов React. В результате вам больше не нужно использовать настраиваемый файл _app для персонализации глобального общего макета.

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

// New: App Router ✨
// app/layout.js
//
// The root layout is shared for the entire application
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

// app/dashboard/layout.js
//
// Layouts can be nested and composed
export default function DashboardLayout({ children }) {
  return (
    <section>
      <h1>Dashboard</h1>
      {children}
    </section>
  );
}

В контексте маршрутизатора страниц настройка начальной полезной нагрузки с сервера была достигнута за счет использования файла _document.

// Pages Router
// pages/_document.js

// This file allows you to customize the <html> and <body> tags
// for the server request, but adds framework-specific features
// rather than writing HTML elements.
import { Html, Head, Main, NextScript } from 'next/document';

export default function Document() {
  return (
    <Html>
      <Head />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

Благодаря App Router устранена необходимость импорта компонентов ‹Html›, ‹Head› и ‹Body› из Next.js. Вместо этого вы можете просто положиться на React для этих целей.

// New: App Router ✨
// app/layout.js
//
// The root layout is shared for the entire application
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Появление нового маршрутизатора файловой системы стало подходящим моментом для удовлетворения многочисленных других запросов на функции, связанных с их системой маршрутизации. Например:

В прошлом возможность импортировать глобальные таблицы стилей исключительно из внешних пакетов npm, таких как библиотеки компонентов, ограничивалась файлом _app.js, что приводило к неоптимальному опыту разработчиков.

Однако с внедрением App Router у вас теперь есть свобода импортировать и совместно размещать любой файл CSS в любом компоненте, что повышает гибкость и удобство.

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

Однако с внедрением App Router мы переработали архитектуру для полной интеграции с React Suspense.

Эта интеграция позволяет нам выборочно гидратировать определенные части страницы, позволяя другим компонентам в пользовательском интерфейсе оставаться интерактивными без какой-либо блокировки.

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

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

Бесшовная интеграция этих частей — это то, что действительно расширяет возможности Next.js и расширяет его общие возможности.

Только JavaScript. Все это функция

Разработчики Next.js и React стремятся писать код на JavaScript и TypeScript, гармонично комбинируя и компонуя компоненты приложения.

Это желание проистекает из намерения использовать сильные стороны этих языков и сред для создания надежных и целостных приложений.

import React from 'react';
import Head from 'next/head';

export default () => (
  <div>
    <Head>
      <meta name="viewport" content="width=device-width, initial-scale=1" />
    </Head>
    <h1>Hi. I'm mobile-ready!</h1>
  </div>
);

Этот компонент служит контейнером для многократно используемой логики, которую можно легко интегрировать и компоновать в вашем приложении.

В сочетании с маршрутизацией файловой системы это обеспечивает удобный подход для инициирования разработки приложений React, которые органично сочетают в себе знакомые навыки написания JavaScript и HTML.

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

import React from 'react';
import 'isomorphic-fetch';

export default class extends React.Component {
  static async getInitialProps() {
    const res = await fetch('https://api.company.com/user/123');
    const data = await res.json();
    return { username: data.profile.username };
  }
}

По мере распространения и усовершенствования фреймворка команда Next.js приступила к изучению новых шаблонов для выборки данных.

Функция getInitialProps играла двойную роль, выполняясь как на стороне сервера, так и на стороне клиента. Этот API расширил возможности компонента React, позволив выполнять промисы и беспрепятственно передавать результаты свойствам компонента.

Хотя getInitialProps остается функциональным и по сей день, команда Next.js, руководствуясь отзывами клиентов, перешла к следующему поколению API для выборки данных.

Эта эволюция привела к появлению методов getServerSideProps и getStaticProps, которые еще больше расширили возможности извлечения данных из фреймворка.

/ Generate a static version of the route
export async function getStaticProps(context) {
  return { props: {} };
}
// Or dynamically server-render the route
export async function getServerSideProps(context) {
  return { props: {} };
}

Эти API-интерфейсы внесли большую ясность в отношении среды выполнения вашего кода, различая клиентскую и серверную стороны. Кроме того, они упростили автоматическую статическую оптимизацию приложений Next.js.

Более того, введение статического экспорта позволило развернуть Next.js на платформах, которые не поддерживают сервер, таких как корзина AWS S3.

Тем не менее, стало очевидно, что этот подход не был строго связан с концепцией «просто JavaScript», и было желание сохранить более тесную приверженность исходным принципам проектирования.

С момента создания Next.js основная команда поддерживает тесное сотрудничество с основной командой React в Meta.

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

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

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

По умолчанию все компоненты рассматриваются как компоненты React Server, что обеспечивает безопасную выборку данных на сервере. Например:

// app/page.js

export default async function Page() {
  const res = await fetch('https://api.example.com/...');
  // The return value is *not* serialized
  // You can use Date, Map, Set, etc.
  const data = res.json();

  return '...';
}

Принцип «выборка данных зависит от разработчика» имеет первостепенное значение и эффективно реализован. У вас есть свобода выбора данных и компоновки любого компонента в соответствии с вашими требованиями.

Эта гибкость распространяется не только на сторонние компоненты, но и на всю экосистему серверных компонентов. Например, такие компоненты, как react-tweet, специально разработанные для интеграции с серверными компонентами, могут полностью выполняться на сервере.

// app/page.js

import { Tweet } from 'react-tweet';

export default async function Page() {
  return <Tweet id="790942692909916160" />;
}

Благодаря интеграции маршрутизатора с React Suspense теперь вы можете беспрепятственно отображать резервный контент во время процесса загрузки и постепенно отображать желаемый контент, что обеспечивает более плавный и привлекательный пользовательский интерфейс.

// app/page.js

import { Suspense } from 'react';
import { PostFeed, Weather } from './components';

export default function Page() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  );
}

Автоматический серверный рендеринг и разделение кода

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

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

При разделении кода на основе маршрутов каждый файл в каталоге pages/ интеллектуально делится на отдельные пакеты JavaScript, эффективно уменьшая размер файловой системы и повышая производительность начальной загрузки страницы. Этот метод оптимизации значительно способствует повышению производительности и более плавному взаимодействию с пользователем.

// app/page.tsx

import dynamic from 'next/dynamic';

const DynamicHeader = dynamic(() => import('../components/header'), {
  loading: () => <p>Loading...</p>,
});

export default function Home() {
  return <DynamicHeader />;
}

Маршрутизатор приложений вносит заметное изменение: серверные компоненты больше не включаются в пакет JavaScript для браузера. По умолчанию клиентские компоненты автоматически разделяют код с помощью Webpack или Turbopack в Next.js.

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

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

// app/layout.tsx

import { getUser } from './auth';
import { Dashboard, Landing } from './components';

export default async function Layout() {
  const isLoggedIn = await getUser();
  return isLoggedIn ? <Dashboard /> : <Landing />;
}