Що їде на сервер
а що лишається вдома
Репозиторій зазвичай містить більше, ніж сайт: ескізи, промпти, фото-референси й інструменти. Сервер має отримати сайт і нічого більше, а деплой має бути настільки нудним, щоб його не страшно було запускати в понеділок зранку.
Одразу до кодуРепозиторій — ще не сайт
Поруч зі сторінками в репозиторії легко накопичуються дизайнерські джерела, промпти для картинок, фото-референси, нотатки й інструменти. Залийте всю теку — і все це стане публічним разом із сайтом.
- Їде на сервер: готові сторінки, стилі, скрипти, шрифти й картинки, якими вони справді користуються, і серверні файли на кшталт
robots.txt, карти сайту та правил переадресації. - Лишається вдома: дизайнерські джерела й промпти, особисті фото, нотатки, тести й інструменти збирання, резервні копії та все, де є пароль чи ключ.
Тому наш сайт збирається в окрему теку. Збирач робить кожну сторінку кожною мовою за чистою адресою на кшталт /pl/notes/, а потім копіює лише ті файли, на які посилаються сторінки, стилі й скрипти. Те, на що ніхто не посилається, нікуди не їде.
Імена, які перемагають кеш
Одна несподіванка дорогою: CDN перед сайтом ігнорував звичний трюк із ?v=, і після оновлення знову й знову приходили старі стилі. Тож збирач перейменовує самі файли. Кожне нове ім’я містить перші вісім символів хешу SHA-256 від вмісту файлу.
JavaScript · tools/build-site.cjs
for (const file of HASHED) {
const text = readText(file);
const hash = crypto.createHash('sha256').update(text).digest('hex').slice(0, 8);
renamed[file] = file.replace(/(\.[a-z]+)$/, `.${hash}$1`);
write(renamed[file], text);
}readText() заодно перетворює віндовсні закінчення рядків на звичайні, тож однаковий вміст отримує однакове ім’я на будь-якому комп’ютері. Далі сторінки переписуються так, щоб вести на style.1a2b3c4d.css замість style.css; вихідні файли не змінюються.
Тепер правила кешування можуть бути суворими. Сторінки щоразу перевіряються наново, тож деплой видно вже під час наступного відвідування. Стилі й скрипти з хешем кешуються на рік як незмінні: змінений файл отримує нове ім’я, і старий ніколи не застаріває. Картинки автоматично не перейменовуються, тож замінена картинка отримує нове ім’я вручну, наприклад -v2.
Деплой, який уміє сказати «ні»
Скрипт деплою запускає збирач і відмовляється йти далі, якщо результат виглядає неповним. Це важливо, коли заливка дзеркалить теку з видаленням, як rsync --delete: віддзеркалений із порожньої теки, він спорожнив би живий сайт.
Bash · tools/deploy.sh
test -f dist/site/index.html || { echo "deploy: no index.html in dist/site"; exit 1; }
test -f dist/site/.htaccess || { echo "deploy: no .htaccess in dist/site"; exit 1; }
pages=$(find dist/site -name '*.html' | wc -l)Наступний рядок порівнює це число з очікуваною кількістю сторінок: кожна сторінка кожною мовою плюс 404. Лише тоді щось вирушає з комп’ютера.
- Спершу резервна копія
Перш ніж щось зміниться, поточна версія сайту пакується в резервну копію. Кількох останніх копій досить. - Розпакувати поруч із живим сайтом
Нова збірка спершу потрапляє в тимчасову теку, тож зламана заливка ніколи не замінить робочий сайт наполовину. - Чіпати лише свою теку
Синхронізація оновлює теку самого сайту й нічого поруч.
Ключі — осторонь. Ключу чи паролю для деплою не місце ні в репозиторії, ні в збірці: вони живуть лише там, звідки деплой запускають.
Питати живий сайт, а не збірку
Після заливки скрипт ставить справжньому домену кілька запитань і чекає точних відповідей.
- Головна й сторінка кожною мовою відповідають 200: усі версії на місці.
- Обробник форми зв’язку відповідає 405 на звичайний візит: він приймає лише POST.
- Стара адреса відповідає 301: збережені людьми посилання й далі кудись ведуть.
- Вигадана адреса відповідає 404: відсутню сторінку чесно позначено, і показується власна сторінка 404 сайту.
Ще одна несподіванка: CDN може відповісти 403 на голий запит зі скрипта, хоча всім іншим сторінку віддає. Тож кожне запитання має п’ять спроб, перш ніж зарахується як провал.
Bash · tools/deploy.sh
check() {
for attempt in 1 2 3 4 5; do
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 20 "$1")
if [ "$code" = "$2" ]; then echo "$1 -> $code"; return 0; fi
sleep 6
done
echo "deploy: $1 answered $code, expected $2"; return 1
}Нудно — і так задумано
Добрий деплой минає без пригод: та сама збірка щоразу, свіжа резервна копія й кілька точних відповідей від живого сайту. Якщо щось не так, скрипт зупиняється раніше, ніж це помітять відвідувачі. Котка схвалює все, що дає їй проспати день релізу.