Бесплатный интерактивный курс · aicoding.space
Из конспекта в обучающий сайт: skills-edu-site
Практический курс по @dzhechkov/skills-edu-site для того, кто впервые видит пакет. Вместе с Леной, преподавателем основ сетей, ты установишь пак навыков, разберёшь, что именно легло в проект, пройдёшь восемь шагов конвейера генератора, выберешь типы упражнений под своё содержание, поймёшь, где живут данные курса и как работает слой достижений, опубликуешь сайт на GitHub Pages и проверишь сборку перед тем, как показать его студентам.
Содержание курса
1. Что делает skills-edu-site
Пакет одной фразой: из документации — интерактивный обучающий сайт с тестами, карточками и достижениями.
Ключевая мысль: генератор обучающего сайта из документации
Лена преподаёт основы сетей и уже три года раздаёт студентам одну и ту же папку конспектов в markdown. Читают её, по её же подсчёту, человек пять из тридцати. Её вопрос звучал так же, как, возможно, и твой: «а можно из этого сделать что-то, во что захочется кликать?»
Можно, и ровно для этого существует пакет. @dzhechkov/skills-edu-site — это генератор обучающего сайта из документации: пак навыков для Claude Code, который превращает конспекты, руководства и базы знаний в интерактивное одностраничное приложение с тестами, карточками, достижениями, полосой прогресса и готовой публикацией на GitHub Pages.
Разберём слова, потому что дальше они будут встречаться постоянно:
- Навык (skill) — папка с инструкциями для Claude Code: прочитав её, ассистент умеет выполнять новую задачу. Пакет ставит ровно один навык —
edu-site-generator. - Одностраничное приложение (SPA) — сайт, который загружается один раз, а дальше переключает разделы без перезагрузки страницы. Именно такой сайт получит Лена.
- Геймификация — очки, значки-достижения и полоса прогресса, которые превращают чтение в прохождение.
Где пакет живёт: страница на npm, исходники — в репозитории на GitHub. Пакет входит в экосистему Keysarium — о соседстве с ней будет отдельная секция.
Что важно понять с первой минуты: генератор не пишет сайт «в общих чертах». Он идёт по фиксированному конвейеру из восьми шагов — от разбора твоих документов до проверки сборки — и после каждого шага останавливается и спрашивает «ok?». Лена сначала решила, что это лишняя церемония. К концу курса ты поймёшь, почему она передумала.
Компромисс: ты получаешь проверенный маршрут от документа до сайта — но именно маршрут, а не волшебную кнопку. Содержание остаётся твоим, и качество сайта не превысит качество конспектов, которые ты в него подал.
2. Установка за одну команду
npx init, открыть Claude Code, вызвать /edu-site-generator — три шага до первого сайта.
Ключевая мысль: команда init устанавливает пак
Хватит вводных — Лена уже открыла терминал в папке своего проекта. Открывай и ты.
Путь до первого сайта — три шага:
- Установи пак навыков:
npx @dzhechkov/skills-edu-site init. Командаinitустанавливает пак в текущий проект. Голый вызовnpx @dzhechkov/skills-edu-siteбез словаinitделает то же самое —initподразумевается по умолчанию, и вопросов команда не задаёт. - Открой Claude Code в этой же папке. Навык регистрируется под именем своей папки —
edu-site-generator. - Вызови навык:
/edu-site-generator ./docs/— и генератор начнёт разбирать твои документы.
Есть и глобальный вариант: npm install -g @dzhechkov/skills-edu-site, а потом skills-edu-site init в нужном проекте. Лена выбрала npx — ничего не остаётся в системе, кроме файлов в проекте.
Два флага, которые стоит знать до первого запуска:
init --dry-run— покажет, что будет сделано, ничего не записывая. Лена запустила его первым и увидела список файлов до того, как они появились.init --force— перезапишет существующие файлы. Без него повторныйinitв уже установленный проект честно откажет: «уже установлено, используй update или --force» — и выйдет с кодом 1.
Грабли Лены — не повторяй: она первый раз запустила init не в папке проекта, а в домашней. Пакет кладёт файлы относительно текущей директории, а не «куда-нибудь в проект». Сначала cd в проект, потом init.
Что нужно на машине: Claude Code, Node.js не ниже 16 и npm — он понадобится позже, чтобы собрать сгенерированный сайт.
Компромисс: npx не оставляет следов и всегда тянет свежую версию пакета, но каждый запуск идёт в сеть; глобальная установка работает без сети, зато со временем устаревает — и в секции про update ты увидишь, чем это оборачивается.
3. Что легло в проект: навык и манифест
Папка .claude/skills/edu-site-generator/ с восемью модулями и четырьмя справочниками — плюс манифест в корне, без которого остальные команды слепы.
Ключевая мысль: манифест установки .skills-edu-site.json
Лена не любит, когда что-то «само появилось». Поэтому после init она первым делом открыла дерево проекта — давай посмотрим вместе.
В проекте появилась папка .claude/skills/edu-site-generator/, и внутри неё ровно то, что перечисляет README:
SKILL.md— сам навык, он же оркестратор: описывает, когда навык включается и в каком порядке читать модули.modules/— 8 модулей, шаги00–07: от разбора содержания до проверки сборки. Каждый шаг конвейера — один файл.references/— 4 справочника: шаблоны компонентов, схемы данных, каталог упражнений, описание стека.examples/— 1 пример структуры готового курса на пять секций.
И ещё один файл, не в папке навыка, а в корне проекта: .skills-edu-site.json. Это манифест установки — список того, что пакет положил, с версией и датой. Лена чуть не удалила его как мусор. Не делай так: команды update, remove, list и doctor читают именно манифест, чтобы понять, что установлено. Удалишь манифест — и list скажет «пак не установлен», хотя папка навыка на месте.
Зачем манифест, если можно просто посмотреть папку? Потому что папка .claude/skills/ общая: рядом могут лежать навыки других пакетов. Манифест отвечает на вопрос «какие из этих файлов — мои», и только по нему remove может убрать своё, не тронув чужого.
Компромисс: отдельный файл-манифест — это ещё один артефакт в корне проекта, который надо коммитить вместе с навыком; взамен каждая команда пакета точно знает свою границу и никогда не удалит соседский навык.
4. Жизненный цикл пака: update, remove, list, doctor
Как обновлять, проверять и удалять пак — и почему update из старой глобальной установки ничего не обновит.
Ключевая мысль: update сверяет с шаблонами запущенной версии
Через месяц Лена услышала от коллеги: «в новой версии пакета поправили модуль проверки». Она запустила skills-edu-site update из своей глобальной установки — и увидела «всё актуально». Обновления не произошло. Прежде чем читать дальше, реши: пакет соврал, обновление ещё не вышло — или Лена спросила не у того?
Ответ — третье, и это главное, что нужно знать про update. Команда update сверяет установленные файлы с шаблонами, которые лежат внутри той версии пакета, которую ты запустил. В реестр npm она не ходит и «есть ли что новее» не проверяет. Устаревшая глобальная установка предложит только саму себя. Поэтому обновляться надо так: npx @dzhechkov/skills-edu-site@latest update — @latest заставляет npx взять свежую версию, и уже её шаблоны становятся эталоном. update --dry-run покажет, какие файлы добавятся и изменятся, прежде чем что-то трогать.
Остальные команды жизненного цикла:
list— таблица установленных компонентов, версия и дата установки. Всё это из манифеста.doctor— шесть проверок здоровья: все файлы манифеста на месте; папка навыка иSKILL.mdесть; модули есть; справочники есть; пример есть; состояние интеграции с Keysarium. К каждой провалившейся проверке — подсказка, как чинить (обычно —update).remove— удаляет папку навыка и манифест, но сначала спрашивает подтверждение. Если пак не установлен, просто сообщает об этом.
Про remove есть измеренная деталь, которая важна для скриптов. Когда команда запущена не из терминала, а из конвейера или пайпа (ввод — не TTY), спросить она не может. Без --force она отказывает и выходит с кодом 1, а не делает вид, что всё удалила: README приводит воспроизводитель — printf '' | node bin/cli.js remove; echo $? даёт 1 и все файлы на месте; с --force — удаляет и выходит с 0. Лена оценила это как сетевик: тихий «успех» без действия хуже громкого отказа.
Компромисс: отсутствие сетевой проверки делает update быстрым и предсказуемым — эталон всегда на диске, — но перекладывает на тебя обязанность запускать его через @latest; отказ remove без TTY защищает автоматизацию от ложного зелёного, но требует явного --force в скриптах.
5. Соседство с Keysarium
Пакет работает сам по себе, но узнаёт Keysarium в проекте — по одному файлу, без сети.
Ключевая мысль: автоопределение Keysarium по файлу .keysarium.json
В README дважды упоминается Keysarium, и Лена спросила: «мне это обязательно?» Короткий ответ — нет. Длинный — интереснее.
Keysarium — соседний пакет того же автора, большой набор навыков для Claude Code, в котором есть свой исследовательский конвейер Casarium. skills-edu-site работает и без него: всё, что ты прошёл в прошлых секциях, ни разу не потребовало Keysarium.
Но если Keysarium в проекте уже стоит, генератор об этом узнает — и вот как. При init пакет проверяет, есть ли в корне проекта файл .keysarium.json — манифест Keysarium, точно такой же по назначению, как наш .skills-edu-site.json. Нашёл — печатает рамку «Keysarium обнаружен», показывает его версию и сообщает, что оба пака делят одну папку .claude/skills/. Это и есть автоопределение Keysarium по файлу — никакого запроса в сеть, никакого сканирования системы: один файл в корне.
Лена, привыкшая к тому, что «обнаружение» обычно означает опрос сервисов, удивилась простоте. Здесь решение честнее: файл-манифест либо есть, либо нет, и результат воспроизводим на любой машине.
Что даёт соседство:
- навык
edu-site-generatorстановится частью общего инструментария Keysarium; - генератор умеет делать обучающий сайт из исследовательских артефактов, которые производит конвейер Casarium, — а не только из твоих конспектов;
doctorвключает отдельную проверку состояния этой интеграции.
Порядок установки, если хочешь обоих: сначала npx @dzhechkov/keysarium init, потом npx @dzhechkov/skills-edu-site init — тогда второй увидит манифест первого. Поставишь в обратном порядке — ничего не сломается, просто рамки «обнаружен» при init не будет.
Компромисс: определение по файлу дёшево и воспроизводимо, но и наивно: если манифест Keysarium остался от удалённой установки, пакет всё равно скажет «обнаружен» — он верит файлу, а не проверяет соседа.
6. Восемь шагов конвейера
От разбора содержания до проверки сборки: что делает каждый шаг и почему после каждого — остановка.
Ключевая мысль: восемь шагов конвейера
Лена набирает /edu-site-generator ./docs/ — и вместо «сайт готов» получает: «Шаг 0/7: анализ содержания завершён. Тем найдено: 9. Язык: ru. «ok» — продолжить, или напиши, что поправить». Она озадачена. Ты — уже нет, потому что знаешь из первой секции: генератор идёт по конвейеру.
Конвейер — это восемь шагов, по одному файлу-модулю на каждый, modules/00-… — modules/07-…:
- 00 Анализ содержания — читает твои документы, выделяет темы, определяет язык, прикидывает число секций.
- 01 Структура курса — раскладывает темы по секциям от простого к сложному и назначает каждой тип упражнения.
- 02 Генерация данных — пишет файлы данных: секции, упражнения, вопросы тестов, достижения.
- 03 Каркас проекта —
package.json, конфигурация Vite,index.html, тема в CSS. - 04 Компоненты — интерфейс: раскладка, шесть интерактивных компонентов, страницы.
- 05 Геймификация — хранилище состояния, прогресс, достижения, уведомления.
- 06 Публикация — конфигурация GitHub Pages и рабочий процесс GitHub Actions.
- 07 Проверка —
npm run buildи перекрёстные проверки.
Три взгляда на один и тот же конвейер — выбери тот, что тебе ближе:
- Общая картина: первые три шага — про содержание, следующие три — про код, последние два — про доставку.
- По шагам: каждый модуль заканчивается контрольной точкой «Step N/7 … Complete», списком артефактов и вопросом «ok?».
- Как артефакт: после шага 02 у тебя есть файлы данных, которые можно открыть и прочитать ещё до того, как появится хоть один компонент.
Зачем остановка после каждого шага? Лена поняла на шаге 01: генератор назначил её теме «команды диагностики» карточки, а она хотела конструктор команд. Одно слово в ответ — «шаг 3 сделай builder» — и структура поправлена до того, как написан код. Без контрольной точки она узнала бы об этом на готовом сайте.
Компромисс: восемь остановок удлиняют путь и требуют твоего присутствия, зато каждая ошибка ловится на самом дешёвом шаге — в структуре, а не в сгенерированном коде.
7. Шесть типов упражнений — и какой к чему
Тест, карточки, сопоставление, порядок, конструктор команд, сценарий: как генератор выбирает тип по природе содержания.
Ключевая мысль: шесть типов упражнений
На шаге 01 генератор показал Лене таблицу: тема — тип упражнения. Она посмотрела и спросила: «а по какому принципу?» Принцип есть, и он записан в справочнике references/exercise-catalog.md.
В пакете шесть типов упражнений, и у каждого — своя природа содержания:
- Тест (
quiz) — факты, правила, лучшие практики. Вопросы с вариантами и объяснением к правильному ответу. - Карточки (
flashcards) — термины и определения, всё, что запоминают парами. Карточка переворачивается по клику. - Сопоставление (
matching) — связи: инструмент — назначение, причина — следствие. Левая колонка на месте, правая перемешана. - Порядок (
drag-and-drop) — процессы с определённой последовательностью шагов. Перетаскиваешь, потом «Проверить». - Конструктор команд (
builder) — синтаксис команд и вызовов, где важен порядок частей. Собираешь из кусочков, подсказки идут по нарастающей. - Сценарий (
scenario) — решения в ситуации: несколько шагов, у каждого два-три варианта с оценкой «хорошо / нейтрально / плохо».
Значения interactiveType — ровно эти шесть слов. Старые имена ordering, simulation и drag-order модуль анализа прямо запрещает: они остались как псевдонимы в компонентах, но в новых данных им не место.
Теперь правило, ради которого эта секция цитирует принцип разнообразия. У генератора есть запрет на три одинаковых типа подряд и требование использовать все шесть типов, если секций шесть и больше. Лена спросила, зачем это в коде, а не в рекомендациях. Ответ в таблице анти-паттернов навыка: «все упражнения одного типа — монотонный интерфейс». Внимание студента устаёт от однообразия быстрее, чем от сложности. Каталог даже даёт раскладку: для 10–15 секций — 3 теста, 2 карточек, 2 сопоставления, 2 порядка, 1 конструктор, 2 сценария.
Посмотри на этот курс: тринадцать секций, шесть типов, и нигде три подряд одинаковых. Это не совпадение — это то же правило.
Компромисс: привязка типа к природе содержания даёт осмысленные упражнения, но не всякая тема ложится на «свой» тип идеально; тогда генератор выбирает ближайший, а ты правишь его на контрольной точке шага 01.
8. Ты — методист: сколько секций и из чего
Четыре формы входа, границы 3–20 секций, 150–400 слов теории: реши за Лену, как разложить её конспекты.
Ключевая мысль: от трёх до двадцати секций
В этой секции решения принимаешь ты. Лена принесла папку: 14 файлов markdown про основы сетей, два из них — по абзацу, один — на сорок страниц. Генератор ждёт от тебя не «ok», а методических решений. Правила, в которых ты их принимаешь, записаны в SKILL.md и модулях 00–01.
Что можно подать на вход — одно из четырёх:
- адрес документации в сети — генератор её загрузит;
- путь к файлу или папке — прочитает напрямую;
- вставленный текст — возьмёт как есть;
- описание темы словами — сгенерирует содержание из знаний модели.
Четвёртый способ — самый соблазнительный и самый рискованный: содержание будет правдоподобным, но не твоим. Лена отказалась от него сразу: её студенты сдают её экзамен, а не экзамен модели.
Сколько секций. Границы жёсткие: от трёх до двадцати секций. Меньше трёх — навык предупредит, что содержания не хватает для геймификации, и предложит добавить документов. Больше двадцати — предложит сгруппировать темы или разбить на два курса. Золотая середина по модулю анализа — 5–15.
Сколько теории в секции. Модуль структуры просит 150–400 слов: контекст, суть, применение. Анти-паттерн «теория слишком длинная» — больше 500 слов — лечится разбиением на подсекции. Сорокастраничный файл Лены — это не одна секция, а четыре-пять.
Что ещё решается на шаге 01:
- порядок от простого к сложному, синтез в конце;
- тип упражнения по природе содержания (прошлая секция);
- отдельная эмодзи-иконка на секцию, без повторов;
- по одному вопросу финального теста на секцию, четыре варианта.
Вопрос без единственно верного ответа, над которым Лена думала дольше всего: два файла по абзацу — это две тонкие секции, одна общая или материал для FAQ? Правильного ответа нет; есть решение, которое ты сможешь объяснить студентам.
Компромисс: жёсткие границы 3–20 и 150–400 слов отсекают заведомо плохие курсы, но внутри границ генератор не знает твоих студентов — тонкую резку тем делаешь ты, на контрольных точках шагов 00 и 01.
9. Где живёт содержание: src/data
Секции, упражнения, вопросы и достижения — в файлах данных, а не в компонентах. И почему дерево в README — эскиз, а схема — контракт.
Ключевая мысль: данные курса живут в src/data
Сайт сгенерирован. Лена нашла опечатку в вопросе теста и спросила: «где править — в компоненте теста?» Подумай сам, прежде чем читать: если содержание лежит в компонентах, сколько файлов придётся открыть, чтобы поправить одну опечатку в курсе на тринадцать секций?
Ответ генератора однозначен, и он записан в таблице анти-паттернов навыка: «содержание в JSX вместо data/» — ошибка; всё содержание обязано жить в файлах данных. Компоненты только показывают то, что в них подали. Поэтому данные курса живут в src/data, и опечатку Лена правит в одном файле, не открывая ни одного компонента.
Что лежит в src/data по обязывающему справочнику references/data-schemas.md:
sections.js— массив секций: id, порядок, заголовок, иконка, тип упражнения, теория; рядомTOTAL_SECTIONS.exercises.js— данные упражнений по типам: карточки, пары сопоставления, порядок, конструктор, сценарии — иfaqDataдля FAQ.quizQuestions.js— вопросы тестов по секциям иfinalTestQuestions: по одному на секцию, сsectionId.achievements.js— достижения с условиями открытия.
А теперь честное наблюдение, которое Лена сделала раньше меня. В README, в разделе «Output Structure», дерево проекта нарисовано иначе: src/data/modules.json, exercises.json, stores/useProgress.js. В SKILL.md и схемах — sections.js, store/useAppStore.js, hooks/. Два документа одного пакета расходятся. Что считать правдой?
Правило простое: обязывающий документ — тот, по которому генератор пишет файлы, а это data-schemas.md и модуль 02: именно их навык читает на шаге генерации данных. Дерево в README — эскиз для первого взгляда. Если сомневаешься, открой сгенерированный проект: он и есть окончательный ответ.
Ещё одно, что README говорит верно: файла tailwind.config.js в проекте нет и не будет — об этом в секции про стек.
Компромисс: разнесение содержания и компонентов делает правку курса дешёвой и безопасной, но обязывает соблюдать схему: поле не по имени — и компонент молча покажет пустоту.
10. Слой достижений и прогресса
Хранилище Zustand с сохранением в localStorage, пять стандартных достижений, всплывающие уведомления и финальный тест на 70%.
Ключевая мысль: достижения и прогресс хранятся в localStorage
Студент Лены закрыл вкладку на шестой секции, а назавтра открыл сайт — и прогресс на месте: шесть галочек, два значка, полоса на 46%. Лена спросила: «где это хранится, если у нас нет сервера?»
Ответ — в браузере самого студента. Достижения и прогресс хранятся в localStorage, а управляет ими хранилище состояния Zustand с промежуточным слоем persist. Zustand — маленькая библиотека, которая держит состояние приложения в одном объекте; persist при каждом изменении записывает выбранные поля в localStorage под ключом вида <имя-курса>-progress и восстанавливает их при открытии сайта.
Что именно сохраняется (модуль 05, partialize):
- пройденные секции и балл за каждую (0–100 по результату упражнения);
- открытые достижения;
- результат финального теста и ответы;
- выбор тёмной темы — при загрузке класс
darkвосстанавливается ещё до первого кадра.
Достижения живут в src/data/achievements.js. Пять стандартных есть в каждом курсе: first-step (первая секция), halfway (половина), perfectionist (секция на 100), full-course (все секции), test-passed (финальный тест на 70 и выше). К ним — три-пять тематических, привязанных к группам секций; всего 8–12. Хук useAchievements после каждого изменения состояния проверяет условия и открывает новые; всплывающее уведомление появляется справа сверху и само исчезает через четыре секунды.
Финальный тест — по одному вопросу на секцию, порог прохождения 70%. Результат считается отдельно от баллов секций.
Теперь вопрос на самонаблюдение. Ты только что прошёл девять секций этого курса и, скорее всего, видел уведомления о своих значках. Вспомни момент, когда всплыло первое, — заметил ли ты, что после него прошёл следующую секцию внимательнее? Это и есть механизм, который Лена включает для своих студентов: прогресс, который видно, меняет поведение.
Компромисс: хранение в браузере не требует сервера и работает с GitHub Pages, где сервера и нет, — но прогресс привязан к одному браузеру на одном устройстве, и «сброс прогресса» — это кнопка resetProgress, а не восстановление из резервной копии.
11. Стек: React 19, Vite, TailwindCSS v4
Пять технологий сгенерированного сайта — и две «примечания мелким шрифтом», которые на деле главное: нет tailwind.config.js и только HashRouter.
Ключевая мысль: TailwindCSS v4 настраивается в CSS через @theme
Лена захотела перекрасить сайт в цвета колледжа и полезла искать tailwind.config.js. Файла нет. Она решила, что генератор его забыл, и почти создала свой. Хорошо, что дочитала README до примечания под таблицей.
Сначала таблица стека — пять технологий, из которых собран сгенерированный сайт:
- React 19 — библиотека интерфейса.
- Vite — сборщик и сервер разработки.
- TailwindCSS v4 — CSS-каркас с утилитарными классами.
- Zustand — хранилище состояния (прошлая секция).
- React Router v7 — переключение страниц на стороне браузера.
Плюс @dnd-kit для перетаскивания в упражнениях «порядок» и «сопоставление».
А теперь два примечания, которые обычно пропускают, — и которые в этом пакете важнее таблицы. Здесь и цитируется принцип «врезки — не украшение»: то, что напечатано мелким шрифтом под таблицей, и есть главное.
Примечание первое. Файла tailwind.config.js нет, потому что TailwindCSS v4 настраивается в CSS через директиву @theme. Цвета, шрифты и прочие токены темы объявляются прямо в src/index.css; свои утилиты — через @utility, а не через @layer utilities; подключение — одной строкой @import "tailwindcss". Лена перекрасила сайт, поправив несколько строк в index.css, и никакой конфигурационный файл ей не понадобился. Создай она tailwind.config.js — он бы просто молча ничего не делал.
Примечание второе. Маршрутизатор — обязательно HashRouter, не BrowserRouter. GitHub Pages отдаёт index.html только по корню и не умеет отвечать на пути вроде /section-3 — сервера, который перехватил бы такой запрос, там нет. HashRouter кладёт раздел после #, и браузер никогда не спрашивает сервер о нём. По той же причине навигация по секциям сделана через scrollIntoView(), а не через ссылки <a href="#section-…"> — они конфликтуют с хеш-маршрутизацией.
Компромисс: TailwindCSS v4 убирает конфигурационный файл и держит тему рядом со стилями — удобно, но всё, что ты знал о tailwind.config.js из v3, здесь не работает; HashRouter даёт совместимость с GitHub Pages ценой символа # в адресах.
12. Публикация на GitHub Pages
deploy.yml, base по имени репозитория, HashRouter, push в main — и почему 404 на Pages почти всегда про base.
Ключевая мысль: base равен имени репозитория
Сайт собран, Лена запушила его в репозиторий networks-101 — и получила белую страницу с ошибками 404 в консоли. Посмотри на схему под текстом: путь до работающей страницы — четыре узла, и Лена споткнулась на втором.
Шаг 06 конвейера готовит публикацию так:
.github/workflows/deploy.yml— рабочий процесс GitHub Actions: при каждом push в веткуmainон ставит Node 20, выполняетnpm ciиnpm run build, загружает папкуdistкак артефакт Pages и разворачивает его. Параметрenablement: trueсам включает Pages в репозитории, если они ещё не включены.baseвvite.config.js— здесь и была ошибка Лены.baseравен имени репозитория: дляhttps://github.com/lena/networks-101этоbase: '/networks-101/'. Генератор выводит его из адресаgit remote; если удалённого репозитория ещё нет, спрашивает имя у тебя. Лена создала репозиторий после генерации, иbaseостался от заготовки. Все пути к скриптам и стилям смотрели не туда — отсюда 404.HashRouter— из прошлой секции: разделы после#, сервер о них не спрашивают.- Push в
main— и через минуту-две сайт открывается по адресуhttps://<пользователь>.github.io/<репозиторий>/.
Почему схема здесь важнее текста: 404 на Pages выглядит одинаково при любой из трёх причин — неверный base, BrowserRouter вместо HashRouter, не включённые Pages. Глядя на четыре узла, ты проверяешь их по очереди, а не гадаешь. Таблица анти-паттернов навыка отдельно называет «неверный base путь → 404 на GitHub Pages» и лечение: «выводить из имени репозитория».
Проверь себя: сайт по адресу https://lena.github.io/networks-101/ — какой base? Если ответил '/networks-101/' со слешами с обеих сторон — ты уже не наступишь на грабли Лены.
Компромисс: публикация через Actions полностью автоматическая и бесплатная, но привязана к имени репозитория: переименуешь репозиторий — обязан поменять base, иначе снова белая страница.
13. Проверка перед показом студентам
npm run build без ошибок, перекрёстные проверки данных и три известные ловушки — шаг 07 и честный итог курса.
Ключевая мысль: сборка npm run build подтверждает готовность
Лена собралась показывать сайт группе в понедельник. Последний шаг конвейера — 07, проверка — существует ровно для того, чтобы понедельник прошёл без сюрпризов.
Что подтверждает готовность: сборка. npm run build обязан завершиться без единой ошибки. Не «сайт открывается у меня в dev-режиме», а именно сборка: Vite в режиме разработки прощает то, что production-сборка не пропустит. Если ошибка есть, модуль 07 даёт таблицу «ошибка → причина → починка»: не найден модуль — нет файла или неверный путь; не экспортируется имя — расходятся имена в файле данных; не найден @dnd-kit — доустановить; класс TailwindCSS не применяется — токен не объявлен в @theme. Протокол: прочитать ошибку целиком, найти в таблице, починить, собрать заново — пока не станет чисто.
Перекрёстные проверки — то, что сборка не ловит, потому что это не ошибки синтаксиса, а расхождения данных:
- у каждой секции из
SECTIONSесть свой компонентSectionN.jsx; - у каждого
interactiveTypeесть данные упражнения; - в
finalTestQuestions— ровно по одному вопросу на секцию с вернымsectionId; - файлы
robots.txtиsitemap.xmlна месте, и в карте сайта есть адрес каждой секции.
Три известные ловушки, которые модуль велит проверять поимённо, потому что они уже случались:
- В компоненте теста счётчик правильных ответов при переходе к следующему вопросу не должен прибавляться дважды.
- Навигация по секциям — через
scrollIntoView(), не через ссылки с#(конфликт сHashRouter). - Тёмная тема восстанавливается при загрузке через
onRehydrateStorage.
Лена прошла всё это в субботу. Сборка упала один раз — на неверном имени экспорта в exercises.js после её правки опечатки из девятой секции. Таблица назвала причину, починка заняла минуту.
И честный итог курса, в четырёх строках, как мы закрывали каждую секцию. Сильные стороны пакета: полный маршрут от документа до опубликованного сайта, восемь контрольных точек, шесть типов упражнений, достижения без сервера. Слабые: нужен Claude Code; содержание не улучшается, только упаковывается; README местами эскиз, а не контракт; прогресс живёт в одном браузере. Оценка Лены: 4/5 — «понедельник прошёл, студенты кликали». Одной строкой: сборка npm run build подтверждает готовность — всё остальное до неё было обещанием.
Компромисс: проверка по списку занимает полчаса, которые хочется сэкономить; но каждая ловушка в списке стоила кому-то сломанного показа, и полчаса дешевле.
Частые вопросы
- Пак уже установлен. Как обновиться до свежей версии?
npx @dzhechkov/skills-edu-site@latest update. Без @latest команда update сверяет файлы с шаблонами той версии, которую ты запустил, и в реестр не ходит — устаревшая глобальная установка предложит только саму себя. Сначала можно посмотреть план: update --dry-run.
- Я случайно удалил .skills-edu-site.json. Что делать?
Это манифест установки — его читают update, remove, list и doctor. Папка навыка на месте, но команды её не «видят». Проще всего переустановить: npx @dzhechkov/skills-edu-site init --force — манифест будет записан заново.
- Обязательно ли ставить Keysarium?
Нет. Пакет работает сам по себе. Если Keysarium стоит, init найдёт его манифест .keysarium.json в корне проекта и сообщит об интеграции; появится возможность строить сайт из артефактов конвейера Casarium.
- Сколько документов нужно, чтобы генератор согласился работать?
Минимум на три секции; максимум рекомендованный — двадцать; золотая середина — 5–15. Меньше трёх — предупреждение и просьба добавить содержания, больше двадцати — предложение сгруппировать или разбить на два курса.
- Где править текст и вопросы уже сгенерированного сайта?
В файлах данных src/data: sections.js (секции и теория), exercises.js (упражнения и FAQ), quizQuestions.js (тесты и финальный тест), achievements.js (достижения). Компоненты только показывают данные; обязывающая схема — references/data-schemas.md.
- Почему на GitHub Pages белая страница и 404 в консоли?
Почти всегда — base в vite.config.js: он должен быть равен имени репозитория со слешами с обеих сторон, например '/networks-101/'. Вторая причина — BrowserRouter вместо HashRouter, третья — не включённые Pages (deploy.yml с enablement: true включает их сам).
- Где tailwind.config.js? Его нет в проекте.
И не должно быть: сайт использует TailwindCSS v4, где тема настраивается в CSS через директиву @theme в src/index.css, а свои утилиты — через @utility. Созданный вручную tailwind.config.js ничего не сделает.
- Как удалить пак из скрипта без терминала?
npx @dzhechkov/skills-edu-site remove --force. Без --force при вводе не из терминала команда откажет с кодом 1 и ничего не удалит — это измерено и описано в README, чтобы автоматизация не видела ложный успех.