Predstavujem wisdomtech blog
Môj najnovší open source projekt je jednoduchý publikačný systém založený na django frameworku. V tomto článku predstavím projekt a niektoré netradičné technické riešenia.
Spoločnosť Wisdom Technologies s.r.o., pod ktorou som pracoval nedávno ukončila svoju činnosť. Možno sa pýtate, čo sa zmenilo a prečo teraz predstavujem nový projekt.
Dôvodom vytvorenia novej platformy na písanie blogov je snaha o zachovanie súčasného obsahu a pridávanie nových článkov.
Vytvorenie úplne nového webu a presun obsahu som si zobral na starosť ja. Nový web je aktuálne online na adrese wisdomtech.sk. Toto predstavenie sa však týka projektu a nemá byť reklamou (vlastne čo tak môže neexistujúca firma ponúkať?).
Predstavenie začnem licenciou. Vybral som MIT, ktorá patrí medzi tie slobodnejšie z pohľadu vývojára. Zdrojové kódy sú zverejnené na githube.
Technologický stack
S webovým frameworkom Django pracujem pomerne dlhú dobu. Celý projekt je preto postavený na Djanngu.
Ako webový server je použitý nginx s agresívnym cachovaním. Ako databázový server je použitý štandardný PostgreSQL bez nejakých tých špecialít typu RUM.
Javascripty a css súbory sú kombinované / kompilované pythonom bez externých závislostí na nodejs, alebo dart (scss). O ich generovanie sa stará django-compressor.
Ako šablónovací systém som zvolil Jinja2. HTML je kompletne renderované na serveri.
V zásade celý technologický stack je pomerne konzervatívny a niektorí „moderní“ javascriptoví developeri by tento prístup označili za stredovek.
Výkon na prvom mieste
Pri vývoji frontendu sa snažím dlhodobo vyhýbať veľkým frameworkom a kombinovaniu niekoľkých MB javascriptu do jedného veľkého súboru. Namiesto toho píšem čo najmenší postačujúci kód. Tak je to aj v tomto prípade.
Štýl webu tvorí necelých 6 kB CSS
. Funkcionalitu dopĺňa niečo cez 1 kB javascriptu
. Najviac priestoru zaberajú webové fonty, ktoré sú síce slušne optimalizované, ale aj tak je to najväčšia časť prenosu dát. Holt nejaká tá konzistencia medzi rôznymi zariadeniami s rôznymi nainštalovanými štýlmi písma nie je zadarmo.
Úroveň optimalizácie v niektorých častiach prekračuje všetky rozumné medze. Napríklad modul stránkovania je navrhnutý tak, aby mu nevadilo stránkovanie nad niekoľko terabajtovou databázou. Fakt delo na komára, ale tu by som chcel povedať, že nie je to jediný projekt, na ktorom pracujem a potreboval som si vyskúšať, či môj modul funguje korektne. O stránkovaní v relačných databázach mám v pláne napísať niekedy inokedy (a zatiaľ ani neviem na ktorom webe).
Dizajn
Ako dizajn som chcel niečo jednoduché. Už pomerne dlhú dobu píšem články s použitím vlastnej šablóny, ktorá je založená na štýle Gutenberg. Keď sme sa rozprávali, akú šablónu použijeme, zhodli sme sa na tom, že chceme niečo jednoduché. Hneď som ako príklad ukázal svoj publikačný systém a tak bolo rozhodnutie použiť Gutenberg schválené.
V kóde Gutenbergu som urobil dosť zásadné zmeny. Takpovediac z pôvodného kódu zostal asi len komentár v hlavičke. Vzhľad je ale silne inšpirovaný, preto tam aj komentár zostáva.
Na obrázkoch je Mandelbrotova množina. Kód pre rendering množiny som zverejnil na shadertoy.com.
CSS
Štýly sa generujú z scss zdrojového kódu pomocou knižnice libsass. V porovnaní s referenčnou implementáciou má minimálne závislosti, rádovo vyšší výkon a možnosť registrovať si vlastné natívne funkcie.
Vektorové obrázky sú vložené do scss pomocou utility funkcie a vlastného rozšírenia libsass, ktoré vie vložiť svg kód do scss. Okrem vkladania obrázkov umožňuje aj vložiť vstavaný CSS štýl priamo do SVG, čo sa dá použiť napríklad na vloženie viacerých variantov toho istého SVG so zmenenými farbami.
Nginx cache
Chcel som dosiahnuť rýchlosť odpovede servera porovnateľnú so statickými generátormi. V praxi to znamená, že cache musí byť implementované na úrovni webového serveru. Lenže ...
There are only two hard things in Computer Science: cache invalidation and naming things.
-- Phil Karlton.
Začnem tou jednoduchšou časťou - ukladanie cache. Webový server nginx má podporu ukladania cache na disk, prečo to teda nenakonfigurovať a z django aplikácie vo vhodný moment len premazať cache?
Navrhol som teda ukladanie cache do adresára /tmp/blog_cache
. V ňom som vytvoril ešte jeden podadresár pre cachovanie zoznamu článkov. Nastavenie v nginx vyzerá pomerne jednoducho:
uwsgi_cache_path /tmp/blog_cache levels=1:2 keys_zone=blog_cache:10m max_size=100m inactive=14d; uwsgi_cache_path /tmp/blog_cache/list levels=1:2 keys_zone=blog_cache_list:10m max_size=100m inactive=14d; server { listen 80; listen [::]:80; set $base_host "wisdomtech.sk"; server_name wisdomtech.sk www.wisdomtech.sk; include snippets/letsencrypt.conf; include snippets/ssl.conf; include snippets/django-vhost.conf; include snippets/standard-error-pages.conf; location ~ ^/(en/|sk/|)$ { include snippets/https-redirect.conf; include snippets/no-www-redirect.conf; uwsgi_cache blog_cache_list; uwsgi_cache_valid 200 1d; uwsgi_cache_key "${uri}:${arg_page}"; include snippets/call-uwsgi.conf; } location ~ ^/(en/|sk/|)[-a-zA-Z0-9_]+-p\d+/$ { include snippets/https-redirect.conf; include snippets/no-www-redirect.conf; uwsgi_cache blog_cache; uwsgi_cache_valid 200 301 302 7d; uwsgi_cache_key "${uri}"; include snippets/call-uwsgi.conf; } location / { include snippets/https-redirect.conf; include snippets/no-www-redirect.conf; try_files $uri @uwsgi; } }
Názov cache súboru je vypočítaný ako md5sum
z cache_key
. Pri každom uložení stačí vymazať cache pre detail a podadresár list
. Znie síce jednoducho, ale tu som narazil na jeden problém. Práva cache adresára sú 700
a súbory majú 600
. Server nginx neumožňuje nastaviť iného vlastníka, či režim cache súborov. Ako to teda vyriešiť?
Nechcel som, aby nginx a aplikácia bežali pod rovnakým užívateľom. Nakoniec som to vyriešil primontovaním cache adresára cez bindfs s premapovaným vlastníkom.
Kód na prvom mieste
Som programátor a často publikujem články s rôznymi ukážkami zdrojového kódu.
Mnoho publikačných systémov trpí rôznymi nepríjemnými vlastnosťami. Za najnepríjemnejšiu považujem nahrádzanie úvodzoviek vo výpisoch.
Moja implementácia v prvom rade nemodifikuje zdrojové kódy a kód v značke <code>
. Do bežného textu sa pomocou slovníka pridávajú znaky zalomenia slova (soft hyphen).
Do zdrojových kódov sa pridáva zvýrazňovanie syntaxe priamo na strane servera pomocou knižnice pygments. Publikačné systémy dnes väčšinou riešia zvýrazňovanie na strane klienta pomocou javascriptu. Za rendering na serveri ma možno niektorí budú považovať za fosíliu, ale čo už. My starí programátori si na to musíme zvyknuť.
Z neštandardných vlastností by som spomenul ešte možnosť kombinovať markup v zdrojových kódoch. V praxi to znamená, že v zdrojovom kóde môžem zvýrazniť riadok, či časť kódu. Vo WYSIWYG editore stačí označiť relevantnú časť, stlačiť Ctrl+B
pre tučné písmo a je to. Na serveri je príšerný kus kódu, ktorý spojí môj markup s výstupom z highlightera. Nepýtajte sa ako to funguje, písal som to ja a netuším ako to fungovalo ani keď som to písal. Proste to funguje a rieši to všetky možné spôsoby kríženia tagov.
Obrázky
Pre generovanie náhľadov používam modul easy thumbnails. Samozrejme nebol by som to ja, keby som ho nepoužíval trochu neštandardným spôsobom a nenarazil by som pri tom na niektoré corner casy, kvôli ktorým som aj písal vlastné patche. Tie sú už našťastie začlenené v hlavnom projekte.
Obrázky sa generujú v niekoľkých veľkostiach a niekoľkých formátoch. Je na prehliadači, aby si vybral správny obrázok na základe šírky viewportu v pixeloch (myslím tie reálne, nie tie v CSS). Kompresia je tým vyššia, čím je väčšie rozlíšenie obrázka. Dôvodom je, že obrázky s väčším rozlíšením sa typicky renderujú na HiDPI displayoch, ale fyzická veľkosť obrázka na displayi nie je tak veľká, aby bolo viditeľné zníženie kvality povedzme z 80% na 60%.
Všetky obrázky (aj tie v obsahu stránky) majú automaticky nastavenú šírku a výšku vďaka čomu ani pri lazy loadingu nedochádza k prepočítavaniu layout stránky. Samotný kód obrázka vyzerá ako celkom slušné monštrum.
<picture> <source type="image/webp" srcset=" /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.828x569_LxxUgxPXyElIm8YNruKDMRPi.jpg.webp 828w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.328x225_LxxUgxPXyElIm8YNruKDMRPi.jpg.webp 328w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.496x340_LxxUgxPXyElIm8YNruKDMRPi.jpg.webp 496w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.656x450_LxxUgxPXyElIm8YNruKDMRPi.jpg.webp 656w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.984x676_t_YubxSW0WssWJBfRk0fakrX.jpg.webp 984w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.1656x1138_GFZfoNLQBEUWG955RDv2VPdz.jpg.webp 1656w" > <img src="/64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.828x569_LxxUgxPXyElIm8YNruKDMRPi.jpg" srcset=" /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.828x569_LxxUgxPXyElIm8YNruKDMRPi.jpg 828w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.328x225_LxxUgxPXyElIm8YNruKDMRPi.jpg 328w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.496x340_LxxUgxPXyElIm8YNruKDMRPi.jpg 496w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.656x450_LxxUgxPXyElIm8YNruKDMRPi.jpg 656w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.984x676_t_YubxSW0WssWJBfRk0fakrX.jpg 984w /64af9506-9dfd-415a-b516-7e52e80ee1d0.jpg.1656x1138_GFZfoNLQBEUWG955RDv2VPdz.jpg 1656w" alt="Nunc scelerisque, tellus at eleifend viverra" width="828" height="569"> </picture>
Administrácia
Namiesto vlastného administrátorského rozhrania som išiel cestou najmenšieho odporu a využil som vstavané rozhranie djanga. Editáciu obsahu zabezpečuje TinyMCE. Inak tu nie je asi nič zaujímavé, jednoducho staré nudné automaticky generované administrátorské rozhranie. Nenadchne. Neurazí.
Záver
Čo by som mal napísať na záver? Hádam už len zopakujem odkaz na repozitár. Vďaka slobodne licencii pokojne forkujte, kopírujte časti kódu, inšpirujte sa, jednoducho urobte internet lepším miestom.
Pre pridávanie komentárov sa musíte prihlásiť.
Nádherný blog, škoda len, že mu takmer nerozumiem, ono tieto webové technológie sú úplne mimo mňa. Môj vrchol pochopenia je asi statický web, niečo ako HUGO.
mna by zaujimalo preco si prastil s Wisdom Technologies
Ja nie, kolega sa rozhodol odísť. Bol zničený zo zákazníkov a ja by som to sám nezvládal.
chapem, v tomto ecommerce biznise sa tiez pohybujem. Nastastie riesime eshops s revenue viac ako 20M eur a neriesime malichernosti.