Олег Марков
Создание серверных приложений на Vue с помощью Nuxt js
Введение
Создание современных веб-приложений требует не только красивого интерфейса, но и высокой производительности, SEO-оптимизации и безопасности. При разработке сложных SPA (Single Page Application) на Vue многие сталкиваются с трудностью реализации серверной логики, эффективной маршрутизации и предварительной загрузки данных для SEO. Nuxt.js — это фреймворк, который расширяет возможности Vue, позволяя строить полноценные серверные приложения, в том числе сочетающие SSR (Server Side Rendering) и статическую генерацию. Здесь вы узнаете, как начать создавать серверные приложения на Vue с помощью Nuxt.js, в чем его преимущества и какие ключевые возможности он предлагает для реальных задач.
Что такое Nuxt.js
Nuxt.js — прогрессивный фреймворк на базе Vue.js, предназначенный для создания универсальных приложений. Основная задача Nuxt — автоматизировать и упростить организацию работы с:
- SSR (рендеринг на сервере)
- статической генерацией страниц
- маршрутизацией и структурой директорий
- предварительной загрузкой данных
- интеграцией API на сервере
Nuxt подходит как для проектов, где нужен SEO (например, блоги, маркетплейсы, корпоративные сайты), так и для динамических веб-приложений с богатой клиентской логикой.
В основе Nuxt лежит концепция “конфигурируй по желанию, работай из коробки”, что помогает быстро стартовать с минимальными настройками, расширяя проект по мере роста требований.
Отличие Nuxt.js от Vue
Если вы уже работали с Vue, возможно, делали SPA с vue-cli
или vite
. Но сразу при масштабировании приложения возникали задачи:
- автоматическое разделение кода (code splitting)
- мощная маршрутизация
- SEO-оптимизация
- универсальность эндпойнтов для API
Во Vue эти элементы реализуются вручную, что усложняет поддержку. Nuxt.js берет на себя эти задачи:
- Автоматически создает роуты на основе файловой структуры
- Инкапсулирует логику SSR — не нужно вручную настраивать сервер
- Предоставляет API-роуты через serverMiddleware или Nitro (в Nuxt 3+)
- Позволяет легко интегрировать middlewares, плагины и модули
Давайте посмотрим, как это реализовано на практике.
Структура серверного приложения на Nuxt.js
В Nuxt основная работа строится вокруг отдельных директорий:
pages/
— любые.vue
-файлы автоматически становятся роутамиcomponents/
— переиспользуемые компоненты (не роуты)server/
— функции и API эндпойнты в Nuxt 3+ (подробнее ниже)plugins/
— подключаемые плагиныmiddleware/
— промежуточная логика
Например, структура приложения может выглядеть так:
my-app/
pages/
index.vue
about.vue
users/
_id.vue
components/
Navbar.vue
server/
api/
hello.js
nuxt.config.ts
package.json
Теперь давайте поймем, как включается рендеринг на сервере и создаются серверные эндпойнты.
Рендеринг на стороне сервера (SSR) в Nuxt.js
SSR означает, что HTML-страницы обрабатываются и генерируются на сервере, а не на клиенте (в браузере), что помогает:
- Улучшать SEO (поисковые роботы видят сразу готовый HTML)
- Повышать производительность первой загрузки
- Позволять предзагружать данные до передачи страницы пользователю
Nuxt поддерживает разные режимы работы:
SSR (default)
“Universal” — сервер генерирует готовый HTML, дальше клиент берет управление (гидратация).Single Page Application (SPA)
Весь рендеринг выполняется на клиенте, сервер только отдает статические файлы.Статическая генерация (SSG)
На этапе сборки формируются статические HTML-страницы для каждого маршрута.
Чтобы включить/выключить SSR, укажите флаг в nuxt.config.ts
:
// nuxt.config.ts
export default defineNuxtConfig({
ssr: true, // для SSR или false для SPA
})
Большинство возможностей по универсальной отрисовке реализованы “под капотом” — вы просто пишете страницы и компоненты, а Nuxt сам заботится о рендеринге там, где это требуется.
Создание серверных API с помощью Nuxt.js
В современных Nuxt (3+) появилась директория server/
, в которой можно размещать собственные API эндпойнты на Node.js. Это позволяет держать клиентский и серверный код рядом, не разносить проекты, и быстро обмениваться данными без внешнего бэкенда.
Добавление API эндпойнта
Смотрите, как можно создать API-эндпойнт:
// server/api/hello.js
export default defineEventHandler(async (event) => {
// Получаем клиентский IP, как пример серверной логики
const ip = event.node.req.socket.remoteAddress
return { message: `Hello from server! Your IP is ${ip}` }
})
- Любой файл в
server/api/
становится эндпойнтом по соответствующему маршруту: этот файл —/api/hello
- Вы можете обрабатывать методы запроса, заголовки, получать тело запроса через утилиты Nuxt
Теперь вы можете выполнить запрос с клиента:
// В компоненте/странице
const { data } = await useFetch('/api/hello')
Этот подход делает развитие серверной логики очень удобным. Не требуется настраивать отдельный бэкенд: вы пишете серверные функции там же, где клиентскую логику.
Асинхронная загрузка данных в компонентах
Nuxt встраивает удобные хелперы для получения серверных данных до рендера компонента. Попробуйте следующее:
<template>
<div>
<p>{{ data.message }}</p>
</div>
</template>
<script setup>
const { data, pending, error } = await useFetch('/api/hello')
</script>
- Функция
useFetch
автоматически выполняет серверный запрос при SSR, на клиенте — после гидратации. - Полученные данные становятся доступными до первого рендера — это ускоряет загрузку.
Продвинутая серверная логика: middleware и обработка запросов
Часто нужно проверять авторизацию, логгировать действия или изменять объекты запроса до передачи в конечный обработчик. Для этого Nuxt предлагает промежуточные серверные функции (server middleware).
Пример: проверка авторизации
Создадим middleware для серверных эндпойнтов:
// server/middleware/auth.js
export default eventHandler(async (event) => {
// Проверяем наличие cookie 'token'
const token = getCookie(event, 'token')
if (!token) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
}
})
Чтобы применить middleware к определенному API-роуту:
// server/api/protected.js
import auth from '../middleware/auth.js'
export default defineEventHandler(async (event) => {
await auth(event) // защита маршрута
// Основная логика эндпойнта ниже
return { message: 'Вы авторизованы' }
})
Здесь вы видите, как просто подключать промежуточную логику для отдельных эндпойнтов.
Работа с внешними базами данных
Любой эндпойнт в server/api/
— это полноценная серверная функция, где допустим импорт Node.js модулей, любых библиотек для работы с БД (например, Prisma, Sequelize, mongoose, pg, mysql2 и т.д.).
Пример с MongoDB:
// server/api/users.js
import { MongoClient } from 'mongodb'
const client = new MongoClient('mongodb://localhost:27017')
const dbName = 'mydb'
export default defineEventHandler(async (event) => {
await client.connect()
const db = client.db(dbName)
const users = await db.collection('users').find().toArray()
return users
})
- Здесь реализован API-эндпойнт
/api/users
, который возвращает список пользователей из MongoDB. - Вы можете обрабатывать любые методы (GET/POST/PUT/DELETE), парсить тело, работать с куками и сессиями.
Динамические маршруты и параметры
В директории pages/
структура файлов определяет ваши пользовательские маршруты.
Например:
pages/
users/
_id.vue
Это создаст маршрут /users/:id
. Внутри компонента получите параметр так:
<script setup>
const route = useRoute()
const userId = route.params.id
</script>
Можно асинхронно загружать данные пользователя по его id:
<script setup>
const route = useRoute()
const { data } = await useFetch(`/api/users/${route.params.id}`)
</script>
При SSR эти данные также будут загружены до рендера страницы.
Интеграция клиентских и серверных библиотек
Nuxt поддерживает подключение сторонних npm-библиотек — как для клиента, так и для сервера. Если библиотека использует Node API, импортируйте её в серверных файлах или эндпойнтах, а не в браузерном коде.
Например, работа с JWT на сервере:
// server/api/login.js
import jwt from 'jsonwebtoken'
export default defineEventHandler(async (event) => {
const body = await readBody(event)
// Проверка логина/пароля...
const token = jwt.sign({ userId: body.userId }, 'секретка')
setCookie(event, 'token', token)
return { ok: true }
})
Деплой и запуск серверного Nuxt-приложения
Nuxt можно запускать:
- В Dev-режиме (разработка):
nuxi dev
- В production-сборке:
- Сборка проекта:
nuxi build
- Запуск:
nuxi preview
или (используя Node.js сервер)node .output/server/index.mjs
- Сборка проекта:
Можно развернуть приложение где угодно: на Vercel, Netlify, Heroku, собственном VPS, в Docker-контейнере. Nuxt поддерживает auto adapter'ы для популярных платформ.
Лучшая практика — разделение логики и отказоустойчивость
Работая с серверным кодом, старайтесь:
- Разделять клиентскую и серверную логику (не импортируйте Node-модули в компоненты, которые исполняются в браузере)
- Обрабатывать все нестандартные случаи (ошибки при запросах к БД, отсутствие данных, невалидные куки)
- Использовать environment переменные для секретов (например, через
.env
) - Структурировать большие проекты с помощью модулей или слоёв
Предварительная загрузка данных (pre-fetching)
Nuxt позволяет предварительно загружать любые данные как для сервера, так и для клиента. Для этого используйте useAsyncData
или useFetch
внутри компонента или страницы.
<script setup>
const { data, pending, error } = await useAsyncData('key', () => $fetch('/api/data'))
</script>
- Всё, что возвращает сервер, автоматически сериализуется для передачи между сервером и клиентом
- Это упрощает построение динамических, но быстро загружаемых страниц
Заключение
Nuxt.js — это мощный фреймворк, делающий разработку серверных приложений на Vue гораздо проще и быстрее. Здесь вы получили обзор основных механизмов Nuxt: автоматическая организация роутинга, легкая интеграция серверной логики, рендеринг на сервере и работа с асинхронными данными. С его помощью вы сможете строить как оптимизированные для поисковиков сайты, так и полноценные full-stack решения, не разделяя проекты на клиентский и серверный. Nuxt отлично подходит для проектов любого масштаба благодаря модульной архитектуре и большому количеству готовых плагинов.
Частозадаваемые технические вопросы и ответы
Как подключить внешние API или собственный сервер?
Если вам нужно проксировать запросы к внешнему API — используйте серверные эндпойнты Nuxt в server/api/
и в них делайте HTTP-запросы с помощью fetch
или сторонних библиотек вроде axios
. Для сложных сценариев можно использовать proxy-модули, либо разворачивать отдельный Serve Middleware.
Можно ли использовать WebSockets в серверной части Nuxt?
Да, но только вне стандартных API-эндпойнтов. Для работы с WebSockets интегрируйте свой сервер (например, на ws
), используя серверные хуки Nuxt или запуск через serverMiddleware
. Внимательно разграничивайте зоны работы SSR и своего исходного WebSocket-сервера.
Как управлять сессиями и куками?
Для работы с куками используйте функции getCookie
и setCookie
(доступны из пакета h3
, который используется внутри Nuxt server). Для полноценной работы сессий можно подключить сторонние пакеты (например, iron-session
). Все манипуляции сессиями и куки лучше делать в файлов server/api/ или server/middleware/.
Как решать проблему "Cannot find module '...' " при импорте в серверный код?
Убедитесь, что устанавливаете серверные зависимости (npm install ...
) и импортируете их строго в server-файлах. Импорт серверных пакетов в клиентские компоненты приведет к ошибке в браузере.
Где задавать переменные окружения?
Nuxt автоматически подхватывает переменные из .env
, либо из системных переменных. Используйте внутри серверного кода — через process.env.NAME
. Для передачи переменных на клиент используйте префикс NUXT_ в название переменной, тогда она будет доступна глобально (например, NUXT_API_URL).