Henk Arendse

Dingen die mij bezig houden

Header Image

De Supernova Website Generator

image images/supernova_gui_light.png

Voor het omzetten van deze site van een WordPress-site naar een static HTML-site, heb ik een website generator ontwikkeld. Waarom? Om te beginnen omdat het leuk is om zoiets te doen. En eigenlijk was het ook opmerkelijk eenvoudig. Dat maakte het nog leuker. En als ICT-er besteed ik natuurlijk liever 10 dagen aan het ontwikkelen van iets spannends (de website generator) dan 1 dag aan iets saais (handmatig HTML-pagina's converteren).

En als je zelf een product maakt, dan mag je het ook zelf een naam geven. We noemen hem "Supernova".

Wat is een "Website generator"? Dat is software die op basis van "content files" met behulp van "templates" kant-en-klare HTML-files maakt die direct geschikt zijn om over te zetten naar de server waarop de website draait.

Dat klinkt wat ingewikkeld. Laat ik het aan de hand van een concreet voorbeeld uitleggen. En als voorbeeld gebruik ik de webpagina die je nu zit te lezen. Die is tenslotte ook door de Supernova generator gemaakt.

Een nieuw project

folder structuur project

Een Supernova website project begint met het maken van een nieuwe folder met daarin 3 subfolders voor het project (bv D:\Documents\Projecten\Supernova\prj_Henk Arendse).

De naam van de projectfolder kan vrij gekozen worden. De namen van de 3 subfolders moeten exact zo zijn als aangegeven in de afbeelding: content, site en theme. De theme folder moet twee subfolders hebben: assets en templates.

Content files

Vervolgens moeten de teksten voor de website pagina's gemaakt worden. De generator is geen chatGPT; hij verzint niets zelf. Alle teksten van mijn site moet ik zelf bedenken en schrijven. En dat vraagt concentratie, dus wil ik bij het schrijven niet afgeleid worden door lastige lay-outkwesties. Want die zijn natuurlijk veel leuker om op te lossen. Voordat je het weet zit je dan weer met CSS en vormgeving te stoeien, in plaats van teksten schrijven.

Daarom wordt de tekst geschreven in zgn. "content files"; één voor elke webpagina. De tekst wordt geschreven in Markdown of in de vorm van heel eenvoudige HTML. De content file bevat alleen maar teksten en afbeeldingen. Liefst alleen h3, h4, p en img tags, geen div's en classes; alleen maar content.

De content file voor deze webpagina heet heel treffend supernova.html en ziet er als volgt uit: content file

Bovenin staat een blok met definities, zoals de titel en de header voor de webpagina en een samenvatting. De Title zullen we terugzien op het tabblad van de pagina in de webbrowser, de Header bovenaan het artikel en de Summary zien we terug op de pagina met de lijst van artikelen, in dit geval de Websites pagina.
Na het definitieblok komt de echte content.

Theme

De algemene vormingeving, de lay-out en de navigatie van pagina's van de site wordt vastgelegd in "Template files", die in de theme/templates folder geplaatst worden. Samen met de CSS-files, de Javascript en de images voor de pagehaders in de theme/assets folder bepalen die hoe de gegenereerde site er uit komt te zien. De template files assets vormen samen het "theme" van de site. Het thema van deze site heb ik de naam "Gemini" gegeven. Dat was nog voordat Google zijn AI-product ook de naam Gemini gaf. Misschien moet ik Google hierover aanspreken. Of misschien mijn theme een andere naam geven.
Gemini is een "Multiblog" thema, omdat je hiermee meerdere blogs op één site kunt maken. Bij deze site zijn dat de blogs Opmerkelijk, Websites en ICT-boeken. Deze pagina's bevatten allemaal een introductie over de betreffende blog en een lijst met de artikelen in deze blog. Ook deze pagina's zijn gegenereerd door Supernova, met behulp van het list.html template, op basis van de List en Summary specificatie in het definitieblok van de content files.

Hieronder een fragment van de template file die ik gebruik om deze website te genereren. template file

Dit stukje template bevat de link naar de CSS-files, de div tags en de classes. Voor de CSS gebruik ik Pico als basis. Pico is een geweldig CSS-framework, heerlijk simpel om te gebruiken. Het heeft bijna geen classes, dus heb ik zelf een paar classes gedefinieerd, in custom.css

In het definitieblok van de content file (zie hierboven) staat een Template veld. Dat is belangrijk, want hierdoor 'weet' de Supernova generator welk template gebruikt moet worden voor het genereren van deze pagina. Voor deze site heb ik een template gemaakt dat detail.html heet. De generator maakt dan een kopie van detail.html en die kopie krijgt de naam 'supernova.html', gelijk aan de naam van de content file.

Tijdens het kopiëren worden de definities en de tekst van de content file op de juiste plaatsen in de gekopieerde pagina geplaatst. De Title uit het definitieblok wordt bijvoorbeeld ingevuld op de plaats van {{page.title}}

Alle syntax in de template file die tussen { en } staat, zijn instructies voor de Jinja template engine. Hiermee wordt logica uitgevoerd op basis van waarden van variabelen die door de generator worden doorgeven aan het kopieerproces. Die variabelen kunnen enkelvoudig, maar ook samengesteld zijn, bijvoorbeeld Python dictionaries, lists of, nog mooier, lists van dictionaries.
De Jinja template engine vormt echt de kern van het systeem en doet al het zware werk.

De site-folder

site
├───assets
│   ├───css
│   └───js
├───images
│   └───header
│
├───opmerkelijk
│   └───images
├───ict-boeken
│   └───images
└───websites
    └───images

De site folder is de folder die straks in zijn geheel naar de webserver wordt overgezet. Behalve HTML-bestanden moet die folder dus ook de images, Javascript files, de CSS-files en de .htacces file bevaten. De generator vult die folder automatisch, inclusief alle benodigde subfolders. De theme/assets folder wordt naar de site/assets folder gekopieerd. Dat kan wat Supernova betreft op allerlei manieren, zolang de inhoud van de content files en de template files maar consistent is met elkaar en met de gedefinieerde subfolders.

Voor deze website heb ik ervoor gekozen de content gerelateerde images in separate folders op te nemen in de contentfolders. Deze folders worden door de generator gekopieerd naar de corresponderende subfolders in de site folder. Bijvoobeeld: de images voor de blog websites zet ik in de content/websites/images folder. De generator kopieert die folder dan naar de site/websites/images folder.

En daar moet ik wel rekening mee houden bij het schrijven van de content files. Voor het weergeven van bijvoorbeeld een specifieke afbeelding, schrijf ik dan in de content file:
<img src="images/image01.png">

De Generator

Zoals gezegd: de Supernova generator combineert de inhoud van de content file en de template file tot een complete HTML-file die in de site folder wordt opgeslagen. De naam van complete HTML-file is gelijk aan de naam van de content file. En omdat de content file in subfolder /content/websites zit, maakt de generator automatisch een subfolder /site/websites, waarin de gegenereerde HTML-file wordt opgeslagen.

De motor van de generator heb ik gebouwd met behulp van Python en de Jinja2 module. De hoofdfunctie van de generator in generator.py is:


        def generate(
                local_dir: str, 
                to_server: bool, 
                domain: str, 
                root: str)   -> tuple[str, ListOfDictionaries]:
    
De functie retourneert een list met dictionaries. Elke dictionary bevat de gegevens van één pagina. Die gegevens worden gebruikt door de templates. De input argumenten:

  • local_project_dir de hoofdfolder van het project; bv D:\Documents\Projecten\Supernova\prj_Henk
  • to_sever Geeft aan of html gemaakt wordt voor locaal gebruik op de laptop, of voor gebruik op de webserver.
  • domain Het domain wordt niet veel gebruikt, omdat de interne links op de pagina's als relatieve links worden geschreven, bijvoorbeeld /websites/voorbeeld.html. Maar voor speciale toepassingen is het domain toch nodig. Bijvoorbeeld om een sitemap.xml file te genereren.
  • root de naam is van de folder waarin de gegenereerde HTML-files worden getest of gebruikt.
    Als er gegeneerd wordt om lokaal te testen, dan zal de root gelijk zijn aan de project/site folder; in dit voorbeeld D:\Documents\Projecten\Supernova\prj_Henk\site. Maar als er voldoende getest is en de gegenereerd HTML-files overgezet kunnen worden naar de webserver, dan zal het root argument meestal de waarde / hebben. De root variabele wordt gebruikt in de templates, bijvoorbeeld: href="{{root}}assets/css/custom.css".

De generator kan via de command line of via terminal worden opgestart. template file

Het genereren via de command line werkt prima, maar het komt toch wat primitief over. Een grafisch applicatie is mooier. In principe kan men binnen Python ook grafische applicaties bouwen, maar dat is niet het sterkste punt van Python. Er zijn tools waarmee dat een stuk gemakkelijker kan. Ik heb Streamlit gebruikt om een grafische schil om Supernova te maken. Die grafische schil draait in een browser, lokaal op de laptop.

template file

Gebruikerservaring

Normale werkwijze voor het maken van een nieuwe webpagina met behulp van Supernova is dat er eerst veel gewerkt en getest wordt op de lokale folder. Als alles naar tevredenheid werkt, genereer ik de hele site met de optie root='/' waarna ik de hele project/sites folder, inclusief alle subfolders, naar de public html folder op de webserver kopieer. Dat doe ik met FileZilla.

Ook als ik slechts één pagina toevoeg, dan genereer ik de hele site opnieuw en kopieer ik de hele site folder, inclusief alle subfolders, naar public_tml op de webserver. Daarmee overschrijf ik alle bestaande bestanden op de server. Als er dan een verbetering is aangebracht in de template, dan zit die aanpassing in alle pagina's.

Dat werkt heel prettig. En het bespaart tijd, vooral als er een aanpassing doorgevoerd moet worden voor alle pagina's. En nog belangrijker: het zorgt ervoor dat de structuur van alle webpagina's hetzelfde is.

Uiteraard heeft Supernova alleen maar nut wanneer er een website gemaakt moet worden, die veel contentpagina's heeft. In één van mijn volgende projecten heb ik een website gemaakt die maar één pagina had (index.html). Wel een grote pagina, met veel tekst en afbeeldingen, maar toch maar één pagina. Voor die site heb ik Supernova niet gebruikt.

Er zijn twee punten waar ik aan moest wennen.
Ten eerste moet je na elke (kleine) aanpassing opnieuw genereren moet om de aanpassing in het eindresultaat te zien. Dat is een extra stap. In plaats van Wijzigen, Opslaan en Verversen moet ik nu: Wijzigen, Opslaan, Her-genereren en Verversen om het eindresultaat te zien.

Ten tweede moest ik er aan wennen dat Windows niet al te kritisch is wat bestandsnamen betreft. Bestandsnamen zijn niet case-sensitief. Een verwijzing naar 'fig1.PNG' werkt prima onder windows, ook als het bestand in werkelijkheid 'Fig1.png' heet. Zo'n fout in de content files ontdek je dus niet bij het testen op de lokale Windows computer. Dat merk je pas na het kopiëren van de webpagina naar de webserver. En dat is een beetje laat. Of je merkt het helemaal niet, en dat is nog erger.

Maar ook dat went snel. Ik vind het nu heel prettig en makkelijk om met Supervova websites te maken.