Перейти к содержимому

1. Что такое Next.js

Next.js — это React-фреймворк для создания full-stack веб-приложений. Разработан компанией Vercel и поддерживается огромным сообществом. Думай о нём как о React на стероидах — все мощности React плюс серверный рендеринг, файловая маршрутизация, оптимизации и много другого из коробки. 🚀

React — это библиотека интерфейса
Next.js — это фреймворк для создания приложений на React
┌─────────────────────────────────────────────────────────────┐
│ Next.js │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ React │ │
│ │ Components │ Hooks │ Context │ State │ Props │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ + File Routing + SSR/SSG/ISR + API Routes │
│ + Server Actions + Image Optim. + Font Optim. │
│ + Middleware + Caching + Streaming │
└─────────────────────────────────────────────────────────────┘

2016 год. Guillermo Rauch (CEO Vercel) написал пост «7 Principles of Rich Web Applications». Одним из принципов был server-side rendering. В октябре 2016 года вышел Next.js 1.0 — маленький фреймворк с одной суперсилой: React + SSR.

2016 │ Next.js 1.0 — SSR для React, file-based routing
2017 │ Next.js 2.0 — динамические роуты, prefetching
2018 │ Next.js 7.0 — улучшенная DX, error overlay
2019 │ Next.js 9.0 — TypeScript из коробки, API Routes
2020 │ Next.js 10.0 — next/image, next/link, i18n
2021 │ Next.js 12.0 — Rust-based компилятор (SWC), middleware
2022 │ Next.js 13.0 — App Router (beta), React Server Components
2023 │ Next.js 13.4 — App Router stable 🎉
2023 │ Next.js 14.0 — Server Actions stable, Partial Prerendering
2024 │ Next.js 15.0 — React 19, Turbopack stable, async APIs

За 8 лет Next.js вырос из маленького эксперимента в самый популярный React-фреймворк с более чем 6 миллионами еженедельных загрузок из npm!


Давай честно посмотрим на проблемы обычного React-приложения (Create React App / Vite):

Проблема 1: SEO и первая загрузка

<!-- Что видит поисковик в React SPA: -->
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
<div id="root"></div> <!-- 🤖 Пусто! Робот ничего не найдёт -->
<script src="/bundle.js"></script> <!-- Качается весь JS сначала -->
</body>
</html>
<!-- Что видит поисковик в Next.js: -->
<!DOCTYPE html>
<html>
<head>
<title>Мой крутой блог | Яша учит код</title>
<meta name="description" content="Статья про Next.js">
</head>
<body>
<header>...</header>
<article>
<h1>Что такое Next.js?</h1>
<p>Next.js — это React-фреймворк...</p> <!-- ✅ Весь контент сразу! -->
</article>
</body>
</html>

Проблема 2: Нет маршрутизации из коробки

Окно терминала
npm install react-router-dom
# Потом написать кучу кода для маршрутов...
# Next.js: просто создай файл!
# app/about/page.tsx → автоматически /about
# app/blog/[slug]/page.tsx → автоматически /blog/:slug

Проблема 3: Нет серверной части

// React SPA: нужен отдельный бэкенд (Express, NestJS, Fastify...)
// Два репозитория, два деплоя, CORS, авторизация между ними...
// Next.js: серверная часть прямо в проекте!
// app/api/users/route.ts → GET /api/users
export async function GET() {
const users = await db.users.findMany();
return Response.json(users);
}

Структура папок = структура URL. Никакого конфига роутов!

app/
├── page.tsx → /
├── about/
│ └── page.tsx → /about
├── blog/
│ ├── page.tsx → /blog
│ └── [slug]/
│ └── page.tsx → /blog/anything
└── dashboard/
├── page.tsx → /dashboard
├── users/
│ └── page.tsx → /dashboard/users
└── settings/
└── page.tsx → /dashboard/settings

Next.js позволяет выбирать стратегию для каждой страницы отдельно:

app/blog/[slug]/page.tsx
// 🏗️ SSG — статическая генерация при сборке (по умолчанию для статических страниц)
export async function generateStaticParams() {
const posts = await getAllPosts();
return posts.map(post => ({ slug: post.slug }));
}
export default async function BlogPost({ params }) {
const post = await getPost(params.slug);
return <article>{post.content}</article>;
}
// ⚡ SSR — сервер рендерит при каждом запросе
// (автоматически если используешь cookies/headers/searchParams)
export const dynamic = 'force-dynamic'; // явное указание
// 🔄 ISR — статика с периодическим обновлением
export const revalidate = 3600; // обновлять каждый час

Это революция! Компоненты, которые работают только на сервере:

// app/users/page.tsx — Server Component по умолчанию!
// Этот код НИКОГДА не попадёт в браузер
import { db } from '@/lib/db'; // 🔒 Прямое обращение к БД в компоненте!
export default async function UsersPage() {
// async/await прямо в компоненте!
const users = await db.user.findMany({
where: { active: true },
orderBy: { name: 'asc' }
});
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
// Клиент получит готовый HTML — ни одной строки кода с БД!
// Сравни с обычным React:
// Нужно: useEffect + useState + fetch + обработка загрузки + обработка ошибок
function UsersPage() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(data => { setUsers(data); setLoading(false); })
.catch(err => { setError(err); setLoading(false); });
}, []);
if (loading) return <Spinner />;
if (error) return <Error />;
return <ul>{users.map(...)}</ul>;
}
// 15 строк vs 5 строк — и без API route!

Функции, которые вызываются с клиента, но выполняются на сервере:

app/actions.ts
'use server'; // 🚀 Эта директива делает функцию серверным действием
export async function createPost(formData: FormData) {
const title = formData.get('title') as string;
const content = formData.get('content') as string;
// Прямая работа с БД — без API routes!
await db.post.create({ data: { title, content } });
revalidatePath('/blog'); // Обновить кеш страницы блога
}
// app/create-post/page.tsx
import { createPost } from '../actions';
export default function CreatePostPage() {
return (
<form action={createPost}> {/* Прямо передаём серверную функцию! */}
<input name="title" placeholder="Заголовок" />
<textarea name="content" placeholder="Содержание" />
<button type="submit">Создать пост</button>
</form>
);
}
// Никакого useState, никакого fetch, никакого API route!

Next.js 15 принёс React 19 и несколько важных изменений в API:

// ⚠️ BREAKING CHANGE: params, searchParams, cookies, headers теперь async!
// Next.js 14 (старый способ):
export default function Page({ params }: { params: { slug: string } }) {
const slug = params.slug; // Синхронно
}
// Next.js 15 (новый способ):
export default async function Page({
params
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params; // Async!
}
// То же для cookies и headers:
import { cookies, headers } from 'next/headers';
// Было:
const cookieStore = cookies();
// Стало:
const cookieStore = await cookies();
Окно терминала
# Next.js 15: next dev использует Turbopack
npm run dev
# ▲ Next.js 15.0.0 (Turbopack)
# - Local: http://localhost:3000
#
# ⚡ В 5-10 раз быстрее Webpack для hot reload!
// ⚠️ BREAKING: fetch() больше НЕ кешируется по умолчанию!
// Next.js 14: кешировалось автоматически
const data = await fetch('/api/data'); // cache: 'force-cache' по умолчанию
// Next.js 15: НЕ кешируется по умолчанию (как в браузере)
const data = await fetch('/api/data'); // cache: 'no-store' по умолчанию
// Если нужен кеш — указывай явно:
const data = await fetch('/api/data', { cache: 'force-cache' });
// Или через revalidate:
const data = await fetch('/api/data', { next: { revalidate: 3600 } });

Компания │ Что делают
──────────────────┼────────────────────────────────────────
TikTok │ Веб-версия TikTok
Twitch │ Некоторые части платформы
Notion │ Маркетинговый сайт + app
Hulu │ Стриминговый сервис
Target │ E-commerce
Loom │ Видео-мессенджер
HashiCorp │ Документация и сайт
Linear │ Project management tool
Vercel │ Собственная платформа
GitHub (частично) │ Отдельные страницы

Окно терминала
# Создаём проект
npx create-next-app@latest my-nextjs-app --typescript --eslint --tailwind --app --turbopack
cd my-nextjs-app
# Смотрим структуру
ls -la
# app/ — маршрутизация и страницы
# components/ — (нужно создать вручную)
# public/ — статические файлы
# next.config.mjs — конфигурация
# Запускаем
npm run dev

Откроем app/page.tsx:

// app/page.tsx — твоя первая страница!
export default function Home() {
return (
<main>
<h1>Привет, Next.js! 👋</h1>
<p>Это серверный компонент — рендерится на сервере!</p>
</main>
);
}
// Обрати внимание: нет 'use client', нет useState, нет useEffect
// Это обычная async-ready функция — чистота! ✨

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
// Экспериментальные фичи
experimental: {
// React 19 Compiler (Next.js 15+)
reactCompiler: true,
// После отправки ответа
after: true,
// Partial Prerendering (PPR) — будущее Next.js
ppr: 'incremental',
},
// Оптимизация изображений
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.unsplash.com',
},
],
},
// Редиректы
async redirects() {
return [
{
source: '/old-blog/:slug',
destination: '/blog/:slug',
permanent: true, // 301 redirect
},
];
},
// Заголовки безопасности
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
],
},
];
},
};
export default nextConfig;

Ты узнал:

  1. Что такое Next.js — React-фреймворк от Vercel для full-stack приложений
  2. История — от 2016 до Next.js 15 в 2024
  3. Проблемы React SPA которые решает Next.js (SEO, роутинг, серверная часть)
  4. Ключевые концепции: File routing, RSC, Server Actions, разные стратегии рендеринга
  5. Next.js 15: async APIs, Turbopack, изменения в кешировании

В следующем уроке разберём App Router vs Pages Router — два поколения системы маршрутизации в Next.js! 🗺️