Files
homepage/spec/migration.md

322 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# План миграции сайта vakhrushev.me с Sculpin на Astro
## Обзор текущего состояния
### Стек
- **Генератор**: Sculpin 3 (PHP 8)
- **Шаблоны**: Twig (base → internal → article, три уровня наследования)
- **Фронтенд**: Webpack 4, SCSS, Vue 2 (интерактивная демка гадалки)
- **Сборка**: Docker (PHP + Node контейнеры), Taskfile
- **Деплой**: Docker-образ nginx, Ansible на личный сервер
- **Аналитика**: Яндекс.Метрика
- **Шрифты**: Google Fonts (PT Serif, Source Code Pro), Font Awesome 5
- **Кастомные бандлы Sculpin**: HtmlPrettier, SiteMap, TwigExtension (hashed_asset)
### Контент
- 8 статей в markdown (2019-2020), русский язык
- 1 статья с интерактивным Vue-компонентом (гадалка Шеннона)
- Страницы: главная, список статей, 404
- Atom-лента (ручной шаблон)
- Sitemap (кастомный бандл + шаблон)
- robots.txt
### Структура стилей
- Переменные SCSS: шрифт PT Serif 20px, ширина 740px, цвета GitHub
- Базовые стили, стили главной, стили внутренних страниц, навигация
- BEM-подобная методология
---
## Принятые решения
- **URL статей**: упрощаем до `/articles/slug/`, старые URL (`/articles/YYYY/MM/DD/slug/`) — 301-редиректы в nginx
- **Пакет `@anwinged/predictor`**: чистый TypeScript, без привязки к фреймворку — миграция на Vue 3 затрагивает только обёртку
- **Tailwind CSS**: используем; Tailwind 4 делает tree-shaking из коробки — в сборку попадают только используемые утилиты
- **Текст на главной**: переносим как есть, автор обновит сам
- **Галерея**: один альбом с фотографиями, хранение в `src/content/gallery/` (оптимизация через Astro Image)
- **Локальная разработка**: всё через Docker (и dev, и build), npm на хосте не используем
## Целевое состояние
### Стек
- **Генератор**: Astro
- **Стилизация**: Tailwind CSS 4
- **Интерактивность**: Vue 3 (islands, для гадалки и будущих компонентов)
- **Сборка**: Docker (один Node-контейнер), Taskfile
- **Деплой**: Docker-образ nginx, Ansible (без изменений)
### Разделы сайта
1. **Главная** — краткое описание, ссылки
2. **Блог** — статьи и эссе по программированию
3. **Галерея** — один альбом с избранными фотографиями
---
## Задачи
### Этап 1. Инициализация проекта Astro
#### 1.1. Создать проект Astro
- Инициализировать Astro в корне проекта (или в отдельной ветке)
- Настроить `astro.config.mjs`: site URL `https://vakhrushev.me`, язык `ru`
- Установить интеграции: `@astrojs/sitemap`, `@astrojs/rss`, `@astrojs/vue`, `@astrojs/tailwind`
- Настроить TypeScript (strict или relaxed — на усмотрение)
#### 1.2. Настроить Tailwind CSS 4
- Установить и настроить Tailwind 4 (tree-shaking из коробки — в сборку попадает только используемый CSS)
- Перенести дизайн-токены из SCSS-переменных в Tailwind-конфигурацию (через `@theme` в CSS):
- Шрифты: PT Serif (serif), Source Code Pro (mono)
- Цвета: `#24292e` (текст), `#0366d6` (ссылки), `#e6e6e6` (линии)
- Ширина контента: 740px
- Размер шрифта: 20px базовый
#### 1.3. Настроить Docker для сборки
- Заменить два Docker-образа (PHP + Node) одним Node-образом
- Использовать актуальную LTS-версию Node (22)
- Удалить PHP Dockerfile — он больше не нужен
- Сохранить `Dockerfile.nginx.prod`, обновить путь: `dist/` вместо `output_prod/`
#### 1.4. Обновить Taskfile
- Убрать задачи: `composer`, `sculpin`, `shell-node`, `format-php`
- Обновить задачи сборки:
- `build-prod`: `astro build`
- Добавить задачу `dev`: запуск `astro dev` для локальной разработки (через Docker с проброшенными портами)
- Обновить задачу `deploy`: путь к собранным файлам `dist/`
- Сохранить структуру Docker-команд через Taskfile
- Все npm/astro-команды выполняются внутри Docker-контейнера
---
### Этап 2. Лейауты и компоненты
#### 2.1. Создать базовый лейаут `BaseLayout.astro`
Аналог текущего `base.html.twig`. Должен включать:
- `<html lang="ru">`, мета-теги (charset, viewport, description, keywords)
- Open Graph мета-теги (og:site_name, og:title, og:description, og:url, og:locale)
- Подключение шрифтов Google Fonts (PT Serif, Source Code Pro)
- Яндекс.Метрика (вынести в отдельный компонент `YandexMetrika.astro`)
- Yandex verification мета-тег
- Слот для контента
Параметры (props): `title`, `description`, `keywords`
#### 2.2. Создать лейаут для внутренних страниц `InternalLayout.astro`
Аналог `internal.html.twig`:
- Использует `BaseLayout`
- Навигация (компонент `Navigation.astro`)
- Контейнер `.page` с ограничением ширины
#### 2.3. Создать лейаут для статей `ArticleLayout.astro`
Аналог `article.html.twig`:
- Использует `InternalLayout`
- Заголовок статьи `<h1>`
- Дата публикации и email внизу
- Слот для содержимого статьи
#### 2.4. Создать общие компоненты
- `Navigation.astro` — навигация (Главная, Блог, Галерея)
- `YandexMetrika.astro` — код счетчика аналитики
- `ArticleList.astro` — список статей, сгруппированных по годам
Особенность: Font Awesome больше не нужен (социальные ссылки удалены в коммите `63a324c`).
Если понадобятся иконки — использовать `astro-icon` или inline SVG.
---
### Этап 3. Content Collections и перенос статей
#### 3.1. Настроить Content Collection для статей
- Создать `src/content/articles/` для markdown-файлов
- Определить схему в `src/content.config.ts`:
```ts
{
title: z.string(),
description: z.string().optional(),
keywords: z.array(z.string()).optional(),
tags: z.array(z.string()).optional(),
draft: z.boolean().default(false),
// date — парсится из имени файла (YYYY-MM-DD-slug.md), не хранится в frontmatter
}
```
#### 3.2. Перенести статьи
Перенести 8 markdown-файлов из `source/_articles/` в `src/content/articles/`.
Имена файлов сохраняют даты (формат `YYYY-MM-DD-slug.md`) для удобной навигации в файловой системе. Дата парсится из имени файла при сборке (в `content.config.ts` или в `getStaticPaths`), дублировать в frontmatter не нужно.
Необходимые изменения в каждом файле:
- Удалить Sculpin-специфичные поля frontmatter (`layout`, `styles`, `scripts`, `use`)
- Оставить `title`, `description`, `keywords`
- Опционально: добавить `tags` для будущей фильтрации
Список статей:
1. `2019-05-01-predictor.md` — **ОСОБЫЙ СЛУЧАЙ**, см. задачу 3.3
2. `2019-06-01-php-serialization.md`
3. `2019-06-28-storytelling.md`
4. `2019-08-08-yandex-disk-image-hosting.md`
5. `2019-09-26-highload-videos.md`
6. `2020-06-27-interesting-programming-blogs.md`
7. `2020-06-27-type-discriminant.md`
8. `2020-11-08-nullable-fields.md`
#### 3.3. Перенести статью с интерактивным компонентом (гадалка)
Статья `predictor.md` содержит встроенный Vue-компонент `<div id="app"></div>`.
Шаги:
- Переименовать файл в `.mdx`
- Обновить Vue-компонент `PredictorDemo.vue` до Vue 3 (Composition API или Options API)
- `@anwinged/predictor` — чистый TS, совместимость с Vue 3 не затронута
- Перенести scoped-стили компонента на Tailwind или оставить scoped CSS
- В MDX-файле: импортировать компонент и использовать `<PredictorDemo client:visible />`
- Удалить ручное подключение JS/CSS через frontmatter (`styles`, `scripts`)
---
### Этап 4. Страницы
#### 4.1. Главная страница `src/pages/index.astro`
- Использовать `BaseLayout`
- Имя, краткое описание (обновить текст — актуализировать информацию о себе)
- Ссылки: email, git, другие
- Список последних статей (через `getCollection('articles')`)
#### 4.2. Страница списка статей `src/pages/articles/index.astro`
- Использовать `InternalLayout`
- Список всех статей, сгруппированных по годам (как сейчас в `article_list.twig`)
- Сортировка по дате, от новых к старым
#### 4.3. Динамические страницы статей `src/pages/articles/[...slug].astro`
- Использовать `ArticleLayout`
- Рендеринг markdown/MDX содержимого через `render()`
- SEO мета-теги из frontmatter
#### 4.4. Страница 404 `src/pages/404.astro`
- Использовать `InternalLayout`
- Текст "Страница не найдена" и ссылка на главную
#### 4.5. Страница галереи `src/pages/gallery/index.astro`
- Использовать `InternalLayout`
- Content Collection `gallery` — фотографии с метаданными (title, описание, дата, порядок)
- Структура хранения:
```
src/content/gallery/
├── photo-001.md # frontmatter: title, image, order
├── photo-002.md
└── ...
public/photos/
├── photo-001.jpg # оригиналы фотографий
├── photo-002.jpg
└── ...
```
- Сетка превью с оптимизацией через Astro Image (WebP/AVIF, responsive sizes)
- Просмотр полноразмерных фотографий: lightbox-библиотека (PhotoSwipe или GLightbox)
- Один альбом, без категорий
---
### Этап 5. RSS, Sitemap, SEO
#### 5.1. Настроить RSS-ленту
- Создать `src/pages/rss.xml.ts` с использованием `@astrojs/rss`
- Включить все статьи (title, description, date, link)
- URL: `/rss.xml`
- Для обратной совместимости: добавить редирект `/atom.xml` → `/rss.xml` (в nginx или через Astro)
#### 5.2. Настроить Sitemap
- Интеграция `@astrojs/sitemap` уже генерирует sitemap автоматически
- Убедиться, что 404 и служебные страницы исключены
#### 5.3. Настроить robots.txt
- Создать `public/robots.txt` со ссылкой на sitemap
#### 5.4. Open Graph и мета-теги
- Уже реализовано в BaseLayout (задача 2.1)
- Проверить корректность на каждом типе страниц
---
### Этап 6. Сборка и деплой
#### 6.1. Обновить Docker-сборку
- Новый `docker/node/Dockerfile` на Node 22 LTS
- PHP Dockerfile удалить
- Обновить `Dockerfile.nginx.prod`:
```dockerfile
FROM nginx:stable
COPY dist /usr/share/nginx/html
```
- Добавить конфиг nginx для SPA fallback (404.html) и кэширования статики
#### 6.2. Обновить Taskfile
Финальная версия задач:
```yaml
tasks:
dev: # astro dev (локальная разработка)
build-prod: # astro build
deploy: # build-prod → docker build → ansible
```
#### 6.3. Проверить деплой
- Собрать Docker-образ
- Проверить, что все страницы отдаются корректно
- Проверить 404
- Проверить RSS и sitemap
---
### Этап 7. Очистка
#### 7.1. Удалить файлы Sculpin
- `app/` — SculpinKernel, конфиги
- `bundle/` — кастомные бандлы (HtmlPrettier, SiteMap, TwigExtension)
- `source/` — старые шаблоны, ассеты, контент (после проверки, что всё перенесено)
- `composer.json`, `composer.lock`
- `docker/php/Dockerfile`
- `webpack.config.js`
- `.php-cs-fixer.php`
#### 7.2. Обновить package.json
- Удалить старые зависимости (webpack, babel, vue 2, node-sass, и т.д.)
- Удалить старые npm-скрипты
- Оставить только Astro и его зависимости
#### 7.3. Обновить .gitignore
- Убрать `output_dev/`, `output_prod/`, `vendor/`
- Добавить `dist/`, `.astro/`, `node_modules/`
#### 7.4. Обновить README.md
- Описание нового стека
- Инструкции по локальной разработке и деплою
---
## URL-совместимость
Новые URL: `/articles/slug/` (например, `/articles/predictor/`).
Редиректы в nginx для старых URL (301):
```
/articles/2019/05/01/predictor/ → /articles/predictor/
/articles/2019/06/01/php-serialization/ → /articles/php-serialization/
/articles/2019/06/28/storytelling/ → /articles/storytelling/
/articles/2019/08/08/yandex-disk-image-hosting/ → /articles/yandex-disk-image-hosting/
/articles/2019/09/26/highload-videos/ → /articles/highload-videos/
/articles/2020/06/27/interesting-programming-blogs/ → /articles/interesting-programming-blogs/
/articles/2020/06/27/type-discriminant/ → /articles/type-discriminant/
/articles/2020/11/08/nullable-fields/ → /articles/nullable-fields/
```
Также редирект `/atom.xml` → `/rss.xml` для совместимости RSS-подписок.
---
## Порядок выполнения
```
Этап 1 (инициализация) → Этап 2 (лейауты) → Этап 3 (контент)
→ Этап 4 (страницы) → Этап 5 (RSS/sitemap) → Этап 6 (деплой) → Этап 7 (очистка)
```
Этапы 2 и 3 можно частично выполнять параллельно.
Этап 7 выполняется только после полной проверки нового сайта.