Preview-omgeving
Tijdens dit project heb ik me op technisch vlak vooral gefocust op het bouwen van een preview omgeving in de context van een headless opzet. Vandaar ook dat er best wel wat iteraties overheen gegaan zijn om uiteindelijk tot een (alsnog niet zo sterke) oplossing te komen.
1. Live website hijacken met JavaScript
In de eerste versie van de preview omgeving had ik ervoor gekozen om de hele website te hijacken met JavaScript zodra er vanuit de Storyblok SDK bekend was dat je in de preview omgeving zit:
De updatePreview functie zorgt er hier voor dat alle HTML opnieuw geïnjecteerd wordt in de pagina middels JavaScript. Dit betekende enerzijds dat we altijd de Storyblok SDK moesten in laden op de website (zie onderstaand). Daarnaast betekende dit dat we alle componenten die we al een keer gebouwd hadden in HTML ook nog eens moesten maken in JavaScript, dubbel werk voor developers die nieuwe componenten willen maken dus... niet bepaald ideaal.
Het eerste wat ik daarom wilde veranderen om de performance van de live website niet te beïnvloeden was het verplaatsen van de preview omgeving naar z'n eigen dedicated branch zodat we het script niet hoeven in te laden op de live website, maar alleen op de preview branch.
Dit maakt dat we geen hinder ondervinden van het inladen van de Storyblok SDK op de live website maar dat het alleen ingeladen hoeft te worden binnen de preview omgeving in het CMS, waar performance minder van belang is.
2. Aparte preview branch hijacken met JavaScript
Een aparte branch dus. Dit was best eenvoudig om te doen aangezien ik hiervoor alleen een aparte preview branch heb hoeven aanmaken. Vervolgens kon ik via ons deployment platform Vercel weer ervoor zorgen dat de preview branch ook als een live website ergens online staat.
Eigenlijk deden we op die branch precies hetzelfde als bovenstaand, alleen omdat die versie van de website dus ingeladen wordt in het CMS en niet voor bezoekers bedoeld is ondervind een bezoeker van de website nu geen hinder meer van het inladen van meerdere scripts.
Echter, developers moesten nog steeds twee keer hun componenten schrijven, éénmaal in HTML en éénmaal in JavaScript voor de preview omgeving. Dit betekent niet alleen dat ze dubbel werkt moeten doen, maar ook nog eens dat er een hogere drempel is om te werken aan de website aangezien ze dus ook nog eens moesten weten hoe dat dan werkt in JavaScript etc. (dit is minimaal iets wat je pas bij Web Apps From Scratch leert maar we willen ook dat er minder ervaren developers aan kunnen werken) dus moest er een betere oplossing komen.
3. Weghalen van JS hijacking, updaten via een webhook
Ik vervolgens besloten om alle hijacking met JavaScript uit de preview omgeving te slopen zodat dit eenvoudiger zou worden voor de developers om mee te werken aan het project.
Dit zorgde helaas weer voor een nieuw probleem: we hebben geen live updates meer, daarvoor moet je pushen naar de preview branch op GitHub. Aangezien nieuwe developers net als ons de workflow aan moesten houden van branches en PR's zou de live preview pas updaten als er een nieuw component gebouwd is o.i.d...
Daarnaast kan een niet-developer nu niet meer (relatief) eenvoudig de wijzigingen zien die hij of zij in de content heeft gemaakt, iets wat met de eerdere JavaScript oplossing wel het geval was. Daarom kwam ik met dezelfde oplossing die we ook voor de live omgeving gebruiken: webhooks.
Middels een webhook en integratie met het CMS (hoe dit werkt is eerder beschreven in Updaten van een statische site) kan nu de preview omgeving met een druk op de knop geüpdatet worden.
Het volgende probleem dat ik tegenkwam bij het bouwen van de preview omgeving is dat, nu het in een aparte branch staat, out of sync is met de live website... Als we de live website zouden updaten met allemaal nieuwe, toffe features gaat deze op den duur flink voorlopen op de preview omgeving.
In de volgende iteratie heb ik er dus voor gezorgd dat als de live website geüpdatet wordt, dat de preview omgeving dan eveneens geüpdatet wordt (yay version control, yay GitHub).
4. Preview branch geautomatiseerd syncen middels GitHub Actions
Hoewel je dit natuurlijk handmatig zou kunnen doen als developer door elke keer dat de live website is geüpdatet even git merge master te doen op de preview-branch leek me dat vrij omslachtig, helemaal wanneer je full-on gaat ontwikkelen aan de website.
Daarom besloot ik mezelf uit te dagen en eens te duiken in Continiuous Integration middels GitHub Actions. De workflow (zoals dat heet bij GitHub Actions) moest dus ervoor zorgen dat de preview branch een seintje krijgt dat het moet updaten wanneer er gepusht is naar de master branch.
Allereerst heb ik gezocht hoe je überhaupt een dusdanige workflow kan opzetten. Gelukkig heeft GitHub daar zelf een uitgebreide documentatie van, die ik dan ook grondig heb doorgelezen.
Daarna ben ik gaan kijken of andere developers al een soortgelijke oplossing hebben gebouwd, ik wil namelijk niet het wiel opnieuw uitvinden. Ik stuitte op een workflow die ongeveer doet wat we willen: het schiet een PR in bij branch X als er gepusht wordt naar branch Y. Dit is hoe het uiteindelijke script eruit ziet:
Nu zie je dus dat elke keer als er naar master gepusht wordt de preview branch wordt geüpdatet middels de GitHub Actions CI:
Tijdens ons gesprek met de opdrachtgever bleek echter alsnog dat de hele flow met het updaten van de preview omgeving middels een webhook in het CMS toch wat omslachtig bleek.
Daarom heb ik wederom een iteratie gedaan op de preview omgeving en ervoor gezorgd dat de preview branch geüpdatet wordt wanneer iemand in het CMS op 'opslaan' drukt. Iets wat in een CMS als Wordpress ook veelvoorkomend is.
5. Preview website geautomatiseerd laten updaten
Omdat het updaten vanuit een webhook toch wat onduidelijk en omslachtig bleek voor de content editors heb ik ervoor gekozen om de preview omgeving te laten updaten als iemand op 'opslaan' drukt in het CMS.
Daarvoor kon ik gelukkig de eerder beschreven Storyblok SDK gebruiken en luisteren naar een aantal events. Uiteindelijk is de webhook ook gewoon een link die ik heb kunnen fetchen met JavaScript, wanneer de link werd aangesproken werd er simpelweg een nieuwe versie van de preview omgeving 'gebuild'.
Allereerst was het zaak om een serverless functie te schrijven die voor ons een verzoek doet naar de webhook van de preview omgeving. Ik wilde niet dat de webhook openbaar werd en dus heb ik 'm in een environment variabele gezet:
Vervolgens heb ik, in het JavaScript bestand voor de preview omgeving, ervoor gezorgd dat de serverless functie op het juiste moment aangesproken wordt door te luisteren naar de events vanuit Storyblok:
Dit maakt dat de content-editor direct in het CMS feedback krijgt als hij of zij op 'opslaan' drukt. Na 30 seconden wordt de pagina automatisch ververst waardoor de preview omgeving daarna gebruik maakt van de nieuwe data.
6. Creëren van nieuwe pagina's onduidelijk
Ondanks alle eerdere verbeteringen bleek dat het nog onduidelijk was voor een eindgebruiker dat hij de website moest updaten voordat je kan werken aan het maken van een nieuwe pagina.
Wanneer je namelijk in het CMS een nieuwe pagina maakte kreeg je onze 404 pagina te zien omdat de pagina nog niet bestaat in de laatste versie van de preview omgeving:
Echter, de bovenstaande pagina geeft compleet verkeerde feedback aan een gebruiker als hij of zij in het CMS een nieuwe pagina maakt want "ik heb de pagina toch zojuist aangemaakt?".
Daarom leek het mij sterker om de eindgebruiker in deze net wat meer feedback te geven en duidelijker het proces naar voren te brengen in de interface. Hoewel zeker verre van ideaal is dit de beste oplossing waarmee ik heb kunnen komen in de context van een statisch gegenereerde website.
Wanneer een gebruiker in het CMS een nieuwe pagina aanmaakt krijgt hij of zij namelijk te zien dat de pagina gebouwd wordt, dat dit zo'n 30 seconden duurt en dat hij of zij op 'save' moet drukken om het proces te starten. We renderen dan als het ware een andere vorm van de 404 pagina:
Conclusie
Het bleek uiteindelijk aardig lastig om de preview omgeving goed te laten werken met een statisch gegenereerde website met minimale client-side JavaScript. Storyblok had hier ook wel wat voorbeelden voor maar die waren allemaal gefocust op JavaScript frameworks als Vue en React...
Het is best logisch dat het gebruik van een JavaScript framework het eenvoudiger maakt om de DOM te updaten, daar zijn ze immers voor bedoelt.
Echter, ik denk dat we er goed aan hebben gedaan om in het begin de keuze te maken zo dicht mogelijk bij vanilla JavaScript te blijven. Met name met het oog op toekomstige developers van CMD die anders ook nog een heel framework zouden moeten leren als ze de website willen onderhouden.
Aan de andere kant hadden we ook een server-side rendered website kunnen bouwen en dan had de preview omgeving ook naar behoren gewerkt, echter, dat haalt het hele principe van een statisch gegenereerde website weer onderuit. Het was al met al dus best een hoofdpijndossier geworden maar ik heb er wel enorm veel van geleerd, en daar gaat het mijns inziens bij zo'n project toch allemaal om.
Last updated