Деплой на GitHub Pages

Развёртывание на статическом хостинге требует учёта особенностей путей к ресурсам. GitHub Pages обслуживает сайт из подкаталога репозитория, поэтому базовый путь приложения должен быть явно задан.

В Vite ключевым параметром становится base в конфигурации:

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  base: '/repo-name/',
})

Значение base определяет префикс для всех ассетов: скриптов, стилей, изображений и динамически загружаемых модулей. Без корректной настройки приложение может корректно работать локально, но терять ресурсы после публикации.

Для пользовательских доменов используется значение:

base: '/'

Сборка проекта

Процесс сборки формирует оптимизированный набор статических файлов:

npm run build

По умолчанию Vite создаёт директорию dist, содержащую:

  • HTML entry point
  • собранные JS-модули
  • CSS-чанки
  • статические ресурсы
  • манифест сборки (если используется)

Особенность сборки Vite заключается в использовании Rollup под капотом, что обеспечивает корректное разделение чанков и tree-shaking.

Перед публикацией важно убедиться, что пути в dist/index.html соответствуют базовому URL.


Размещение на GitHub Pages

GitHub предоставляет встроенный механизм публикации статических сайтов через сервис GitHub Pages.

Существует несколько стратегий деплоя:

Ветка gh-pages

Один из классических подходов — публикация содержимого dist в отдельную ветку.

Установка инструмента:

npm install -D gh-pages

Добавление скриптов:

{
  "scripts": {
    "build": "vite build",
    "deploy": "npm run build && gh-pages -d dist"
  }
}

Запуск публикации:

npm run deploy

После выполнения содержимое dist отправляется в ветку gh-pages, которая указывается в настройках репозитория как источник Pages.


Папка docs

Альтернативный способ — использование директории docs в основной ветке:

// vite.config.js
export default defineConfig({
  build: {
    outDir: 'docs'
  },
  base: '/repo-name/'
})

После сборки необходимо закоммитить docs в репозиторий и выбрать его как источник GitHub Pages.

Подход упрощает инфраструктуру, но загрязняет основную ветку сборочными файлами.


GitHub Actions и автоматический деплой

Современный способ публикации основан на CI/CD через GitHub Actions.

Пример workflow:

name: Deploy Vite App

on:
  push:
    branches:
      - main

jobs:
  build-deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install dependencies
        run: npm install

      - name: Build project
        run: npm run build

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v4
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./dist

Этот подход устраняет необходимость ручного деплоя и гарантирует синхронизацию состояния репозитория и опубликованного сайта.


Особенности SPA и маршрутизации

Одностраничные приложения, собранные на Vite, часто используют клиентский роутинг (например, Vue Router или React Router). GitHub Pages не поддерживает fallback на index.html для всех маршрутов.

Типичная проблема:

/about → 404 Not Found

Решения:

Hash-роутинг

Самый простой вариант:

https://site.github.io/#/about

Маршруты после # обрабатываются только клиентом, сервер их игнорирует.


404 fallback hack

Создаётся файл 404.html, копия index.html:

cp dist/index.html dist/404.html

GitHub Pages будет отдавать 404.html, что позволяет приложению перехватывать маршруты и восстанавливать состояние.


Настройка путей для ассетов

При использовании относительных путей важно учитывать структуру сборки:

  • абсолютные пути требуют корректного base
  • динамические импорты должны учитывать окружение
  • изображения в public/ доступны напрямую

Пример:

const imgUrl = import.meta.env.BASE_URL + 'logo.png'

Кэширование и обновление версий

GitHub Pages активно кэширует статику через CDN. Vite автоматически добавляет хэши в имена файлов:

assets/index.a1b2c3.js

Это обеспечивает:

  • безопасное обновление без ручного инвалида кеша
  • параллельное хранение версий
  • отсутствие конфликтов при частичных обновлениях

Монорепозитории и относительный base

В монорепо структурах базовый путь часто зависит от подпапки:

/apps/frontend
/apps/admin

Конфигурация:

base: '/frontend/'

При изменении структуры важно синхронизировать:

  • vite.config.js
  • настройки GitHub Pages
  • ссылки в роутере

Пользовательский домен

При использовании кастомного домена в корне dist добавляется файл CNAME:

example.com

И в конфигурации Vite:

base: '/'

DNS-настройки должны указывать на GitHub Pages:

  • A-записи или CNAME в зависимости от схемы

Частые ошибки деплоя

Некорректный base:

  • ресурсы загружаются с /assets/... вместо /repo/assets/...

Отсутствие build перед deploy:

  • публикация пустого или устаревшего dist

SPA routing 404:

  • отсутствие 404.html
  • отсутствие hash-роутинга

Кэш CDN:

  • обновления не видны сразу после деплоя

Неверная ветка Pages:

  • указана не gh-pages или не docs

Оптимизация структуры публикации

При стабильной конфигурации обычно фиксируется следующий поток:

  • исходный код в main
  • сборка через Vite
  • публикация через Actions
  • статический результат в Pages

Такой подход минимизирует ручные операции и обеспечивает детерминированность каждого деплоя.