Как настроить SSG и SSR на nuxt

Всё что нужно знать о nuxt.js

Denis Grushkin
Mad Devs — блог об IT
8 min readApr 20, 2021

--

Как настроить SSG и SSR на nuxt.

Как только я начал изучать Vue, я был приятно удивлён этим фреймворком. Он оказался очень простым и легким в освоении. Его API имел достаточно функционала для решения повседневных задач. В общем, я был в восторге.

Но однажды, когда мне понадобилось настроить сайт под SEO, внутренних инструментов Vue не хватило. Пришлось окунаться в глубины интернета, где я и нашёл фреймворк, который до сих пор не перестаёт меня удивлять.

Nuxt.js – это многофункциональный, интуитивно понятный фреймворк, или очень качественная надстройка над Vue. Его основная задача – упростить жизнь разработчику, дав все необходимые инструменты для создания сайтов любой сложности.

Предлагаю сегодня кратко ознакомиться с его основными возможностями.

Итак, в этой статье поговорим о:

  1. Базовой структуре файлов и папок
  2. Файле настроек nuxt.config.js
  3. Настройках SEO
  4. Роутах
  5. Плагинах
  6. Хранилище
  7. SSG
  8. SSR

Отдельно покажу, как настроить SSG, SSR на продакшне и создать собственный API с помощью nuxt сервера.

Разбираемся с файлами и папками

Nuxt подготовил для нас готовую структуру, где большинство файлов и папок привязаны к определённому функционалу.

С одной стороны это позволяет не задумываться, где и как хранить файлы, с другой стороны может показаться, что nuxt ограничивает нас. Но скажу по своему опыту, проблем пока не было.

  • .nuxt – это папка. В реальном времени nuxt собирает в неё откомпилированные, но еще не сжатые файлы. При запуске команд npm run dev или npm run build будут использоваться файлы именно из этой папки.
  • components – папка для компонентов страниц. Кнопки, инпуты, селекты и т.д.
  • layouts – обёртки для страниц. Иногда может понадобиться обёртка с сайдбаром слева, например, для админ панели, но в тоже время сайдбар не нужен на страницы авторизации. В этом случае нам и помогут разные лайауты – с сайдбаром и без.
  • middlewares – папка для функций, которые должны запускаться до рендера лайаута или страниц. Через них можно, например, проверять, имеет ли пользователь доступ на определённую страницу, и если нет, то перенаправлять его на специальную страницу.
  • pages – папка для страниц. Созданные в ней файлы преобразуются в роуты. Настраивать ничего не нужно. Подробнее об этом написал ниже.
  • plugins – все плагины, которые будут устанавливаться в проект, должны находиться в этой папке. Это не обязательно, просто так принято.
  • static – папка, в которой обычно хранят фавиконку, различные манифесты, иконки для метаданных и т.д. Файлы в этой папке будут доступны по прямой ссылке, например, http://localhost:3000/favicon.ico
  • store – временное хранилище, которое позволяет централизовать данные.
  • nuxt.config.js – это основной файл настроек. С него и начнем.

Основной файл настроек

nuxt.config.js – этот файл является точкой входа, в котором настраивается буквально всё. Располагается он в корне проекта. Там вы добавляете метаданные, подключаете плагины, настраиваете сервер, конфигурируете webpack, подключаете env переменные и т.д.

Чтобы env переменные были доступны в этом файле, нужно установить библиотеку dotenv и импортировать её в начале файла, вот так:

require('dotenv').config()...module.exports = {
env: {
API_URL: process.env.NODE_API_URL
}
}

Далее в блок env можно добавлять переменные.

Если ещё понадобится какая-то библиотека в этом файле, например lodash, её так же устанавливаем и импортируем в начале файла.

Настройки для SEO

При разработке сайта на Vue я столкнулся с такой проблемой, что не смог настроить метаинформацию отдельно для каждой станицы. Пришлось искать плагины, настроить генерацию html-файлов для каждого роута, короче заниматься поиском. Таким образом я и познакомился с nuxt.

Он позволяет настроить как общие метаданные для всех страниц, так и отдельные для каждой.

Общие настраиваются в файле nuxt.config.js, в блоке head. Вот пример

head: {
htmlAttrs: {
lang: 'en'
},
title: 'My site',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'yandex-verification', content: 'xxx' },
{ name: 'facebook-domain-verification', content: 'xxx' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'sitemap', type: 'application/xml', href: 'https://localhost/sitemap.xml' }
],
scripts: [
{ src: 'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver' }
]
}

Настройки для отдельной страницы указываются в файле страницы, в папке pages.

export default {
name: 'Page',
head() {
bodyAttrs: {
class: 'page-1'
}
meta: [
{ name: 'description', content: 'description' },
{ property: 'og:url', content: 'url' },
{ property: 'og:type', content: 'website' },
{ property: 'og:title', content: 'title' },
{ property: 'og:description', content: 'description' },
{ property: 'og:image', content: 'image' }
],
link: [
{ ... }
],
scripts: [
{ ... }
]
}
}

Более подробно можно ознакомиться с настройками метаданных на этой странице.

Создание роутов

Как писал выше, в папке pages мы создаём страницы. Это делается просто. Если вы добавите в эту папку файл с названием Blog.vue, nuxt создаст новый роут – http://localhost:3000/blog – это и будет ссылкой на страницу блога.

Если вам нужно будет создать страницу, которая будет отвечать за отдельный пост в блоге, то это можно сделать так:

  1. В папке pages создать папку blog
  2. В папку blog добавить два файла – index.vue и _id.vue
  3. Файл index.vue будет отвечать за список постов, _id.vue за отдельный пост
  4. Если всё настроено правильно, то по ссылке http://localhost:3000/blog/:id, где вместо :id будет id нужно поста, откроется страница поста.

Добавление плагинов

Так как nuxt имеет несколько режимов работы, не все плагины могут быть подключены прямо в компоненты. Это связанно с тем, что компоненты предварительно обрабатываются на сервере, где отсутствует объект window, document и в целом браузерный API. Из-за чего будут сыпаться ошибки.

Для решения этой проблемы в файле nuxt.config.js есть специальный массив – plugins, в который подключаются все плагины.

Давайте подключим какой-нибудь для примера. В папке plugins создайте файл с название пакета, я установил v-tooltip. В файл добавьте следующие настройки:

import Vue from 'vue'
import VTooltip from 'v-tooltip'

Vue.use(VTooltip)

После чего перейдем в nuxt.config.js, подключим наш новый плагин.

plugins: [
{ src: '~/plugins/vtooltip.js', mode: 'client' }
]

Обратите внимание на ключ mode: я специально его указал, чтобы сказать nuxt, что этот плагин должен запускаться только на стороне клиента, там, где есть браузерный API. Если добавить в ключ mode значение server, плагин будет запускаться только на стороне сервера. На клиент он не попадёт.

Хранилище

Под капотом используется Vuex.

Команда разработчиков nuxt и тут решила упростить нам жизнь, написав дополнительную надстройку для Vuex, которая помогает писать меньше кода, а значит и меньше багов.

Чтобы добавить модуль в nuxt хранилище, достаточно в папке store создать новый файл, в котором надо расписать переменные, экшены, мутации и геттеры. Название этого файла будет названием модуля, которое будем вызывать в коде, чтобы получать нужные данные.

Ниже покажу пример модуля, где запрашивается список продуктов по API:

// products.jsexport const state = () => ({
loaded: false,
list: []
})
export const mutations = {
SET_DATA(state, data) {
state.list = data
},
SET_LOADED_STATUS(state, status) {
state.loaded = status
}
}
export const actions = {
async getProducts({ commit }) {
try {
const products = API.GetProducts() // делаем запрос к api
commit('SET_DATA', products)
commit('SET_LOADED_STATUS', true)
} catch (err) {
if (err) throw err
}
}
}
export const getters = {
products(state) {
return state.list
}
}

И где-нибудь в коде пытаемся получить эти данные:

// Home.vue<template>
<div>
{{ productsList }}
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
name: 'Home',
computed: {
...mapState('products', {
productsList: 'list',
}),
},
created() {
this.getProducts()
},
methods: {
...mapActions('categories', ['getProducts']),
}
}
</script>

SSG

Static site generation – этот способ развертывания проекта больше подходит для сайтов, которые не имеют динамических страниц.

Суть SSG проста – при сборке проекта на продакшн будут генерироваться готовые html-файлы в папку dist. С ними мы и будем работать дальше. Только нужно будет добавить собственный сервер, который будет запускать проект (об этом расскажу ниже).

SSR

Server side rendering – будет лучшим решением для проекта, где страницы создаются налету, то есть через админ-панель, например, страницы блога.

В случае с SSR на продакшне будет запущен встроенный в nuxt сервер, который обеспечит генерацию новых html-файлов в реальном времени при получении новых данных, например, по API. Вам не придётся ничего перезапускать или настраивать на хостинге, nuxt берёт эту ответственность на себя.

Ну вот мы и добрались до основной темы статьи, где будем настраивать проект под два разных типа работы.

Настройка SSG сервера

Нам понадобится Express сервер.

Установим и добавим настройки для него.

npm i express

В корне проекта нужно создать файл index.js – он будет хранить в себе все настройки сервера.

const express = require('express');
const app = express();
const path = require('path');
const port = process.env.PORT || 5000;app.use(express.static('dist'));app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
});
app.listen(port, () =>
console.log(`Server is running on: http://localhost:${port}`));

Далее в файле nuxt.config.js нужно указать для ключа target значение static. Это будет значить, что nuxt будет работать в режиме генерации html-файлов в папку dist. На эту папку мы и натравили наш сервер.

Также в файле настроек придётся перечислить все страницы, которые должны быть сгенерированы. Найдите ключ generate и укажите нужные страницы.

generate: {
routes: ['/', '/about']
}

В этом случае будет сгенерирована главная страница и страница About.

Ну и остаётся запустить команду

npm run generate

В папке dist будут созданы css, js и html файлы, то есть всё что необходимо. Причем это всё будет сжато и оптимизировано.

Если вам нужно настроить проект на хостинге, предлагаю ознакомиться с одной из моих статей. Она поможет быстро и без проблем запустить ваш проект, который будет полностью готов к продакшну.

https://maddevs.io/blog/how-to-deploy-a-project-on-heroku

Но это еще не всё. Я крайне рекомендую познакомиться с проектом, где до недавнего времени был настроен SSG. Там вы сможете найти всё, что понадобится, если вдруг вы тоже захотите настроить SSG в своём проекте.

Настройка SSR сервера

Настройка SSR на самом деле проще, чем SSG, так как nuxt предоставляет свой сервер. Нам не придётся устанавливать express или настраивать что-то – всё готово и настроено.

Чтобы его запустить, достаточно выполнить три шага:

  1. В файле nuxt.config.js поменять значение для ключа target со static на server.
  2. Выполнить команду npm run build – она оптимизирует все файлы в папке .nuxt, за которой будет наблюдать сервер
  3. Ну и запустить сам сервер командой npm start или nuxt start

При успешном старте в консоли будет следующее сообщение

   ╭────────────────────────────────────────────╮
│ │
│ Nuxt @ v2.15.2 │
│ │
│ ▸ Environment: production │
│ ▸ Rendering: server-side │
│ ▸ Target: server │
│ │
│ Memory usage: 61.2 MB (RSS: 176 MB) │
│ │
│ Listening: http://localhost:3000/
│ │
╰────────────────────────────────────────────╯

По сообщению видно: nuxt указал, что запущен в режиме production, где всё оптимизировано и сжато.

Теперь вам не нужно указывать в generate какие страницы генерировать. Nuxt будет создавать html налету.

Собственный API на nuxt сервере

Настроив SSR, мы можете создавать собственный API, что даёт ещё больше возможностей.

Например, на сайте есть форма, которая должна отправлять данные на почту. Чтобы не расписывать всю логику на стороне фронта и не светить токены, можно будет создать отдельный API-поинт, написать для него простенький smtp сервер и спокойно слать на него запросы. При этом мы не будем грузить фронт дополнительным кодом + все токены будут лежать на стороне сервера, что намного безопаснее, ну и не нужно будет платить за сторонний API, который будет делать те же самые вещи, только за деньги.

Давайте настроим.

В первую очередь создадим две папки. Одна общая – server, в которой будут находится все файлы сервера, вторую – middlewares добавим в папку server, она нужна для API-поинтов.

Создадим в папке middlewares файл с название logger.js и вставим туда простенький код.

export default function (req, res, next) {
console.log('Hello world!')
next()
}

Когда будем обращаться к нему, он будет всего лишь выводить сообщение в консоль. Для примера пойдет.

Далее в файле nuxt.config.js добавим новый ключ serverMiddleware. В нём нужно указать путь до API-поинта и адрес, по которому он будет доступен.

serverMiddleware: [
{ path: '/api/log', handler: '~/server/middlewares/logger.js' }
]

Теперь, если делать запрос по адресу http://localhost:3000/api/log, в консоли увидим сообщение “Hello world!”

Таким образом можно писать любые обработчики, которые помогут облегчить логику на стороне фронта, сделав её проще, доступнее и быстрее.

Заключение

Всё, о чем я писал выше, можно посмотреть на реальном примере, по этой ссылке. Мы активно работаем над нашим сайтом, где стараемся применять всё лучшее, что даёт Nuxt. Там вы можете более детально ознакомиться с SSR.

Я рекомендую почитать официальную документацию Nuxt, она имеет еще много чего интересного.

Спасибо!

--

--