Motywacja
Nad zmianą myślałem od dłuższego czasu, ale zawsze było ALE
. Co prawda, o powodach zmian i ich konsekwencjach pisałem w tej notatce ↗, ale uzupełnię ją cytatem, który znalazłem u Lei Verou ↗:
It was time to move on. It’s not you WP, it’s me.
Czas i na mnie.
Statyczne strony
W moim czytniku RSS jest sporo statycznie generowanie blogów, imponujące szybkością, prostotą i co najważniejsze: nie było żadnych różnić w stosunku do blogów, opartych na WP. Stąd też wydawało się oczywiste, iż przejście na tego typu “silnik” jest kolejnym krokiem milowym w mojej wieloletniej karierze Blogera. No i wreszcie zrealizowałem jedno z wielu celów, jakie wytyczyłem na ten rok — lepiej późno niż wcale.
Proces tworzenia i publikacji notatek jest naprawdę uproszczony do minimum, co prawda jeszcze nie jest w pełni zautomatyzowany, ale już teraz działa tak, jak przewidywałem.
Czyli
- Tworzę plik
index.md
w katalogu2023/12/nowy-wpis
- Dodaję opcjonalną grafikę — okładkę do
./images
- Puszczam do PR do mastera
- Uruchamiam
npm run build
i przesyłam zawartość na serwer
Automatyczny deploy
Tak, brakuje tutaj automatycznego deploy, który zadziałałby po przesłaniu zmian do gałęzi master
projektu w repozytorium. Świadomie ten krok pominąłem z uwagi na wielkość projektu, przekraczający przeszło 1 GB (wszelkie zdjęcia i ilustracje do wpisów), co ma negatywny wpływ na limit czasowy, jaki obowiązuje w większości CI/CD.
Mam kilka pomysłów na optymalizację, więc w najbliższej przyszłości będę to sprawdzał.
✅ Udało się dzięki Wiktorowi ↗, który podsunął pomysł na wykorzystanie GitLab Runner.
Migracja treści do Markdown
Skoro istnieją odpowiednie narzędzia, to proces migracji wydawał się dość prosty. Jak się potem okazało, to był najbardziej upierdliwy i czasochłonny etap pracy.
Narzędzie do eksportu WordPress
Z pomocą przychodzi projekt WordPress export to Markdown ↗, Jest to skrypt konwertujący plik XML (wyeksportowany z WordPress) do plików Markdown odpowiednich dla większości znanych generatorów stron statycznych.
Każdy post jest zapisywany jako oddzielny plik Markdown z odpowiednią treścią. Obrazy są również pobierane i zapisywane. Osadzone treści z YouTube, Twittera, CodePen itp. są starannie zachowywane.
Własny fork - dostosowany do wymogów AstroJS
Okazało się, ze domyślne opcje ww. eksportera nie są zgodne z tymi, które stosuje sie zazwyczaj AstroJS (a konkretnie w AstroPaper | Astro ↗).
Po przejrzeniu listy zgłoszeń i zmian w repo projektu, utworzyłem własny projekt ↗ ( baza wiadoma), wprowadzając modyfikacje własne i innych:
- dodano ścieżki w frontmatterze dokumentu
-dodano
description
na bazie wpisów znajdujących nad tagiem<!--more-->
- dodano wsparcie dla plików
webp
- PR: 82 ↗ - dodano metadane Wordpressa w frontmatterze - PR: 96 ↗
Osiągnąłem strukturę pliku .md
, zgodną z schematem AstroJS,
---
title: ""
postSlug: ""
pubDatetime: ""
categories:
- ""
- ""
tags:
- ""
- ""
- ""
description: ""
series: ""
coverImage: "https://static.bobiko.blog/2023/12/migracja-wordpress-astro/images/astrojs.png"
wp_id: "--"
wp_slug: ""
wp_type: "post"
---
Content ...
Dalsze komplikacje
Ignorancja kosztuje
Sam eksport nie wymagał mojej uwagi, zatem działał w tle, łącznie z pobraniem plików graficznych. Finalnie komunikat wyglądał właśnie tak:
Informacje o 251 plikach zignorowałem, bo uznałem to za małą istotne dla bloga (zwłaszcza, ze powstały ponad 12-15 lat temu).
Jak się potem okazało, musiałem osunąć te błędne ścieżki z wpisy, bo w trakcie build
sypało wyjątkami. Ignorancja kosztuje
Ścieżki grafik
Pierwsze podejście uruchomienia projektu zakończyło się niepowodzeniem, ponieważ ścieżki plików były złe - wskazywały na katalog /public/images/*
(ścieżka absolutna) zamiast /dist/blog/2023-12/images/*
(ścieżka lokalna) Ten sam błąd wystąpił w przypadku metadanych coverImage
Rozwiązanie: zmiana ścieżki images/image.jpg
na ./images/image.jpg
. Niby niewielka różnica, ale konsekwencje ogromne.
Polskie znaki w nazwie plików
Dotąd nie wiem, dlaczego pozwoliłem na polskie ogonki, spacje etc. w nazwach plików. Skoro WordPress nie widział w tym nic szczególnego, to czemu miałbym się tym przejmować? Otóż AstroJS ma jaką dziwną manierę ze wszelkie niedozwolone znaki zamieniał na ich odpowiedniki z ASCII
a nazwa plików pozostała bez zmian.
Napisałem z niewielką pomocą AI taki oto konwerter w Bash:
#!/bin/bash
if [ -z "$1" ]; then
echo "Podaj katalog główny jako parametr"
exit 1
fi
cd "$1" || exit 2
echo "stara nazwa | nowa nazwa" > zmiany.csv
find . -type f \( -iname "*.jpg" -o -iname "*.png" -o -iname "*.gif" \) | while read -r file; do
filename=$(basename -- "$file")
# Zamień polskie znaki diakrytyczne na ich odpowiedniki bez ogonków, używając polecenia iconv z kodowaniem ASCII//TRANSLIT
newname=$(echo "$filename" | iconv -f UTF-8 -t ASCII//TRANSLIT)
# Jeśli nazwa pliku się zmieniła, to
if [ "$filename" != "$newname" ]; then
# Zapisz zmianę do pliku csv, używając tylko ./images/<nazwa pliku> jako ścieżki
echo "./images/$filename | ./images/$newname" >> zmiany.csv
# Zmień nazwę pliku graficznego
mv -- "$file" "${file%/*}/$newname"
# Wypisz na ekranie informację o zmianie nazwy pliku graficznego
echo "Zmieniono nazwę pliku graficznego: $file -> ${file%/*}/$newname"
# Znajdź plik index.md w katalogu poziom wyżej od katalogu z grafiką
mdfile="${file%/*/*}/index.md"
# Jeśli plik index.md istnieje, to
if [ -f "$mdfile" ]; then
# Zmień ścieżkę pliku graficznego w treści pliku index.md, używając tylko ./images/<nazwa pliku> jako ścieżki
sed -i "s/(.\/images\/$filename)/(.\/images\/$newname)/g" "$mdfile"
# Wypisz na ekranie informację o zmianie ścieżki pliku graficznego w pliku index.md
echo "Zmieniono ścieżkę pliku graficznego w pliku index.md: $mdfile"
fi
fi
done
w ten sposób miałem listę plików do zamiany. Napisałem drugi skrypt, zamieniający ścieżki w plikach MD i sprawiło, szybko przywróciłem poprzedni stan. Okazało się, że niepoprawnie wykrywały odpowiedniki z tablicy ASCII. Lista zmian nie była na tyle duża, wiec ten etap zrobiłem po prostu ręcznie.
Dziwne znaki
Pojawiły się kolejne błędy, jakie pojawiły się w trakcie budowania w AstroJS.
\-
\*
\'
Tego typu błędy pojawiały się głównie tam, gdzie była lista. To chyba jakiś nieoczekiwany błąd, wyjątek, z którym nie poradził sobie eksporter.
Wszędzie pułapki.
Czas publikacji
O ile Hugo czy Jekyll dość łaskawie podchodzą do czasu publikacji wpisu, ograniczając się do formatu YYYY-MM-DD
, tak w AstroJS jest wymagany datę i godzinę w formacie ISO 8601 (czyli obiekt Date()
w JS).
Przy eksporcie nie ma z tym największego problemu, ale nieświadomie popełniłem błąd, zapisując atrybut pubDatetime
jako string
, co było niezgodne z schematem struktury w AstroJS. Łopatologicznie rzecz biorąc: chodziło o to, ze 2023-12-18T17:30:45.000Z
powinien być bez cudzysłowie.
Rozwiązanie było proste: konwersja string
na obiekt Datetime
przy użyciu biblioteki Zod
:
{
pubDatetime: z.string().transform(str => new Date(str) ),
}
Struktura linków
Pierwsze wersje bloga miały dziwaczną strukturę linków
https://bobiko.blog/posts/YYYY-MM/<nazwa>
co odzwierciedlało strukturę w projekcie:
├── posts
│ ├── index.astro
│ └── [slug]
│ ├── index.astro
│ └── index.png.ts
Początkowo myślałem o przekierowaniach w plikach .htaccess
, ale konsekwencje byłyby ogromne — z uwagi na 16 lat blogowania.
Poszperałem i znalazłem info / wzmiankę (tylko już nie pamiętam gdzie), że aby usunać posts
z URL, należy skorzystać z operatora spread
├── posts
│ ├── index.astro
│ └── [...slug]
│ ├── index.astro
│ └── index.png.ts
Zapis [...posts]
pozwala na rozbicie iterowanego obiektu z postami na pojedyncze posty.
Ostatecznie .htacces
wykorzystałem do przekierowania:
- tagów i kategorii, których nie indeksowałem;
- nieistniejących już stron na stronę główną.
Co dalej?
Jestem zadowolony z efektów wielodniowej pracy nad zmianą, dostarczając całkiem niezłą dawkę wiedzy (i frustracji także). Sprawiła, że poznałem bliżej AstroJS (wady i zalety), widzę spory potencjał na nowe strony w najbliższej przyszłość; najbardziej cenię fakt, że mogę pisać równie mikrokomponenty w Next.js obok Vue czy Svelte.
Wracając do pytania, to sporo pracy czeka na mnie:
- system komentarzy — ciagle chodzi za mną chęć zbudowania takiego systemu, na wzór Giscusa;
- migracja zdjęć na CDN. — proces budowania wpisu jest długi i upierdliwy; za każdym razem przekracza wagę 1 GB i cały ten projekt “muszę” przesłać na serwer;
- nie chciałbym zrezygnować z mechanizmu AstroJS do optymalizacji zdjęć
- chwilowo rozwiązałem to własnym runnerem, które mam zainstalowane na serwerach;
- optymalizacja RSS — niezależny walidator RSS krzyczy niekompatybilnością, brakuje grafik, wiec wkrótce się tym zajmę.
- integracja z fedi - tak, brakuje obecności profilu bloga na mastodon i możliwości integracji z komentarzami i reakcjami
- przykład fajnej implementacji - Bullets #8 | Blogging is cool, coding a blog is even cooler :: lubieniebieski by adam nowak ↗
Dziękuję za każdy feedback (w większości bardzo pozytywny), co tylko utwierdza mnie w przekonaniu, że była to dobra decyzja ❤️
Uff. ale się rozpisałem ;-).