Разбираемся с фреймворком, который используют в Spotify, TikTok и Notion.
Разработка приложений на React может быть долгой и слишком сложной, особенно в самом начале изучения. Рано или поздно вы столкнётесь с проблемами навигации, стилизации и медленным рендерингом на стороне клиента. Все эти проблемы можно решить с помощью Next.js — фреймворка на базе React. В этой статье рассказываем про его фишки и особенности.
Что такое Next.js
Next.js — это метафреймворк на базе React для разработки клиент-серверных (fullstack) приложений как для мобильных платформ, так и для веба. Если говорить проще, то Next.js помогает решить проблемы, которые есть в React и добавляет новые функции для более удобной и быстрой работы.
Next.js разработала компания Vercel (ранее Zeit) и выпустила его в качестве открытого проекта на GitHub в октябре 2016 года. В его основе лежало шесть принципов:
- Всегда готов к работе. Основные функции фреймворка готовы к работе сразу после развёртывания приложения, надо добавить только данные проекта.
- Только JavaScript. Все функции фреймворка написаны на одном языке программирования, что позволяет добиться большей эффективности.
- Разделение кода. Кодовая база приложений автоматически разделяется на серверную и клиентскую. Благодаря этому загружаются только те фрагменты страницы, которые нужны пользователю, а всё остальное, включая внешние скрипты и служебные функции, выполняется на сервере.
- Работа с данными. Разработчик может сам определить, когда и какие данные должно запрашивать приложение.
- Предугадывание запросов. Приложение предсказывает, какие ресурсы скоро понадобятся и заранее загружает их.
- Простое развёртывание. Сборка проекта запускается одной командой. Next.js генерирует версию приложения с готовыми файлами HTML, CSS и JavaScript.
На момент написания статьи актуальная версия Next.js — 14.0, которая вышла в октябре 2023 года. При этом команда проекта каждый месяц выпускает минорные обновления и работает над версией 15.0.
Зачем нужен Next.js
Одна из главных задач Next.js — исправить врождённые «болячки» React. Например, React обычно отрисовывает приложение в браузере, а перед рендерингом загружает с сервера и запускает JavaScript-код. Это сильно замедляет работу сайта и заставляет пользователя ждать, пока страница загрузится. Next.js, напротив, рендерит страницы на сервере и отдаёт их в готовом виде.
Вот ещё несколько преимуществ Next.js перед React:
- Встроенная навигация. Для того чтобы добавить новую страницу в приложение и сослаться на неё внутри приложения, достаточно просто создать новый файл в директории проекта.
- Рендеринг на стороне сервера. Можно настроить рендеринг так, чтобы он работал на сервере. Тогда приложению не придётся загружать файлы и собирать страницу локально, а пользователю не надо будет ждать, пока страница откроется в браузере.
- Быстрая разработка. Многие важные функции в Next.js доступны из коробки, поэтому разработчики могут не тратить время на их реализацию. Например, если в React для настройки маршрутизации надо использовать сторонние библиотеки, то в Next.js всё работает по умолчанию.
- Работа с SEO. Next.js повышает SEO-показатели сайта за счёт серверного рендеринга, статической генерации и управления метатегами.
Основные преимущества Next.js
Давайте рассмотрим, что именно предлагает Next.js, на какие его функции стоит обратить внимание в первую очередь и что они нам дают.
Рендеринг на стороне сервера
Next.js позволяет разработчикам рендерить HTML-код на стороне сервера в ответ на запрос. Этот метод значительно ускоряет загрузку приложения в сравнении с рендерингом на стороне клиента, особенно если на клиентской стороне слабое железо.
Генерация статической разметки
Next.js позволяет использовать метод генерации статической разметки, при котором HTML-код создаётся на этапе компиляции. Этот метод отлично подходит для страниц, которые редко обновляются. В этом случае код передаётся пользователю напрямую из хранилища контента (content delivery network, CDN).
Реализация API
В Next.js можно создавать конечные точки API прямо внутри приложения. Если в других фреймворках для работы с базами данных, внешними API и любой другой серверной логикой нужен отдельный бэкенд, то в Next.js всё это можно реализовать в основном проекте.
Навигация, основанная на файлах
Next.js использует принципы навигации, основанные на файлах. Благодаря этому структурой проекта можно управлять с помощью простого добавления папок и файлов в основную директорию приложения.
Автоматическое дробление кода
Фреймворк автоматически разбивает ваш код на небольшие части, загружая для каждой страницы только те фрагменты JavaScript-кода, которые в ней используются. Это ускоряет работу всего приложения.
Горячая замена модулей
Горячая замена модулей — функция, которая позволяет разработчикам увидеть внесённые изменения в режиме реального времени. Для этого не надо каждый раз обновлять страницу, что значительно ускоряет разработку.
Встроенная поддержка CSS и Sass
Next.js поддерживает импорт файлов CSS и Sass напрямую внутрь компонентов, что позволяет настраивать внешний вид приложения без дополнительных усилий.
Салют, Next.js: создаём первый проект
Лучшее обучение — это практика, поэтому от теории перейдём к действиям и создадим свой первый проект на Next.js, но сперва установим сам фреймворк. Чтобы установить последнюю версию Next.js, надо выполнить несколько простых шагов:
1. Убедитесь, что у вас установлен пакетный менеджер NPM или Yarn.
2. Откройте терминал и перейдите в папку, в которой будет находиться проект. Для этого можно использовать команду cd.
3. Запустите команду ниже, которая установит последнюю версию Next.js и инициализирует новый проект.
npx create-next-app@latest
4. Во время инициализации надо ответить на несколько вопросов, которые помогут настроить проект:
Вопрос | Перевод | Значение по умолчанию |
---|---|---|
1 ✔ What is your project named? | Имя проекта | ‘my-app’ |
2 ✔ Would you like to use TypeScript? No/yes | Вы хотите использовать TypeScript? | Yes |
3 ✔ Would you like to use ESLint? No/yes | Вы хотите использовать ESLint? | Yes |
4 ✔ Would you like to use Tailwind CSS? No/yes | Вы хотите использовать Tailwind CSS? | No |
5 ✔ Would you like to use `src/` directory? No/yes | Вы хотите использовать папку src? | Yes |
6 ✔ Would you like to use App Router? (recommended) No/yes | Вы хотите использовать App Router? | Yes |
7 ✔ Would you like to customize the default import alias (@/*)? No/yes | Вы хотите настроить имя импорта по умолчанию? | No |
8 ✔ What import alias would you like configured? @/* | Какое имя импорта вы бы хотели использовать? | — |
5. Теперь вы можете запустить проект всего одной командой:
npm run dev
Вы великолепны! Ваш первый проект на последней версии Next.js запущен.
Из чего состоит проект Next.js
Давайте посмотрим, что уже есть внутри нашего проекта. Верхнеуровневые папки проекта используются для хранения вашего кода и статических ресурсов, например изображений или внешних скриптов. Всего в Next.js четыре папки:
- app — страницы приложения с навигацией через app;
- pages — страницы приложения с навигацией через pages;
- public — папка для хранения статических ресурсов;
- src — дополнительная папка для исходников проекта.
Верхнеуровневые файлы используются для настройки приложения, управления зависимостями, интеграции систем мониторинга и настройки окружения. Вот основные из них:
- next.config.js — настройки Next.js;
- package.json — зависимости проекта и скрипты;
- .env — переменные для настройки окружения;
- .eslintrc.json — настройки ESLint;
- tsconfig.json — настройки TypeScript;
- jsconfig.json — настройки JavaScript.
Организация страниц
Добавление страниц в приложение в Next.js основано на структуре файловой системы. До выпуска Next.js 13-й версии всё было просто: чтобы создать новую страницу вашему сайту или приложению, достаточно было добавить файл в структуру pages. Сейчас так тоже можно, но добавился каталог app, который добавляет новые функции и работает одновременно с pages, так что вы можете выбрать, какие страницы где добавлять. Как работает каждый из них и в чём отличия app, рассмотрим ниже.
Навигация с помощью pages
Для создания страницы надо добавить файл в папку pages, и он автоматически появится в навигации внутри приложения. Важно помнить, что все файлы в pages — маршруты, основанные на имени файла. Например, если добавить в папку файл contact.js, на сайте появится страница с адресом /contact. При этом разработчику не надо настраивать маршрутизацию вручную.
Next.js также поддерживает динамические маршруты — то есть маршруты, которые могут меняться в зависимости от исходных данных, например названия товаров в онлайн-магазине или ID пользователей социальной сети. Для создания динамической маршрутизации используются файлы с квадратными скобками в названии. Если создать в проекте файл с именем pages/posts/[id].js, он будет доступен по ссылкам posts/1, posts/2 и так далее.
Навигация с помощью app
Работать с папкой app так же просто, как с pages, — надо просто добавить файл, а маршрут построится автоматически. При этом у этого способа есть несколько преимуществ:
- Можно создавать вложенные макеты, которые применяются для страниц определённого раздела.
- Есть отдельные страницы ошибок для разделов и страниц.
- Выполнение кода на сервере в ответ на действия пользователя.
- Можно рендерить разные страницы по одному и тому же адресу в зависимости от условий.
Навигация внутри папки app приоритетнее навигации внутри pages. Следите, чтобы один и тот же URL не повторялся в разных папках.
Вложенные папки внутри app определяют вашу навигацию, следуя от корневой папки до финальной, в которой уже лежит файл page.js. Файлы внутри папок используются для создания контента на определённом узле навигации.
Разбиваем страницу на части с помощью макетов
Макет — это набор компонентов, которые используются на разных страницах приложения. Например, меню сайта, хедер и «подвал» одинаковы для всех страниц — значит, их можно вынести в макет и переиспользовать.
У макетов в Next.js есть следующие преимущества:
- Элементы макета можно не загружать заново при переходе между страницами — при этом их состояние сохранится. Например, если у вас есть строка поиска, то данные, введённые пользователем на одной странице, сохранятся на другой.
- Если у вас несколько групп пользователей с разной навигацией, то вы можете создать макеты навигации для каждой из них. Например, создать два меню: для пользователей и администраторов.
Чтобы добавить макет в проект, надо создать корневую директорию components и внутри неё файл components/Layout.js, который будет содержать инструкции по загрузке необходимых компонентов. В коде указание children служит для загрузки контента итоговой страницы:
import Header from ‘./Header’; import Footer from ‘./Footer’; const RootLayout = ({ children }) => { return ( <> <Header /> <main>{children}</main> <Footer /> </> ); }; export default RootLayout;
Если вы хотите добавить макет только на определённую страницу, то ваш код будет выглядеть так:
import RootLayout from ‘@/components/Layout’; const Home = () => { return ( <RootLayout> <main>{/* … */}</main> </RootLayout> ); }; export default Home;
Если вы хотите, чтобы макет сохранял своё состояние при переходе между страницами, то его надо добавить в файл pages/_app.js:
// Импортируем глобальные стили import ‘@/styles/globals.css’; // Импортируем компонент макета RootLayout import RootLayout from ‘@/components/Layout’; // Добавляем макет на все страницы приложения export default function App({ Component, pageProps }) { return ( <RootLayout> <Component {…pageProps} /> </RootLayout> ); }
Теперь состояние нашего макета сохраняется при переходе между страницами и нет никакой необходимости прописывать загрузку макета внутри каждой.
Ссылаемся на другие страницы
Для добавления ссылки в Next.js используется компонент Link. Он реализует навигацию на стороне клиента с использованием JavaScript.
Чтобы создать ссылку, например, на страницу about, в код страницы надо добавить следующий код:
import Link from ‘@/styles/globals.css’ <Link href=”/about/”>О нас</Link>
Генерация контента
React и Next.js позволяют создавать гибридные приложения, где часть контента рендерится на стороне сервера, а часть — на стороне клиента. По умолчанию Next.js использует серверные компоненты, поэтому вам не надо ничего дополнительно настраивать, чтобы серверный рендеринг работал.
Использование серверных компонентов идеально для тех частей страниц, которые не требуют динамического обновления в процессе работы пользователя на странице. Вот в чём их преимущество:
- Так как контент сайта генерируется на сервере, клиенту поступает уже готовая HTML-страница — браузеру не нужно рендерить массивные JS-блоки.
- Вы сохраняете логику и чувствительные данные на сервере, включая токены и API. Так меньше шансов, что они «утекут» клиенту.
- Код готовой страницы может храниться на сервере и повторно использоваться при следующих запросах.
- Сгенерированная на сервере страница гораздо легче обрабатывается поисковыми ботами и ботами социальных сетей.
Клиентские компоненты, в свою очередь, рендерятся и на сервере, и на клиенте. При первом запросе они создаются на стороне сервера, а затем отправляются в браузер клиента. Когда пользователь просматривает загруженную страницу, все обновления будут происходить уже на клиентской стороне. Такие компоненты удобно использовать для анимации или изменения контента в ответ на действия пользователя — например, при нажатии на кнопку «Нравится» или отправке формы.
Чтобы использовать клиентские компоненты, просто добавьте строчку ‘use client’ в начале вашего файла.
‘use client’ import { useState } from ‘react’ // the rest of your code
Всё, что определено в данном файле, включая импортируемые модули, будет обрабатываться как клиентские компоненты.
Добавляем изображения
В Next.js есть удобные инструменты для работы с изображениями, например опция ленивой загрузки (lazy load) и заполнение мест под картинки. Это позволяет разработчикам добиться более быстрой загрузки страницы и предотвращает «съезжание» картинок.
Изображения можно загружать как из локального хранилища, так и с внешних источников, например со стороннего сервера. При этом менять размер картинок можно уже внутри самого приложения.
Для использования изображений в приложении понадобится следующий код:
import Image from ‘next/image’ import Avatar from ‘./me.png’ export default function Page() { return ( <Image src={Avatar} ) }
Преимущество работы с изображениями в Next.js в том, что фреймворк расширяет базовый HTML-компонент <img> с помощью дополнительных функций. Например, можно оптимизировать размер изображения под платформу пользователя и загружать картинки по мере прокрутки страницы.
Добавляем внешние скрипты
С помощью внешних скриптов в приложение можно добавить функции, которые разработали сторонние программисты. Например, системы анализа данных, виджеты поддержки пользователей и рекламные блоки.
В Next.js можно добавить скрипт как ко всему проекту, так и к отдельному элементу. При этом важно помнить, что если скрипт будет использоваться во всём приложении, то его надо встроить в корневой макет, а все остальные — в макеты конечных страниц.
Код интеграции скрипта выглядит следующим образом:
import Script from ‘next/script’ export default function Page() { return ( <> <Script src=”https://example.com/script.js” /> </> ) }
Можно настроить поведение скрипта в Next.js с помощью свойства strategy:
- beforeInteractive — загружает код скрипта до загрузки всего остального кода;
- afterInteractive — используется по умолчанию. Загружается после определения кусков кода, необходимых для страницы;
- lazyOnload — загружает скрипт после загрузки основного кода.
Встроенная поддержка CSS
Чтобы добавить глобальные стили в приложение на Next.js, надо импортировать CSS-файл в pages/_app.js. Например, если у вас в папке styles есть файл styles.css, то импорт будет выглядеть следующим образом:
import ‘../styles/style.css’ function MyApp({ Component, pageProps }) { return <Component {…pageProps} /> } export default MyApp
Стили можно применить как к отдельной странице, так и к определённому компоненту. Например, у нас есть файл navigationbar.css в папке styles. Тогда в файл navigationbar.js мы добавляем код импорта:
import styles from ‘../styles/navigationbar.css’; export default function Navigationbar({ current }) { return ( // Ваш код ); }
Настраиваем API в Next.js
Для взаимодействия с внешними приложениями, отправки и получение запросов нужна конечная точка API. Для этого создайте в папке pages/api файл с функцией в следующем формате:
// req — входящее сообщение HTTP, res — HTTP-ответ сервера export default function handler(req, res) { // … }
Один из наиболее популярных способов применения API — это обработка введённых пользователем данных. Если у вас на странице добавлена форма ввода, вы можете отправить POST-запрос и сохранить данные напрямую в базу данных с помощью следующего кода:
export default function handler(req, res) { const email = req.body.email; }
Подводим итоги
- Next.js — фреймворк на базе React, который позволяет создавать производительные мобильные и веб-приложения.
- С помощью Next.js можно создавать клиент-серверные (fullstack) приложения.
- Скорость работы Next.js особенно заметна пользователям с нестабильным подключением к интернету и слабым железом.
- Программистам доступно множество инструментов для удобной и быстрой разработки приложений. Например, автоматическая маршрутизация, сочетание серверного рендеринга со статической генерацией и возможность создавать конечные точки API.
Конечная точка API — URL-адрес, с помощью которого сервисы «общаются» друг с другом.
Sass — метаязык на базе CSS, котороый упрощает работу со стилями.
«Съезжание» картинок — распространённая проблема, когда картинки без заранее заданных размеров на веб-странцие загружаются асинхронно. В процессе загрузки изображения сдвигают элементы вокруг, например другие картинки или блоки текста.
Метафреймворк — надстройка над другим фреймворком, которая добавляет новые функции, инструменты и библиотеки.