Перейти к основному содержимому

Архитектура

Сайт "Вселенная IT" — связка сервисов с единой навигацией и перекрёстными ссылками. Текст и структура знаний живут в репозитории it-knowledge-base; тяжёлый интерактив и длинный код вынесены на отдельные домены, чтобы энциклопедию можно было собирать и отдавать быстро.

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


Общая схема

Сборка и выкат связаны с DevOps и CI/CD. Исходники хранятся в Git — см. Основы работы с Git.


Роли сервисов

СервисНазначениеТехнология (типично)
spirzen.ruЭнциклопедия, лаборатория, глоссарий, поиск, навигацияDocusaurus 3 + React 19, статический экспорт
code.spirzen.ruЗапускаемые листинги, встраивание через /e/embed/<slug>/Отдельный Astro/Vite-проект
play.spirzen.ruТренажёры, эмуляторы, визуализаторы через /p/embed/<slug>/Отдельный Astro/Vite-проект
assets.spirzen.ruСкриншоты, диаграммы, тяжёлые PNG/WebPCDN / object storage

Разделение сделано осознанно.

  1. Размер бандла. Интерактив из сотен демо держится отдельно от основного JS-чанка энциклопедии.
  2. Независимые релизы. Тренажёр SQL можно обновить без полной пересборки энциклопедии — тот же принцип слабой связанности, что в REST-интеграциях.
  3. Изоляция. iframe + postMessage с проверкой origin задаёт контролируемую границу между контентом и исполняемым кодом. См. также HTTP как основу веб-интеграций и HTTPS.

Паттерны в архитектуре

Ниже — паттерны, которые можно узнать по энциклопедии, и то, как они проявляются именно в "Вселенной IT".

ПаттернСутьГде в проектеТеория в энциклопедии
Static Site Generation (SSG)HTML/JS собираются заранее, сервер отдаёт файлыdocusaurus build → spirzen.ruКак работают сайты, CDN
SPA с гидратациейПосле загрузки HTML React "оживляет" страницуDocusaurus + ReactSPA и frontend-стек
Разделение по bounded contextУ каждого домена своя зона ответственностиspirzen / code / play / assetsПаттерны микросервисов
Embed / FacadeСтатья видит простой компонент, внутри — сложный iframeExternalPlayEmbed, ExternalCodeEmbedМодульность
Lazy loadingКод грузится, когда нуженlazyMdxDemoImports, lazyDemoInViewProxy и lazy loading
Code splittingОдин бандл режется на чанкиWebpack/Rspack splitChunksSPA и bundler
Compile-time transformMarkdown меняется до рендераremark-плагиныMarkdown в вебе
Client-side indexПоиск по заранее собранному JSONdoc-search-index.json + DocSearchОсновы БД и индексы (аналогия)
Redirect / compatibility layerСтарые URL ведут на новыеplugin-client-redirectsHTTP-справочник
Gate / deferred initТяжёлое стартует по действию пользователяClick-to-load, EmbedClickGatePolling и push (отложенная загрузка данных)
Cross-cutting enhancementОбщая логика без дублирования в статьяхDocItem/Layout, articleMetaEnhancementСоставные паттерны
Theme extension (swizzle)Подмена частей фреймворкаsrc/theme/*Основы архитектуры

Паттерны сознательно прагматичные — приоритет скорости сборки тысяч статей и предсказуемости для читателя важнее формальной "чистоты" монолита.


Интеграции и способы взаимодействия

1. spirzen.ru ↔ читатель (HTTP)

Браузер запрашивает статику по HTTP. После первой загрузки навигация между статьями идёт как SPA — без полной перезагрузки страницы, с подгрузкой JS-чанков маршрута.

2. spirzen.ru ↔ code.spirzen.ru / play.spirzen.ru (iframe + postMessage)

ЭтапКтоЧто происходит
РазметкаMDX-статья<ExternalPlayEmbed example="slug" />
ОбёрткаReact на spirzen.ruClick-to-load заглушка, затем <iframe src="…/p/embed/slug/">
Выполнениеplay / codeДемо или листинг в изолированном документе
Обратная связьiframe → родительpostMessage с высотой; проверка origin
Темаquery ?theme=light или darkСогласование яркости с переключателем на spirzen.ru

Это синхронная встраиваемая интеграция — один общий контракт (slug в URL embed, доверенные origins в src/constants/) вместо отдельного REST-API на каждую статью.

3. spirzen.ru ↔ assets.spirzen.ru (прямые URL)

Картинки в Markdown![описание](https://assets.spirzen.ru/...). Браузер качает файл напрямую; CDN кэширует у края сети. Энциклопедия не проксирует байты иллюстраций.

4. Репозиторий ↔ сборка (npm-скрипты)

Перед docusaurus build скрипты в scripts/ генерируют артефакты.

СкриптАртефактЗачем
docs:wiki-linkswikiLinkIndex.jsonРазрешение [[wiki-ссылок]] в remark
docs:search-indexdoc-search-index.jsonКлиентский поиск
docs:redirectsdocLegacyRedirects.jsonРедиректы со старых путей
docs:collection-titlescollectionDocTitles.jsonЗаголовки в хабах подборок

Подробнее — в главе Данные и скрипты.

5. remark ↔ MDX (этап компиляции)

remark-плагины — мост между авторским Markdown и бандлом React. wikiLink.js подставляет ссылки; lazyMdxDemoImports.js переписывает import компонентов на lazy-обёртки. Это интеграция на этапе сборки, в рантайме браузера remark уже не работает.

6. localStorage ↔ тема оформления

Палитра дизайна (data-design) и light/dark (data-theme) сохраняются в браузере. Client modules синхронизируют атрибуты при SPA-переходах — см. Темы и стили.


Что происходит при npm start / npm run build

Цепочка из package.json.

"start": "npm run docs:wiki-links && npm run docs:search-index && npm run docs:redirects && cross-env NODE_OPTIONS=--max-old-space-size=16384 docusaurus start"
ШагСкриптРезультат
1docs:wiki-linkssrc/data/wikiLinkIndex.json, индекс для [[wiki-ссылок]]
2docs:search-indexstatic/doc-search-index.json, клиентский поиск (Ctrl+K)
3docs:redirectssrc/data/docLegacyRedirects.json, редиректы со старых URL
4docusaurus start/buildWebpack/Rspack-сборка сайта

Для продакшена дополнительно запускается docs:collection-titles — заголовки статей в подборках.


Слои приложения spirzen.ru

Каждый пункт — отдельный слой приложения в смысле многоуровневой схемы.

1. Контент (docs/)

  • Файлы .md и .mdx — статьи, разделы, подборки.
  • Frontmatter с полями title, description, slug, tags, related и др.
  • MDX позволяет import React-компонентов прямо в статью.
  • routeBasePath: '/' ставит документацию в корень сайта (/encyclopedia/...).

Текстовая основа — Markdown и языки разметки.

2. Презентация (src/theme/)

Swizzle-компоненты Docusaurus — обёртка статьи, navbar, sidebar, карточки. Здесь вшиты PDF-экспорт, прогресс главы и блок "Смотрите также" без импорта в каждой статье.

3. Интерактив (src/components/)

  • EmbedExternalPlayEmbed, ExternalCodeEmbed (iframe).
  • ХабыCollectionHub, LabTrainersHub, GettingStartedPaths.
  • Поиск — собственный DocSearch вместо Algolia.

4. Данные (src/data/)

JSON и JS-модули с подборками, иконками технологий, палитрами дизайна и словарями терминов. Часть генерируется скриптами, часть редактируется вручную.

5. Стили (src/css/)

Infima (тема Docusaurus) плюс кастомная система --d-* токенов и 25+ палитр data-design. См. HTML и CSS.


Поток запроса читателя

  1. Браузер запрашивает HTML/JS/CSS с spirzen.ru (или localhost:3000).
  2. Client modules (itDesignThemeInit, limitRoutePrefetch) выполняются на клиенте до гидратации React.
  3. При открытии статьи MDX рендерит markdown; remark-плагины уже преобразовали [[ссылки]] и lazy-import компонентов.
  4. ExternalPlayEmbed показывает click-to-load заглушку; после клика iframe грузит play.spirzen.ru и шлёт postMessage с высотой.
  5. Поиск (Ctrl+K) читает doc-search-index.json и ищет локально в браузере — клиентский поиск.

Производительность как часть архитектуры

Решения заложены в нескольких местах сразу.

  • remark lazyMdxDemoImports переписывает статический import Foo from '@site/...' в MDX в lazyDemoInView / lazyExternalEmbed.
  • Webpack splitChunks в docusaurus.config.js выделяет отдельные чанки для React, Docusaurus, Prism, Mermaid и embed-компонентов.
  • limitRoutePrefetch пропускает prefetch тяжёлых маршрутов (/encyclopedia/, /lab/, /about/interactive).
  • Click-to-load iframe откладывает ws:// и тяжёлые демо до клика читателя.

На Windows в dev по умолчанию отключён Rspack faster (IT_DOCUSAURUS_FASTER=1 для включения) — иначе возможен EMFILE при тысячах файлов.


Где что искать в репозитории

it-knowledge-base/
├── docs/ # Контент (статьи)
├── src/
│ ├── components/ # React для MDX и темы
│ ├── theme/ # Swizzle Docusaurus
│ ├── data/ # Статические данные
│ ├── css/ # Глобальные стили
│ ├── remark/ # Плагины markdown
│ ├── clientModules/ # Клиентский bootstrap
│ ├── constants/ # URL embed-сервисов
│ └── pages/ # Главная (отдельно от docs)
├── scripts/ # Генераторы перед сборкой
├── static/ # Файлы как есть (favicon, поисковый JSON)
├── docusaurus.config.js # Главный конфиг
├── sidebars.js # Боковое меню
└── package.json # Зависимости и npm-скрипты

Глоссарий терминов

Краткие определения в контексте "Вселенной IT". Якоря (#сервис) — для ссылок из других глав этого раздела.

Сервис

Отдельно развёрнутое приложение или статический сайт с своим доменом и зоной ответственности. spirzen.ru, code.spirzen.ru, play.spirzen.ru и assets.spirzen.ru — четыре сервиса витрины знаний. Теория — паттерны микросервисов.

Навигация

Способ перемещения читателя по материалам — navbar, sidebar, подборки, wiki-ссылки, поиск, пагинация статей, карта на главной. Единая навигация связывает все домены через ссылки в тексте.

Репозиторий

Git-хранилище исходников (it-knowledge-base на GitHub). В репозитории лежат docs/, src/, скрипты и конфиги; из него собирается spirzen.ru. См. Основы Git.

Интерактив

Запускаемый в браузере опыт — тренажёры, эмуляторы, игры, пошаговые схемы. В проекте основная масса интерактива на play.spirzen.ru и встраивается через Embed. Витрина — /about/interactive.

Домен

Имя хоста в URL (spirzen.ru, code.spirzen.ru). Отдельный домен даёт изоляцию cookies, origin для postMessage и независимый деплой. См. CDN и DNS.

Листинг

Фрагмент исходного кода в статье или на code.spirzen.ru — часто с подсветкой и возможностью запуска. Листинги на code отделены от текста энциклопедии, чтобы не раздувать бандл.

Визуализатор

Интерактивная схема или анимация (алгоритм, сеть, архитектура ПК). На play.spirzen.ru визуализаторы грузятся в iframe только после click-to-load.

Бандл

Один собранный JS-файл (или группа), который браузер скачивает для работы сайта. Цель архитектуры — держать бандл spirzen.ru лёгким, вынося демо на play/code. См. SPA и bundler.

Чанк

Часть бандла, подгружаемая отдельно (lazy route, embed-компонент). Webpack/Rspack splitChunks режет vendor-react, vendor-docusaurus, async-демо. Подробнее — docusaurus.config.js.

Origin

Пара схема + хост + порт (https://play.spirzen.ru). postMessage принимается только с доверенных origin из constants/codeExamples.js и playExamples.js. См. безопасность веба.

Продакшен

Боевая среда, куда попадает результат npm run build после деплоя. Продакшен-URL embed заданы в docusaurus.config.js (customFields). См. DevOps, CI/CD.

Индекс

Заранее собранная структура для быстрого поиска — wikiLinkIndex.json, doc-search-index.json. Аналогия с индексом в БД, но файл лежит в static/ и читается в браузере.

Клиентский поиск

Поиск по статьям без сервера и без Algolia — Ctrl+K, JSON-индекс, fuzzy-match в docSearchEngine.js. Подробнее — Данные и скрипты.

Редирект

HTTP-перенаправление со старого URL на новый после переименования папок энциклопедии. Источники — docLegacyRedirects.json и ручная карта в config. См. HTTP.

Слой приложения

Логический уровень системы — контент, презентация, интерактив, данные, стили. Соответствует слоям в архитектуре ПО.

Frontmatter

YAML-блок между --- в начале .md/.mdxtitle, description, slug, теги. Frontmatter читают Docusaurus и скрипты docs:search-index. Правила — в манифесте и .cursor/rules.

Markdown

Язык разметки текста; в проекте расширен до MDX (Markdown + JSX). См. Текст в веб-технологиях.

Swizzle-компонент

Копия компонента темы Docusaurus в src/theme/, подменяющая стандартную реализацию. Позволяет менять обёртку статьи, navbar, sidebar без форка фреймворка.

Обёртка

React-компонент, который окружает контент — DocItem/Layout, Embed-оболочка вокруг iframe. Паттерн Facade из структурных паттернов.

Верхняя панель сайта — логотип, "Энциклопедия", "Указатель", поиск. Настраивается в themeConfig.navbar и swizzle src/theme/Navbar/.

Боковое меню документации из sidebars.js — дерево разделов, autogenerated для энциклопедии. См. sidebars.js.

Карточка

Компактный блок со ссылкой на статью (DocCard, карточки подборок на главной). Рендерится темой и хабами.

Экспорт

Выгрузка статьи в PDF через ArticlePdfExport (html2canvas + jsPDF) — кнопка в layout статьи.

Embed

Встраивание внешнего контента в страницу. В проекте — React-компонент + iframe на code/play. Отличие от простой ссылки — демо живёт внутри статьи.

Хаб

Страница-каталог — CollectionHub, LabTrainersHub, GettingStartedPaths. Собирает маршруты из src/data/ в один обзор.

Algolia

SaaS-поиск, который Docusaurus поддерживает из коробки. В "Вселенной IT" заменён клиентским поиском из соображений доступности и автономности.

Палитра дизайна

Визуальная тема оформления (data-design) — Matrix, Sakura, "Оригинал" и др. Независима от light/dark. См. Темы и стили.

Infima

CSS-фреймворк по умолчанию в Docusaurus (переменные --ifm-*, сетка, типографика). Кастомные палитры маппятся на Infima через it-design-bridge.css.

Гидратация

Процесс, когда React подключается к уже отрендеренному HTML и делает страницу интерактивной. До гидратации работают client modules и inline-скрипт data-design. См. React.

Заглушка

Плейсхолдер до загрузки тяжёлого блока — EmbedClickGate с кнопкой "Запустить демо". Снижает нагрузку при открытии длинной статьи.

iframe

HTML-элемент вложенного документа. Демо с play/code выполняется в изолированном контексте внутри iframe. См. веб-API браузера.

postMessage

API window.postMessage для обмена данными между окном и iframe. Play шлёт высоту контента; spirzen.ru слушает только доверенные origin.

remark

Экосистема плагинов для обработки Markdown в AST. Плагины в src/remark/ подключены в docusaurus.config.js. См. Markdown.

Click-to-load

Паттерн — iframe и WebSocket демо стартуют только после клика по заглушке. Реализован в ExternalPlayEmbed / ExternalCodeEmbed.

Rspack

Быстрый бандлер (альтернатива Webpack), включается через @docusaurus/faster и future.faster в config.

EMFILE

Ошибка ОС "слишком много открытых файлов". На Windows dev с тысячами MDX Rspack faster по умолчанию выключен.


Связь с остальными главами раздела

Полезные статьи энциклопедии

Содержание