VulCode

DualFroz: strona programisty bez frameworka, z danymi na żywo

Strona osobista Michała "DualFroz" Foxa, założyciela VulCode. Router w PHP przygotowuje HTML z właściwym tytułem i adresami językowymi, widoki są w czystym JavaScripcie, a liczby z GitHuba przychodzą z naszego własnego API.

Zobacz stronę DualFroz
DualFroz: strona główna na komputerze
DualFroz: strona główna na telefonie

Słoik z cukierkami i karta z Discorda

Po bokach strony głównej stoją dwie rzeczy, które zmieniają się bez udziału właściciela: słoik, z którego gość losuje cukierek, i karta profilu z danymi prosto z Discorda.

Słoik z cukierkami na stronie głównej dualfroz.com

Słoik z cukierkami

  • LosowanieGość klika "Weź cukierka", a serwer losuje smak i dokłada do niego krótką wiadomość od Michała.
  • Złote i sezonowe cukierkiCzęść wiadomości to złote cukierki, a na Halloween słoik dostaje własne smaki i pajęczynę.
  • Ochrona przed botamiKażde losowanie przechodzi weryfikację Cloudflare Turnstile i limity prób z jednego adresu, a licznik pod słoikiem pokazuje, ile cukierków już wylosowano.
  • Aplikacja SłoikNa Androidzie: ostatni cukierek, ranking smaków, ostatnie losowania, widżety na ekranie telefonu i powiadomienia o każdym albo tylko o wybranym cukierku.
Karta profilu z Discorda na stronie głównej dualfroz.com

Karta profilu

  • Profil z DiscordaAvatar, odznaki, tag serwera i status przychodzą na żywo z Discorda, a karta odświeża się co 30 sekund bez przeładowania strony.
  • Linki do marekDualFroz, VulCode, Aphrodi, Flaem, Plazer i Lunatic Studios. Każdy link dostaje kod polecenia, który mówi stronie docelowej, że gość przyszedł z dualfroz.com.
  • Teraz słuchamUtwór ze Spotify z okładką i paskiem postępu, który przesuwa się co sekundę, wzięty prosto ze statusu na Discordzie.
  • RozmowaPod spodem data dołączenia do Discorda i przycisk, który otwiera profil, żeby od razu napisać.

Osiem działów w jednej nawigacji

Na komputerze wszystkie są w górnym menu. Na telefonie Start, Projekty i O mnie są na dolnym pasku, a resztę otwiera Więcej.

  • Start

    Słoik z cukierkami, karta profilu z Discorda, tematy, którymi żyje, wyróżnione projekty, stack i najnowsze wpisy z bloga.

  • Usługi

    Strony, aplikacje, panele, sklepy i boty zlecane przez VulCode, a logo, identyfikacja, UI, grafika, wideo i 3D przez Aphrodi.

  • Projekty

    VulCode, Aphrodi, Lunatic Studios, Flaem, Plazer, Vulp, Nebula i inne, przy każdym jego rola i stan projektu.

  • Open source

    Pull requesty do cudzych projektów: przyjęte, w jakich repozytoriach i językach, liczone prosto z GitHuba.

  • O mnie

    Jak myśli, droga do tego miejsca, języki zmierzone na jego repozytoriach i stack rozpisany na warstwy.

  • Poza kodem

    Biblioteczka krótkich książek z własnym czytnikiem, szachy, to, czego teraz słucha, i biurko, przy którym pracuje.

  • Blog

    Krótkie wpisy o tym, co zbudował i czego się nauczył, pisane na Discordzie, w dwóch językach i w kanale RSS.

  • Kontakt

    Formularz z ochroną przed botami, którego wiadomości trafiają na Discorda, adres e-mail i profile w mediach społecznościowych.

Jedna strona, dwa języki, dwa adresy

Każdy widok ma tłumaczenie po polsku i po angielsku, a każdy język swój adres. O tym, która wersja odpowie, decyduje serwer, zanim przeglądarka uruchomi jakikolwiek skrypt.

dualfroz.com
Strona główna dualfroz.com po polsku na telefonie, z dolnym paskiem nawigacji

router.php

  1. Adres z językiemPodstrony mają wersje /pl/ i /en/. Polska strona główna to dualfroz.com, angielska dualfroz.com/en.
  2. Adres bez językaStary adres przechodzi przekierowaniem 301 na wersję z językiem, a strona główna otwiera się w ostatnio wybranym języku.
  3. Wersje w nagłówkuZnaczniki hreflang łączą obie wersje. Wpis na blogu bez tłumaczenia ma tylko polską.
dualfroz.com/en
Strona główna dualfroz.com po angielsku na telefonie, z dolnym paskiem nawigacji

Pierwszy HTML gotowy na serwerze

Strona nie ma kroku budowania ani pakietów npm. Router w PHP składa pierwszy HTML ze wszystkim, czego potrzebują wyszukiwarka i podgląd linku, jak w nagłówku bloga poniżej.

dualfroz.com/pl/bloghtml
<html lang="pl"><title>Blog - Michał &quot;DualFroz&quot; Fox</title><link rel="canonical" href="https://dualfroz.com/pl/blog" /><link rel="alternate" hreflang="pl" href="https://dualfroz.com/pl/blog" /><link rel="alternate" hreflang="en" href="https://dualfroz.com/en/blog" /><link rel="alternate" hreflang="x-default" href="https://dualfroz.com/pl/blog" /><meta property="og:locale" content="pl_PL" /><meta property="og:locale:alternate" content="en_US" /><meta property="og:title" content="Blog - Michał &quot;DualFroz&quot; Fox" />
  1. Nagłówek na serwerze

    Tytuł, opis, adres kanoniczny, wersje językowe i Open Graph są w pierwszym HTML, więc wyszukiwarka i podgląd linku widzą je od razu.

  2. Gotowa treść dla robotów

    Treść każdej podstrony w obu językach jest zapisana wcześniej jako HTML, a serwer wkleja ją do strony, więc robot nie musi uruchamiać skryptów.

  3. Widok bez czekania

    Szablon, styl i tłumaczenie widoku przychodzą w tym samym HTML, a router w przeglądarce składa z nich stronę i dalej przełącza widoki bez przeładowania.

  4. Pliki z numerem wdrożenia

    Adresy skryptów i stylów zawierają numer wdrożenia, więc przeglądarka trzyma je w pamięci przez rok, a po wdrożeniu od razu pobiera nowe.

Własne API statystyk GitHuba

Liczby o kodzie na dualfroz.com, na vulcode.com, w profilu GitHub i na Discordzie pochodzą z jednego serwisu pod ghapi.dualfroz.com, napisanego w czystym PHP, bez frameworka.

  1. Zbiera

    Kolektor uruchamiany co godzinę pyta GitHuba o repozytoria śledzonych kont i organizacji. Tylko on zna token GitHuba.

    • repozytoria, gałęzie i gwiazdki
    • commity i linie kodu według języka
    • pull requesty do cudzych projektów
  2. Zapisuje

    Po każdym przebiegu zapisuje gotowe odpowiedzi, a raz na dobę przelicza wszystko od nowa.

    • wersja publiczna bez nazw prywatnych repozytoriów
    • pełne dane tylko z kluczem API
    • podsumowanie na Discordzie po pełnym przeliczeniu
  3. Oddaje

    API czyta wyłącznie zapisane odpowiedzi, więc żadna strona nie czeka na GitHuba.

    • JSON: podsumowanie, języki, frameworki, testy, open source
    • karty SVG do README profilu
    • odpowiedź 304, gdy dane się nie zmieniły

Kto korzysta z liczb

  • dualfroz.com

    Liczby na stronie O mnie, pull requesty na stronie Open source i karta profilu z Discorda.

  • vulcode.com

    Liczby o kodzie i open source na stronach firmy, pobierane przy każdym budowaniu strony.

  • Profil GitHub

    Karta profilu z Discorda na żywo i wykres języków w README profilu.

  • Discord

    Aplikacja z komendami /summary, /langs, /oss i innymi, w każdej rozmowie, po polsku albo po angielsku.

Blog pisany na Discordzie

Wpis powstaje jako wiadomość na kanale, a reakcja właściciela zatwierdza go do publikacji. Bez niej nic nie wychodzi na stronę.

Na Discordzie
  1. Wiadomość na kanalePierwsza linia to tytuł, reszta to treść, a zdjęcia idą jako załączniki.
  2. Reakcja właścicielaBot sam podsuwa reakcję pod wiadomością, ale wpis publikuje tylko kliknięcie właściciela.
  3. Wątek pod wpisemBot zakłada wątek na wersję angielską, a przypięta wiadomość staje się przypiętym wpisem.
Na stronie
  1. Synchronizacja co minutęTimer systemd uruchamia skrypt w Pythonie, który przez API Discorda pobiera zatwierdzone wpisy, zdjęcia i emoji.
  2. Wpis w dwóch językachTrafia na blog, do mapy strony i do kanału RSS, a wersje językowe łączy hreflang.
  3. Poprawki i zdjęcie wpisuEdycja wiadomości zmienia treść bez zmiany adresu, a cofnięta reakcja zdejmuje wpis ze strony razem ze zdjęciami.

Co strona wysyła na Discorda

Wiadomość z formularza, wejście z linku polecającego i podsumowanie statystyk przychodzą na Discorda jako osobne wiadomości, od razu, gdy coś się wydarzy.

  • Formularz kontaktowy

    Formularz chroni Cloudflare Turnstile i limit wiadomości. Na Discorda przychodzi imię, temat, treść i adres do odpowiedzi, a kopia zostaje na serwerze.

  • Linki polecające

    Krótki adres /ref/kod albo parametr ?ref= zapisuje, skąd przyszedł gość. Każde użycie to wiadomość z sesjami, odsłonami, informacją, czy gość jest nowy, i trzema najczęściej używanymi linkami.

  • Podsumowanie statystyk

    Po każdym pełnym przeliczeniu API statystyk wysyła podsumowanie ze zmianą przy każdej liczbie od poprzedniego przeliczenia, a tytuł prowadzi do publicznego podsumowania w API.

Kiedy taki układ ma sens dla klienta

PHP z czystym JavaScriptem nie jest odpowiedzią na wszystko. Porównanie z tym, co zwykle proponujemy przy stronie firmowej.

PHP i czysty JS, jak tutaj

  • działa na każdym serwerze z PHP
  • bez kroku budowania
  • zero zależności npm po stronie strony

React z prerenderem, jak vulcode.com

  • komponenty i typy pilnują porządku
  • naturalne środowisko dla wielu interaktywnych ekranów
  • statyczne pliki i Node do budowania

Strona jednej osoby albo małej firmy

PHP i czysty JS, jak tutajReact z prerenderem, jak vulcode.com

Przeważa: PHP i czysty JS, jak tutaj. React też się sprawdzi, ale wymaga więcej narzędzi do zbudowania tego samego.

Hosting bez Node

PHP i czysty JS, jak tutajReact z prerenderem, jak vulcode.com

Przeważa: PHP i czysty JS, jak tutaj. Wystarczy zwykły serwer z PHP, bez budowania strony przed każdym wgraniem.

Większy zespół

PHP i czysty JS, jak tutajReact z prerenderem, jak vulcode.com

Przeważa: React z prerenderem, jak vulcode.com. Komponenty i typy pilnują porządku, gdy ten sam kod zmienia wiele osób.

Dużo interaktywnych ekranów

PHP i czysty JS, jak tutajReact z prerenderem, jak vulcode.com

Przeważa: React z prerenderem, jak vulcode.com. W czystym JavaScripcie każdy z nich trzeba napisać ręcznie.

Pytania o ten projekt