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 naar static HTML, 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 namen van deze 3 subfolders moeten exact zo zijn als aangegeven: content, templates en site . De naam van de projectfolder kan vrij gekozen worden.

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-out kwesties. 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.

Template files

De algemene vormingeving, de lay-out en de navigatie van pagina's van de site wordt vastgelegd in "Template Files". Samen met de CSS-files bepalen die hoe de gegenereerde site er uit komt te zien. De template files en de CSS kan gezien worden als een "thema". Het thema van deze site heb ik de naam "Gemini" gegeven.
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 z'n geheel naar de webserver wordt overgezet. Behalve HTML-files moet die folder dus ook de images, javascript files, de CSS-files en de .htacces file bevaten. Dat kan wat Supernova betreft op allerlei manieren, zolang de inhoud van de content files en de template files consistent is met elkaar en met de gedefinieerde subfolders.

Voor deze site heb ik ervoor gekozen om 2 extra subfolders op te nemen in de sites folder: assets en images. En bovendien hebben de functionele subfolders zoals bv websites allemaal hun eigen images folder.

En die structuur zie je ook terugkomen in de inhoud van de content files en de template files. De code voor het weergeven van bijvoorbeeld een afbeelding, ziet er in de template file en in de content file als volgt uit:
<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 is, 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 direct als /websites/voorbeeld.html geschreven worden. worden geschreven. 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. Het genereren gaat snel. Bijvoobeeld: 40 HTML files worden in een fractie van een seconde gegenereerd. 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 bij 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_tml 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 of verandering is aangebracht in de template, dan zit die aanpassing of verbetering 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 content pagina's heeft. In één van mijn volgende projecten heb ik een website gemaakt die maar één pagina had (index.html); daar had ik dus niets aan Supernova.

Er zijn twee punten waar ik aan moest wennen.
Ten eerste moet je na elke (kleine) aanpassing opnieuw genereren 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, Hergenereren en Verversen om het eindresultaat te zien.

Ten tweede is 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 HTML ontdek je dus niet bij het testen op de lokale windows computer. Dat merk je pas na het kopiëren van de site naar de linux server. En dat is een beetje laat.