Next.js объяснил шестилетнему ребенку

Хотите изучить самый популярный и революционный в отрасли фреймворк?

Next.js — это инструмент, который помогает людям создавать действительно крутые веб-сайты с помощью React. Это как волшебная палочка, благодаря которой веб-сайты работают лучше, а страницы отображаются быстрее. Используя рендеринг на стороне сервера и создание статического сайта, Next.js может помочь улучшить поисковую оптимизацию (SEO), напрямую предоставляя статические HTML-страницы, более читаемые для поисковых роботов браузера. Кроме того, Next.js предоставляет возможности полного стека, а это означает, что мы можем создавать как интерфейсные, так и серверные части их приложений в одной и той же среде. Многим людям нравится использовать Next.js, потому что он заставляет их сайты работать лучше и выглядеть круче!

Мы можем обобщить ключевые аспекты Next.js в следующем списке:

  • Маршрутизация на основе файлов
     – Больше никаких шаблонов в пользу более интуитивно понятной структуры папок.
     – Поддержка вложенных и динамических маршрутов.
  • Автоматическая поддержка SSR(подготовка кода на сервере)
     – Отрисовка контента внутри сервера и возврат статических страниц.
     – Улучшенная поисковая оптимизация, поисковые роботы перекидывают View Source и видят контент.
     – смешивание данных на стороне клиента и на стороне сервера.
  • Возможности полного стека
    - Работа с файловой системой
    - Доступ к БД или настройка аутентификации
    - Разделение функций BE, исключение их из пакета
  • Простое развертывание
    — стандартная сборка и полная статическая сборка
  • Оптимизация
    — Разделение кода
    — Оптимизация изображения

Давайте рассмотрим каждую функциональность и поймем, почему всем так нравится Next.js!

Файловая маршрутизация

Когда мы создаем проект Next.js, у нас есть папка с именем /pages, куда мы помещаем все наши страницы. Каждый файл в этой папке представляет собой отдельную страницу на нашем веб-сайте. Например, если у нас есть файл с именем index.tsx, когда мы перейдем к основному URL-адресу нашего веб-сайта, он покажет нам эту страницу.

Мы также можем создавать вложенные страницы, создавая папки внутри папки /pages. Например, у нас может быть папка под названием «блог», и мы можем поместить в нее все наши сообщения в блоге. Таким образом, когда мы перейдем на наш веб-сайт.com/blog, мы увидим все наши сообщения в блоге.

Next.js также позволяет нам создавать динамические страницы. Это означает, что у нас может быть страница, которая меняется в зависимости от того, что мы вводим в URL. Мы можем сделать это, добавив скобки и имя внутри имени файла, например [id].tsx. Это сообщает Next.js, что эта страница будет иметь динамический идентификатор в URL-адресе, и он будет меняться в зависимости от того, что мы туда поместили. Next.js будет использовать более конкретный маршрут (article/list), если он существует, даже если существует более общий маршрут (article/[id]).

Мы также можем использовать специальные символы, такие как […], для захвата нескольких параметров в URL-адресе. Например, если у нас есть файл с именем […slug].tsx, это означает, что мы можем поместить в URL-адрес несколько значений, разделенных косой чертой.

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

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

Предварительный рендеринг

Предварительный рендеринг — это процесс загрузки данных и предварительного создания HTML-страниц. Мы можем предварительно сгенерировать готовую HTML-страницу и отправить ее клиенту, где она «увлажняется» с помощью приложения React, добавляя JavaScript к статической странице, чтобы она стала интерактивной и динамичной на стороне клиента. Next.js поддерживает два типа предварительного рендеринга:

  • Статическая генерация (SSG): предварительно генерирует все статические страницы во время сборки перед развертыванием веб-сайта.
  • Рендеринг на стороне сервера (SSR): он генерирует страницы после развертывания во время «работы», когда запрос достигает сервера.

Создание статического сайта (SSG)

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

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

Чтобы создать страницу SSG, нам нужно экспортировать специальную функцию внутри того же файла нашей страницы с именем getStaticPorps. Эта функция может содержать код узла, который дает нам доступ к внутренним функциям (например, доступ к файловой системе), но у нее нет доступа к веб-API, и, поскольку она не будет включена в комплект, ее можно использовать для хранить конфиденциальную информацию, такую ​​как ключи API.

import React from 'react'

export default function Home({ posts }) {
  ...
}
export async function getStaticProps() {
  // Fetch data from an API or a database
  const res = await fetch('https://example.com/posts')
  const posts = await res.json()
  // Return the fetched data as props
  return {
    props: {
      posts,
    },
  }
}

Есть два способа статического рендеринга страниц в Next.js:

○: Статический (по умолчанию) автоматически отображается как статический HTML (не использует начальные параметры)
●: SSG автоматически создается как статический HTML (используется getStaticProps)

Инкрементная статическая [повторная] генерация (ISR)

Инкрементная статическая регенерация (ISR) означает, что веб-страница создается не только один раз во время сборки. Вместо этого он постоянно обновляется даже после развертывания веб-страницы, не требуя повторного развертывания. Мы заранее создаем веб-страницу, а затем указываем Next.js обновлять веб-страницу каждые X секунд для каждого входящего запроса.

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

Чтобы добиться инкрементной статической регенерации с помощью ISR, мы можем установить время повторной проверки, используя revalidate: 60 в методе getStaticProps.

Н.Б. В локальной среде он будет перепроверяться каждый раз.

Предварительно созданные пути

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

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

// pages/category/[category].js

// This is the main component for the dynamic page
export default function CategoryPage({ movies }) {
  ...
}

// This function tells Next.js which dynamic paths should be pre-generated
export async function getStaticPaths() {

  // In this example, we'll pre-generate pages for this 3 categories
  const paths = [
    { params: { category: 'Thiller' } },
    { params: { category: 'Comedy' } },
    { params: { category: 'Action' } },
  ];

  // Return the array of paths to be pre-generated 
  // and redirect to 404 if it doesn't match.
  return { paths, fallback: false};
}

// This function fetches data for the specified category name and returns it as props
export async function getStaticProps({ params }) {
  const category = params.category;

  // fetch data for category with name `category`
  const res = await fetch(`https://movies.com/category/${category}`);
  const movies = await res.json()

  return { props: { movies } };
}

Как вы видите в примере, нам нужно вернуть список paths и свойство fallback. Этот последний инструктирует Next.js, как вести себя, когда пользователь пытается посетить страницу, которую мы не создали заранее. С fallback: false мы будем перенаправлять на страницу 404, если страница не существует.

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

С fallback: ‘blocking’ страница будет загружаться дольше, но она появится только тогда, когда будет полностью готова, потому что Next.js будет блокировать рендеринг. Если для рендеринга страницы требуется время, может быть удобнее показать состояние загрузки и использовать fallback: true, но если это в целом быстро, blocking позволит избежать эффекта мерцания.

Рендеринг на стороне сервера

Рендеринг на стороне сервера — это процесс рендеринга веб-страниц на сервере «на лету» перед их отправкой в ​​браузер клиента. Этот подход удобен, когда нам нужно генерировать динамический контент, мы можем получить доступ к объекту запроса для получения полезной информации (например, файлов cookie) и мы можем получить данные из базы данных или API перед рендерингом.

Чтобы использовать рендеринг на стороне сервера, мы должны экспортировать специальную функцию с именем getServerSideProps (нельзя использовать рядом с другими функциями getProps). Эта функция позволяет нам написать код на сервере, который генерирует контент для каждого отдельного запроса. Используя параметр контекста, мы можем получить доступ к объектам запроса и ответа и при необходимости изменить их.

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

// pages/user-profile.js

import { getSession } from 'next-auth/client';

export function Profile({ userInfo }) {
  ...
}

export async function getServerSideProps(context) {
  const session = await getSession(context);

  if (!session) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    };
  }

  // Fetch post data from an API using postId
  const res = await fetch(`https://myapi/user/${session.userId}`)
  const userInfo = await res.json()

  return {
    props: {
      userInfo,
    },
  }
}

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

λ: Сервер, рендеринг на стороне сервера во время выполнения (использует getServerSideProps или getInitialProps)

Извлечение данных на стороне клиента

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

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

В заключение, объединив выборку данных на стороне клиента с рендерингом на стороне сервера и инкрементной статической регенерацией, мы можем создавать быстрые, масштабируемые и интерактивные веб-интерфейсы!

Варианты развертывания

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

Но прежде нам нужно построить наш проект!
У нас есть два основных варианта развертывания: стандартная сборка и полная статическая сборка.

Стандартная сборка запускается с помощью команды next build, создавая оптимизированный пакет и серверное приложение. Он будет предварительно отображать все страницы, где это возможно, а сервер будет принимать входящие запросы и генерировать страницы на лету, где это необходимо. Для этого требуется сервер NodeJS, на котором можно запустить. Код серверных функций не будет поставляться вместе с клиентской сборкой.

Полная статическая сборка запускается с помощью команды next export (необходимо добавить в package.json), создавая 100% статическое приложение (HTML, CSS, JS), где нам не нужен NodeJS. Однако его невозможно использовать, если наше приложение использует маршруты API, страницы на стороне сервера или повторную проверку и откат страниц, а также оптимизацию изображений.

Развертывание

После того, как мы очистили, добавили метаданные и оптимизировали код, мы должны использовать переменные среды в целях безопасности, такие как учетные данные БД и ключи API. Мы можем добавить эти переменные в next.config.js, экспортируя объект с реквизитом env. Мы также можем экспортировать функцию и импортировать из next/constants разные PHASES, чтобы условно назначить правильные переменные.

Когда приложение будет готово, мы можем проверить, все ли работает должным образом, запустив нашу команду сборки, а затем мы используем npm start для обслуживания нашего приложения. Он будет обслуживать локально версию нашего приложения.

Оптимизация

После запуска сборки мы можем использовать такие инструменты, как «webpack-bundle-analyzer», чтобы проверить размер наших файлов, который относится только к коду на стороне клиента, игнорируя функции на стороне сервера. Это может помочь нам определить части кода, которые больше, чем необходимо, и оптимизировать их для повышения производительности.

Next.js также предоставляет некоторые встроенные оптимизации, такие как автоматическое разделение кода и оптимизация изображений.

Разделение кода

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

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

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

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

import dynamic from 'next/dynamic';
const MyChart = dynamic(() => import('chart-lib'));

Оптимизация изображения

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

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

import Image from 'next/image'

function MyComponent() {
  return (
    <div>
      <Image src="https://unsplash.com/image.jpg" width={500} height={500} alt="My Image" />
    </div>
  )
}

Помимо отложенной загрузки и оптимизации формата, Next.js также поддерживает другие функции, такие как изображения-заполнители и адаптивная загрузка изображений.

Изображения-заполнители используются для предоставления временного изображения во время загрузки фактического изображения, что помогает предотвратить сдвиг макета и сокращает воспринимаемое время загрузки.

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

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

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

Дополнительные кредиты: Next.js 13 (бета)

Одно из наиболее значительных изменений в Next.js 13 (бета-версия) касается маршрутизации. В новой версии маршруты помещаются в папку app, а не в папку pages. По умолчанию все компоненты и страницы будут отображаться на стороне сервера. В новой версии также вводится немного другое соглашение об именах. В предыдущей версии index.js был файлом по умолчанию для домашней страницы, а в новой версии правильным является page.js. Кроме того, вложенные маршруты должны находиться внутри папки, например blog/page.js.

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

Макеты

Next.js 13 представляет новую функцию под названием «Макеты», которая позволяет нам совместно использовать компоненты пользовательского интерфейса между маршрутами, сохраняя при этом состояние и избегая дорогостоящих повторных рендерингов. С помощью этой функции мы можем создавать вложенные макеты и определять файл макета для каждой папки (маршрута) в своем приложении.

Например, мы можем создать файл layout.js внутри папки blog, и он будет использоваться в качестве макета для всех страниц внутри одной папки. Макет получит компонент как children и отобразит его в своем макете, как показано ниже:

// app/blog/layout.js
export default function BlogLayout({ children }) {
  // computation necessary only for Blog components
  return <section>{children}</section>;
}

В дополнение к layout.js мы также можем использовать другие файлы, такие как loading.js или error.js, для других относительных состояний.

Эта новая функция упрощает поддержание согласованного пользовательского интерфейса в приложении и упрощает процесс разработки.

Серверные и клиентские компоненты

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

Чтобы использовать эту функцию, нам нужно сделать наш компонент обещанием с async впереди. Например:

// app/page.js

async function getData() {
  const res = await fetch('https://api.example.com/...');
  return res.json();
}

// This is an async Server Component
export default async function Page() {
  const data = await getData();

  return <main>{/* ... */}</main>;
}

Однако не все компоненты могут быть серверными компонентами. Компоненты, использующие ловушки, такие как useEffect() или useState(), должны быть загружены как клиентские компоненты, а также интерактивные компоненты с прослушивателями событий, такими как onClick() или onChange(), или API-интерфейсы только для браузера.

По умолчанию все компоненты являются серверными компонентами, и мы должны использовать директиву ‘use client’;, чтобы загрузить их как клиентские компоненты, как показано ниже:

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

Заключение

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

Подведем итоги еще раз:

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

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

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

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

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

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

Дополнительные материалы на PlainEnglish.io.

Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .

Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.