Skip to content

Статическая генерация сайтов (Static Site Generation - SSG) в Nuxt

Статическая генерация сайтов (SSG) - это режим развертывания Nuxt, при котором все необходимые HTML-файлы генерируются во время сборки проекта. В отличие от Server-Side Rendering (SSR), где HTML генерируется по запросу клиента, статические сайты уже готовы к отдаче браузеру без необходимости выполнять какой-либо серверный код.

Преимущества SSG

  • Высокая производительность: Статические файлы очень быстро загружаются браузером, так как нет задержки, связанной с генерацией HTML на сервере.
  • Улучшенное SEO: Поисковые боты могут легко индексировать предварительно сгенерированный HTML-контент.
  • Повышенная безопасность: Отсутствие серверной логики снижает поверхность атаки и устраняет многие распространенные уязвимости.
  • Простое и дешевое развертывание: Статические сайты можно размещать на CDN (Content Delivery Network) или на любом статическом хостинге, что обычно дешевле и проще, чем обслуживание Node.js сервера.
  • Отличный UX: Быстрая первоначальная загрузка страницы обеспечивает лучший пользовательский опыт.

Как работает SSG в Nuxt

При сборке проекта в режиме SSG (nuxt generate), Nuxt проходит по всем вашим страницам (определенным в каталоге pages) и генерирует соответствующий HTML-файл для каждого маршрута. Если ваши страницы зависят от динамических данных, Nuxt предоставляет механизмы для предварительной генерации этих данных во время сборки.

Настройка SSG

Чтобы использовать SSG, убедитесь, что в вашем файле nuxt.config.js установлен режим static:

javascript
export default {
  target: 'static', // Указываем Nuxt, что нужно генерировать статический сайт
  // ... другие настройки
}

Затем для сборки статического сайта выполните команду:

bash
npm run generate
# или
yarn generate

Nuxt создаст каталог dist/ с вашим статическим сайтом, готовым к развертыванию.

Предварительная генерация динамических маршрутов

Если у вас есть страницы с динамическими маршрутами (например, /posts/:id), Nuxt необходимо знать, для каких конкретных значений :id нужно сгенерировать HTML-файлы. Для этого используется хук asyncData или fetch в ваших страницах.

Пример с asyncData:

Предположим, у вас есть страница /posts/_id.vue, которая отображает информацию о посте с определенным ID. Вы можете предварительно сгенерировать HTML для нескольких постов следующим образом:

vue
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.body }}</p>
  </div>
</template>

<script>
export default {
  async asyncData({ $axios, params, error }) {
    try {
      const { data: post } = await $axios.$get(`/api/posts/${params.id}`);
      return { post };
    } catch (e) {
      error({ statusCode: 404, message: 'Пост не найден' });
    }
  },
}
</script>

Чтобы Nuxt знал, для каких id генерировать страницы, вам нужно предоставить функцию generate.routes в nuxt.config.js:

javascript
export default {
  target: 'static',
  modules: ['@nuxtjs/axios'],
  generate: {
    async routes() {
      const { data: posts } = await this.$axios.$get('/api/posts');
      return posts.map(post => `/posts/${post.id}`);
    },
  },
  // ... другие настройки
}

В этом примере generate.routes делает запрос к API для получения списка всех постов и затем возвращает массив маршрутов для предварительной генерации (/posts/1, /posts/2, и т.д.).

Пример с fetch:

vue
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.body }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      post: null,
      loading: true,
      error: null,
    };
  },
  async fetch() {
    try {
      this.post = await this.$axios.$get(`/api/posts/${this.$route.params.id}`);
    } catch (e) {
      this.error = 'Пост не найден';
    } finally {
      this.loading = false;
    }
  },
};
</script>

<script setup>
import { useAsyncData } from '#app';

const route = useRoute();
const { data: post, pending: loading, error } = useAsyncData(
  'post',
  () => $fetch(`/api/posts/${route.params.id}`)
);
</script>

В nuxt.config.js функция generate.routes остается аналогичной примеру с asyncData.

Получение данных во время сборки

Как вы видели в примерах выше, для предварительной генерации страниц с динамическими данными часто требуется получать эти данные во время сборки. Nuxt предоставляет доступ к различным инструментам и контексту внутри asyncData и fetch, а также в функции generate.routes в nuxt.config.js, включая $axios (если установлен модуль @nuxtjs/axios) и другие полезные утилиты.

Особенности SSG

  • API-запросы во время сборки: Любые API-запросы, выполняемые в asyncData, fetch или generate.routes, происходят во время сборки, а не на стороне клиента при каждом посещении страницы.
  • Интерактивность на стороне клиента: Хотя HTML генерируется статически, вы все равно можете добавлять интерактивность на стороне клиента с помощью Vue.js.
  • Динамические данные после загрузки: Если вам нужны динамические данные, которые часто обновляются, вы можете подгружать их на стороне клиента после первоначальной загрузки статической страницы.

Когда использовать SSG

  • Блоги и портфолио: Сайты с относительно статичным контентом, который редко меняется.
  • Документация: Сайты с большим количеством текстового контента.
  • Лендинговые страницы: Сайты, ориентированные на маркетинг и SEO.
  • Небольшие и средние веб-сайты: Большинство сайтов, где контент не требует постоянного обновления в реальном времени.

Ограничения SSG

  • Сложность с часто обновляемым контентом: Если ваш контент обновляется очень часто, перестройка и повторное развертывание всего сайта может быть неэффективным. В таких случаях может лучше подойти SSR или гибридный подход.
  • Время сборки: Для очень больших сайтов с большим количеством динамических маршрутов время сборки может значительно увеличиться.

Заключение

Статическая генерация сайтов (SSG) в Nuxt - это отличный способ создания быстрых, безопасных и SEO-дружественных веб-сайтов. Правильное использование nuxt generate и механизмов предварительной генерации данных позволяет создавать статические сайты даже с динамическим контентом, обеспечивая превосходный пользовательский опыт и простое развертывание.