Часть 1. Иллюзия Всё и сразу: Почему Nuxt падает на сервере?
Введение Вы пишете код в Nuxt 3. В браузере всё работает идеально. Вы делаете npm run build, запускаете сервер… и получаете window is not defined. Знакомо? Добро пожаловать в мир Universal Rendering.
🧩 Аналогия (предыдущий ресторан был не последним):
В ролях: вы (разработчик), кухня (сервер), заказ (Nuxt код), недоступные ингредиенты (браузерные API)
Итак, вы пришли в ресторан, заказываете пасту из меню, но с небольшим уточнением "положите сверху здорового лобстера". Заказ уходит поварам, но ребята на кухне недоумевают "да кто такой этот ваш лобстер??". В итоге вам вместо пасты приносят записку "lobster is not defined". То же самое происходит на сервере, когда мы пытаемся использовать браузерные API при SSR без дополнительных проверок. Разница лишь в том, что посетитель ресторана не должен знать о доступных ингредиентах на кухне в отличие от разработчика.
⚙️ Техническая суть В Nuxt 3 один и тот же код Vue выполняется дважды: сначала на сервере (Node.js/Nitro), чтобы сгенерировать HTML, а потом в браузере, чтобы оживить (гидратировать) его. Поэтому когда мы в приложении, например, обращаемся к localStorage из корня компонента - получаем ошибку на сервере.
Есть чуть менее очевидная проблема, чем прямое обращение к браузерным API - обращение к этим API внутри используемых библиотек. Например, библиотеки, которые строят графики/карты/редакторы зачастую делают что-то вроде document.createElement('canvas'). Вы просто импортируете Chart, а на сервере падает ошибка. Тут можно использовать встроенный Nuxt компонент <ClientOnly> или динамические импорты внутри onMounted
Главная проблема: на сервере нет браузера. Нет объектов window, document, localStorage. Если ваш код обращается к ним в корне компонента, сервер упадет.
💡 Советы по выживанию: 1. Изолируйте браузерный код: Используйте if (import.meta.client) или if (process.client) для проверок. 2. Ждите монтирования: Логика, зависящая от DOM или window, должна жить внутри хука onMounted(). Он гарантировано срабатывает только на клиенте. 3. Думайте универсально: Пишите код, который не зависит от окружения (там, где это возможно).
Заключение: SSR в Nuxt дает невероятный буст для SEO и скорости первого отображения (FCP). Но цена за это - дисциплина. Теперь помимо знания как центровать div, нужно еще и понимать, к чему есть доступ у сервера.
❓ Какая библиотека или API ломали ваш SSR? Делитесь в комментариях, посочувствуем