Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке Nuxt.js і чим він відрізняється від Vue.js?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Nuxt.js** - це мета-фреймворк поверх Vue.js, який додає SSR, роутинг на основі файлів та авто-імпорти. Vue відповідає за UI; Nuxt обгортає його сервером і білд-пайплайном. **Ключове:** у Vue пишеш конфіг роутера вручну; Nuxt генерує роути з файлів у папці `pages/` автоматично.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Nuxt.js** - це мета-фреймворк побудований поверх Vue.js, який додає server-side rendering (SSR), роутинг на основі файлів та авто-імпорти. Структура папок стає повноцінним додатком без ручного написання налаштувань. ## Теорія ### TL;DR - Vue.js - це сире тісто: ти сам пишеш роутер, налаштовуєш SSR, підключаєш залежності. Nuxt - це готова форма: той самий Vue всередині, але він сам читає папку `pages/` і робить решту. - Головна різниця: Vue потребує ручного конфігу `vue-router`; Nuxt генерує роути з назв файлів. - Nuxt рендерить на сервері за замовчуванням. Vue рендерить у браузері. - Правило вибору: публічний сайт з SEO → Nuxt. Внутрішній дашборд без SEO → Vue. - Nuxt 3 використовує Nitro, який запускається на Node.js, Vercel або Cloudflare Workers без змін в коді. ### Швидкий приклад Найпомітніша різниця - роутинг. У Vue пишеш конфіг-файл. У Nuxt просто створюєш файл у правильній папці. **Vue.js (ручний роутинг):** ```js // main.js - все це пишеш сам import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import Home from './pages/Home.vue' import About from './pages/About.vue' const routes = [ { path: '/', component: Home }, { path: '/about', component: About } ] const router = createRouter({ history: createWebHistory(), routes }) createApp({}).use(router).mount('#app') ``` **Nuxt.js (роутинг на основі файлів):** ``` pages/ index.vue → / about.vue → /about products/ [id].vue → /products/:id (динамічний роут, без конфігу) ``` Жодного конфіг-файлу. Nuxt сканує `pages/` під час білду і генерує роутер сам. Відкриваєш `/about` - отримуєш `about.vue`, відрендерений на сервері. ### Ключова різниця Nuxt сканує `pages/`, `components/` і `composables/` через Vite, генерує конфіг Vue Router і серверний бандл Nitro. Коли приходить запит, Nitro запускає компонент сторінки на Node.js, отримує дані через `useAsyncData` або `useFetch` на сервері, і повертає готовий HTML. Vue гідратує його на клієнті без повторного запиту даних - Nuxt автоматично передає серверний payload разом з HTML. Google бачить реальний контент, а не порожній `<div id="app">`. ### Коли що використовувати - **Маркетинговий або продуктовий сайт** → Nuxt. Пошуковики мають читати контент, тому SSR важливий. - **Внутрішній дашборд або адмін-панель** → Vue. Без SEO, без сервера, простіший деплой. - **Статичний блог або документація** → Nuxt з `nuxt generate`. Пре-рендер в HTML, роздача з CDN. - **Headless e-commerce** → Nuxt з серверними роутами. Багато API, але сторінки товарів потребують індексації. - **Швидкий прототип** → Nuxt. Файловий підхід скорочує час налаштування до кількох хвилин. ### Таблиця порівняння | Функція | Vue.js | Nuxt.js (v3) | |---|---|---| | **Рендеринг** | Тільки на клієнті | SSR, SSG, SPA або гібрид на вибір | | **Роутинг** | Ручний конфіг `vue-router` | Автогенерація з папки `pages/` | | **Час старту** | 15-30 хв boilerplate | `npx nuxi init` → одразу готово | | **SEO** | Ручні `<meta>` або плагіни | Вбудований `useHead()` + серверний HTML | | **Отримання даних** | `onMounted` + `fetch` | `useFetch` / `useAsyncData` (з сервера) | | **Розбиття бандлу** | Ручне налаштування | Авто на кожну сторінку | | **Сервер** | Немає (додаєш сам) | Nitro (Node.js, Vercel, Cloudflare edge) | | **Авто-імпорти** | Ні | Так - composables, компоненти, утиліти | | **Коли брати** | SPA, бібліотеки, вбудовані віджети | Публічні сайти, e-commerce, full-stack | ### Як Nuxt обробляє запит Під час білду Vite-плагін Nuxt читає папку `pages/` і генерує конфіг Vue Router. Окремо компілюється серверний бандл Nitro. Коли приходить запит, Nitro знаходить відповідний компонент, запускає його на Node.js, виконує всі `useAsyncData` та `useFetch` виклики на сервері, серіалізує результат в HTML. Браузер отримує готову сторінку. Vue гідратує її без повторних запитів - дані вже передані в payload разом з HTML. ### Типові помилки **1. Отримання даних в `onMounted` для SSR-сторінок** Цей патерн - найпоширеніша помилка в код-рев'ю у розробників, які переходять з Vue SPA на Nuxt. ```vue <script setup> // Неправильно: виконується тільки на клієнті onMounted(async () => { data.value = await $fetch('/api/products') }) </script> ``` Сервер відправляє порожню сторінку. Пошуковики не бачать контенту. Користувач бачить миготіння перед появою даних. ```vue <script setup> // Правильно: виконується на сервері, дані вже в HTML const { data } = await useAsyncData('products', () => $fetch('/api/products')) </script> ``` **2. Пряме використання `window` або `document` в компонентах** ```vue <script setup> // Крашиться на сервері - в Node.js немає window const width = window.innerWidth </script> ``` Nuxt запускає компонент спочатку на Node.js. Там `window` не існує. ```vue <script setup> // Варіант 1: composable з VueUse (сам обробляє SSR) const { width } = useWindowSize() // Варіант 2: перевірка через process.client if (process.client) { const width = window.innerWidth } </script> ``` **3. API-ключі в `<script setup>`** ```vue <script setup> const key = 'sk-secret-123' // Потрапить в клієнтський бандл </script> ``` Nuxt пакує і серверний, і клієнтський JS. Ключ дістанеться до браузера. Використовуй `useRuntimeConfig()` - приватні ключі залишаються тільки на сервері, публічні йдуть в `runtimeConfig.public` у `nuxt.config.ts`. **4. Перевірка `process.client` всередині глобального middleware** ```ts // middleware/auth.global.ts export default defineNuxtRouteMiddleware((to) => { // Неправильно: пропуск серверної перевірки розкриває HTML захищеної сторінки if (process.client && !useCookie('token').value) { return navigateTo('/login') } }) ``` Без серверної перевірки Nuxt рендерить HTML захищеної сторінки і лише потім редиректить. Правильний варіант - прибрати `process.client` повністю. Сервер перехоплює запит ще до генерації HTML. ### Де використовується в продакшені - **Netflix (Voraz)**: Nuxt 2 для SSR-лендингів відео, пізніше мігрували на Nuxt 3 для edge-деплою через Nitro. - **Adobe Portfolio**: Статична генерація сайтів дизайнерів, роздача з CDN. - **Decathlon**: E-commerce каталог з `useAsyncData` для серверного рендерингу сторінок товарів. - **Nuxt Commerce**: Open-source Shopify headless стартер з серверними API-роутами і SSR. ### Питання на співбесіді **Q:** В чому різниця між `useFetch` і `useAsyncData` у Nuxt? **A:** `useFetch` - це скорочення, яке автоматично генерує ключ кешу з URL і викликає `useAsyncData` всередині. `useAsyncData` приймає ручний ключ і кастомну функцію-фетчер, що дає контроль над кешуванням і дедуплікацією. Для простих випадків - `useFetch`. Для кастомного фетчера або передбачуваного ключа - `useAsyncData`. **Q:** Що таке SSR і SSG у Nuxt і коли що обирати? **A:** SSR рендерить кожну сторінку на сервері під час запиту - підходить для динамічних даних: каталоги товарів, дашборди. SSG пре-рендерить сторінки під час білду і роздає статичний HTML з CDN - підходить для блогів, документації, маркетингових сторінок де контент змінюється рідко. Запускаєш `nuxt generate` і отримуєш статику. **Q:** Чим Nitro у Nuxt 3 відрізняється від сервера Nuxt 2? **A:** Nuxt 2 використовував кастомний сервер на базі Express. Nitro в Nuxt 3 - це окремий серверний рушій з екосистеми UnJS. Він компілюється в легкий бандл, який запускається на Node.js, Deno, Cloudflare Workers або Vercel Edge Functions без змін в коді додатку. **Q:** Vue 3 SPA працює нормально, але SEO страждає. Як мігрувати на Nuxt 3? **A:** Перемісти сторінки з `src/views/` в `pages/`, видали ручний конфіг `vue-router`, замінив `onMounted`-фетчинг на `useAsyncData`, додай `app.vue` як кореневий лейаут, запусти `npx nuxi upgrade`. Після міграції стеж за hydration mismatch - де використовував браузерні API без перевірки, буде помилка на сервері. Обгорни такі місця в `<ClientOnly>` або перевірку `process.client`. ## Приклади ### Сторінка товару з SSR та динамічним роутингом Файл `pages/products/[id].vue` автоматично обробляє будь-який URL вигляду `/products/:id`. Жодного конфігу роутів не потрібно. ```vue <!-- pages/products/[id].vue --> <script setup> const route = useRoute() // Виконується на сервері - дані вже в HTML до завантаження браузером const { data: product, pending } = await useAsyncData( `product-${route.params.id}`, () => $fetch(`/api/products/${route.params.id}`) ) // SEO-мета з серверних даних - Google бачить реальний заголовок useHead({ title: product.value?.name ?? 'Товар', meta: [{ name: 'description', content: product.value?.description }] }) </script> <template> <div v-if="pending">Завантаження...</div> <div v-else-if="product"> <h1>{{ product.name }}</h1> <!-- Заголовок вже є в серверному HTML - Google його проіндексує --> <img :src="product.image" :alt="product.name" width="300" /> <p>{{ product.description }}</p> </div> </template> ``` Сервер відправляє сторінку з назвою товару вже в HTML. Google індексує її. Клієнт гідратує без другого мережевого запиту - Nuxt автоматично передає payload `useAsyncData` разом з HTML. ### Auth middleware з серверним редиректом Цей момент дивує розробників, які прийшли з Vue SPA, де middleware завжди клієнтський. ```ts // middleware/auth.global.ts - запускається для кожного роуту, на сервері і клієнті export default defineNuxtRouteMiddleware((to) => { const token = useCookie('token') // Жодного process.client тут - це навмисно // На сервері: неавторизований користувач не отримує HTML захищеної сторінки if (!token.value) { return navigateTo('/login') } }) ``` У Vue SPA браузер рендерить захищену сторінку і лише потім редиректить - HTML вже був у пам'яті. З цим патерном Nuxt відправляє 302 редирект ще до генерації HTML сторінки. Швидше і безпечніше.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.