Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Junior: питання на співбесіді з теми «Next.js, Inertia й маршрутизація»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

4 питання

Є три поширені архітектури, і вони відрізняються тим, хто відповідає за маршрутизацію й дані.

1. Окрема SPA + API Laravel (Vite + React Router, Laravel лише як JSON API, автентифікація через Sanctum):

  • фронтенд і бекенд незалежні: окремі деплої, можна мати кілька клієнтів (веб, мобільний застосунок);
  • треба самому будувати API, валідацію відповідей, обробку помилок, стан завантаження, маршрутизацію й автентифікацію (CORS, CSRF-cookie);
  • без SSR сторінки погано індексуються - для публічного контенту це мінус.

2. Inertia.js (React-сторінки, але маршрути й контролери - Laravel):

return Inertia::render('Orders/Show', ['order' => $order->only('id', 'total', 'status')]);
export default function Show({ order }) { /* ... */ }
  • немає окремого API: контролер передає дані як props сторінки, валідація, авторизація, редиректи, сесії - звичайний Laravel;
  • переходи без перезавантаження, як у SPA;
  • SSR можливий (окремий Node-процес), але не обов'язковий;
  • один застосунок - простіше для невеликої команди. Офіційний стартовий набір Laravel для React побудований саме так.

3. Next.js + Laravel як API:

  • React Server Components, потоковий рендер, кешування на рівні фреймворка, SSR/SSG з коробки - найкраще для SEO й публічних сайтів з великим трафіком;
  • два бекенди: Node-сервер Next.js і Laravel. Автентифікація, кешування й деплой стають складнішими;
  • частина логіки (серверні дії, маршрути) переїжджає з Laravel у Next.js - треба вирішити, де межа.

Як обирати:

Ситуація Вибір
адмінка, кабінет, внутрішній інструмент на Laravel Inertia
кілька клієнтів одного API (веб + мобільний) SPA + API
публічний контент-сайт з вимогами до SEO й швидкості Next.js (або Inertia з SSR)
команда з окремими фронтенд- і бекенд-розробниками SPA чи Next.js + API

Головне питання: чи потрібен окремий API як продукт. Якщо ні - Inertia дає SPA-досвід без витрат на API.

Докладніше в документації: Inertia: як це працює

React Router має три режими, і кожен наступний додає можливості поверх попереднього.

1. Декларативний - маршрути описано в JSX, лише зіставлення URL з компонентами й навігація:

import { BrowserRouter, Routes, Route, Link } from 'react-router';

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/posts/:id" element={<Post />} />
  </Routes>
</BrowserRouter>

Хуки useParams, useNavigate, useLocation, компонент <Link>. Дані завантажує сам компонент.

2. Режим даних - маршрути описано об'єктами поза рендером, і до них додаються завантажувачі даних і дії:

const router = createBrowserRouter([
  { path: '/posts/:id', Component: Post, loader: ({ params }) => getPost(params.id) },
]);

<RouterProvider router={router} />

Дані завантажуються до рендеру сторінки, паралельно для вкладених маршрутів, - без «водоспаду» запитів у useEffect. Дії (action) обробляють форми, після чого дані сторінки перевантажуються автоматично.

3. Фреймворковий - режим даних плюс плагін Vite: типобезпечні модулі маршрутів, автоматичне розділення коду, SSR, статичний рендер чи SPA на вибір. По суті це наступник Remix.

Як обирати: документація радить фреймворковий режим тим, хто не має сильної думки, - він дає найбільше. Декларативний - для простих застосунків або поступового переходу; режим даних - коли потрібні завантажувачі, але власна збірка.

React Router 8 (червень 2026) - перший реліз за щорічним графіком мажорних версій:

  • пакет react-router-dom видалено - усі імпорти з react-router (і react-router/dom);
  • мінімальні версії: React 19.2.7+, Node 22.22+, Vite 7+; пакети тепер лише ESM;
  • поведінка прапорців future.v8_* стала типовою: middleware маршрутів увімкнено завжди, модулі маршрутів розділяються на частини за замовчуванням;
  • у meta-функціях замість застарілого data - loaderData.

Якщо у v7 всі прапорці майбутньої версії вже були увімкнені, перехід на v8 мінімальний.

З Laravel React Router доречний в окремій SPA. В Inertia маршрутизація належить Laravel, і React Router не потрібен.

Докладніше в документації: React Router: вибір режиму

У App Router маршрути визначає структура папок у app/, а спеціальні файли всередині папки задають роль.

app/
├── layout.tsx          # кореневий макет (обов'язковий, містить <html> і <body>)
├── page.tsx            # /
├── blog/
│   ├── layout.tsx      # макет для всіх сторінок /blog/*
│   ├── page.tsx        # /blog
│   └── [slug]/
│       ├── page.tsx    # /blog/:slug
│       ├── loading.tsx # стан завантаження
│       └── error.tsx   # межа помилок

page.tsx - вміст маршруту. Без нього папка не стає доступним URL.

layout.tsx - спільна обгортка для сторінки й усіх вкладених маршрутів:

export default function BlogLayout({ children }: { children: React.ReactNode }) {
  return (
    <section>
      <BlogSidebar />
      {children}
    </section>
  );
}

Ключова властивість макетів: при переході між сторінками всередині макета він не перемонтовується - зберігає стан (відкрита бічна панель, введений пошук) і не рендериться заново. Перемальовується лише змінена частина.

Динамічні сегменти: [slug] - параметр; params у сторінці - Promise, його треба дочекатися:

export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);
  return <article>{post.title}</article>;
}

Інші файли:

  • loading.tsx - автоматичний <Suspense>: запасний вигляд, поки сторінка завантажує дані;
  • error.tsx - межа помилок сегмента (має бути клієнтським компонентом);
  • not-found.tsx - для notFound();
  • route.ts - обробник HTTP-запитів (API) замість сторінки.

Групи маршрутів (marketing) - папки в дужках не потрапляють в URL і дають змогу мати різні макети для частин сайту.

За замовчуванням усі ці компоненти - серверні: можна звертатися до бази чи API прямо в компоненті, а 'use client' додається лише там, де потрібна інтерактивність.

Докладніше в документації: Next.js: макети й сторінки

Next.js читає .env-файли й робить змінні доступними через process.env. Але де саме вони доступні, залежить від префікса.

Без префікса - лише на сервері:

DATABASE_URL=postgres://...
STRIPE_SECRET_KEY=sk_live_...

Доступні в серверних компонентах, обробниках маршрутів, серверних функціях. У браузері process.env.STRIPE_SECRET_KEY - undefined.

З префіксом NEXT_PUBLIC_ - у браузері теж:

NEXT_PUBLIC_ANALYTICS_ID=G-XXXX
NEXT_PUBLIC_API_URL=https://api.example.com
setupAnalytics(process.env.NEXT_PUBLIC_ANALYTICS_ID);

Як це працює: під час next build Next.js підставляє значення прямо в код JavaScript, що йде в браузер. Тобто:

  • значення публічне - будь-хто побачить його в коді сторінки. Сюди можна класти лише те, що й так не секретно;
  • значення фіксується на момент збирання. Змінити NEXT_PUBLIC_API_URL на сервері після збірки - нічого не змінить у вже зібраних файлах. Один Docker-образ для staging і production з різними NEXT_PUBLIC_* не працюватиме як очікується;
  • динамічне звернення не підставляється: process.env[name] чи деструктуризація const { NEXT_PUBLIC_X } = process.env дадуть undefined у браузері.

Як передати конфігурацію під час виконання, якщо образ один на всі середовища:

  • читати змінні без префікса в серверному компоненті й передавати потрібні значення в клієнтські компоненти як props;
  • або ендпойнт конфігурації, з якого клієнт отримує налаштування.

Порядок файлів: .env.local (не в Git, перекриває все), .env.development / .env.production, .env. Змінні оточення процесу мають пріоритет над файлами.

Пастки безпеки:

  • випадково додати NEXT_PUBLIC_ до секрету - класичний витік ключа API;
  • серверний модуль з секретами, імпортований у клієнтський компонент, потрапляє в бандл - захист: пакет server-only у таких модулях дає помилку збірки при імпорті з клієнта.

Аналог у Vite (Laravel-проєкти) - префікс VITE_ і import.meta.env, з тими самими правилами: усе з префіксом публічне й фіксується при збиранні.

Докладніше в документації: Next.js: змінні оточення