Van Vue.js 2 naar Vue.js 3 - wat is nieuw?
Met de nieuwe versie van Vue.js komen een hoop nieuwe features, waaronder de belangrijke Composition API. Hoe verschilt Vue.js 2 van Vue.js 3?
Het frontend JavaScript-framework Vue.js heeft een reputatie opgebouwd als gebruiksvriendelijk en eenvoudig met Vue 2. Het relatief nieuwe Vue 3 zou het leven van developers nog makkelijker moeten maken en stukken onderhoudsvriendelijker zijn.
Vue 3 is min of meer de herschreven versie van Vue 2, maar met een aantal belangrijke wijzigingen en features. Wat Vue 3 allemaal op tafel legt en de grootste verschillen met Vue 2 legt onze frontend developer Jesper Ingels je in deze blog uit. Alvast een spoiler: de Composition API is het pronkstuk.
Op deze pagina te vinden
Wat is Vue Storefront?
Vue Storefront is een headless JavaScript framework binnen e-commerce. Het mooie van ‘headless’ is dat je het kunt aansluiten op verschillende platformen, zoals Magento of Shopware voor productdata en koppelingen. Maar ook op een Product Information Management (PIM) systeem zoals PimCore om alle productdata te beheren en in te laden.
Een ander voordeel van Vue Storefront is dat het over Progressive Web App (PWA) functionaliteiten beschikt. Concreet betekent dit:
Een goede ‘offline’ gebruikerservaring, waarbij je de pagina nog wel kunt blijven gebruiken wanneer je geen internet hebt;
Dat de snelheid van de webshop potentieel erg goed is. Omdat je als developer meer controle hebt over server-side rendering en client-side rendering;
Het downloaden van de webshop als app. Hierbij download je de PWA vanuit de browser en zie je een app-icoon van de webshop op je telefoon.
Vue Storefront cases
Bij Bluebird Day werken we voor verschillende klanten met het Vue Storefront framework, bijvoorbeeld voor de luxe cafetaria Kwalitaria.
Voor Kwalitaria.nl hebben we een kassasysteem aangesloten op Vue Storefront om de productdata op te halen en bestellingen te verwerken.
Een ander voorbeeld van een Vue Storefront project is outdoorwinkel Vrijbuiter:
Hierbij hebben we Magento op Vue Storefront aangesloten en gebruiken we de Magento checkout als ‘externe’ checkout.
Vue Storefront 2
Vue Storefront 2 is de opvolger van Vue Storefront 1. En zoals de naam - ‘Vue’ - al doet vermoeden is het framework gebaseerd op het bekende JavaScript framework Vue.js.
Het grootste verschil tussen Vue Storefront 1 en Vue Storefront 2 is dat features van de nieuwste versie van Vue.js worden gebruikt, namelijk Vue.js 3. Daarom gaan we hieronder dieper in op de verschillen tussen Vue 2 en Vue 3.
Vue 3: drie nieuwe features
Wat precies de nieuwe wijzigingen van Vue 3 ten opzichte van Vue 2 zijn, leggen we je hieronder uit. Met stipt op één is dat de Composition API, die we later in deze blog uitvoerig bespreken. Maar ook de teleport functionaliteit en fragments features zijn het benoemen waard.
1 - Teleport
Met de teleport functionaliteit kun je iets op een andere plek laten renderen dan dat het staat in het Vue project.
Waarom wil je dit?
Een goede use-case voor deze functionaliteit zou zijn een modal met een backdrop.
Stel, je hebt een list en hierin zit een button die een modal openklapt met backdrop. Het is niet erg mooi en semantisch niet helemaal correct dat deze in het list item komen te staan. Aangezien de backdrop de gehele pagina bedekt heb je deze liever in de root van je body.
Introducing teleport
Je wrapt je backdrop en modal (dialog) met het teleport component. Hierbij kun je door middel van een CSS selector in de property ‘to’ aangeven, waar je wilt dat de inhoud van het teleport component naartoe ‘geteleporteerd’ moet worden bij het renderen van de pagina.
2 - Fragments / Multiple root nodes
Met de komst van Vue 3 is het toegestaan om meerdere ‘root nodes’ te hebben in je component. Deze feature noemen ze ‘fragments’.
In Vue 2 was het verplicht om één enkel element in de root van je component te hebben staan. Dus wanneer je meerdere componenten naast elkaar wilde inladen, moest je deze wrappen met een element. Dit element is vaak onnodig en draagt niks bij aan het project.
De fragments feature is daarom meer dan welkom. Het is dus vanaf Vue 3 wel mogelijk om elementen en componenten in de root naast elkaar in te laden. Daardoor moet je minder onnodige code te schrijven. Hoe fijn is dat!
3 - Composition API
De Composition API is eigenlijk de grootste nieuwe feature in Vue.js 3 en deze wordt apart ingeladen in Vue Storefront 2:
In Vue Storefront zie je duidelijk de verschillen in bijvoorbeeld het Product.vue component, hieronder afgebeeld.
Vue Storefront 1 (Zonder Composition API):
Vue Storefront 2 (Met Composition API):
Zoals te zien hierboven, de logica ziet er nu compleet anders uit. Hoe dit precies zit lees je verder in dit artikel.
Options API naar Composition API
In het kort is het verschil tussen de ‘oude’ Options API en de nieuwe Composition API dat je data properties, methods, computed en watchers nu allemaal onder de setup() method vallen. Waarom je dit wil, vertel ik je zo.
Hieronder zie je links Vue 2 met de Options API, rechts zie je Vue met de Composition API in het rood omcirkeld. Het is het allereerste event dat wordt uitgevoerd binnen de nieuwe Vue lifecycle setup() method.
Omdat dit zo vroeg in de Vue lifecycle gebeurt, is bijvoorbeeld het ‘this’ keyword niet beschikbaar in de setup() method. Dit komt omdat het component nog niet geïnitialiseerd is. Hierdoor zijn ook je component properties nog niet beschikbaar.
Options API
Voordat we het over de Composition API hebben, is het goed om even terug te blikken op de ‘oude’ Options API die Vue 2 gebruikt.
Data()
In de data method kun je je data properties kwijt, dit zijn eigenlijk een soort variabelen waarin je data opslaat waarmee je gaat werken in je component. Het handige van deze data properties in Vue is dat ze ‘reactive’ zijn. Dit betekent dat Vue automatisch detecteert wanneer deze aangepast worden en deze aanpassing bijvoorbeeld automatisch output naar je template, wanneer je deze daar output.
Methods()
In je methods object plaats je methods, dus eigenlijk gewoon functies zoals je gewend bent in JavaScript. Deze methods kun je overal in je component aanroepen om mee te werken.
Computed()
In het voorbeeld zie je bij het roze kruisje staan dat er logica in staat. Dit wil je eigenlijk niet, het is een design pattern om je logica van je template zoveel mogelijk gescheiden te houden. Daarom gebruiken we in Vue een method of een computed property om deze logica naar de template te exposen.
Waarom computed?
In principe kun je voor al je logica methods gebruiken en heb je computed properties niet per se nodig. Het belangrijke verschil tussen een method en een computed property is dat de computed property gecached wordt door Vue. Dit houdt in dat de functie pas getriggered wordt als de reactive data die in de computed property staat aangepast wordt. Een method wordt bij het inladen van de pagina en wanneer deze wordt aangeroepen altijd uitgevoerd.
Wanneer je een hoop methods kunt vervangen voor computed properties is dit dus beter voor performance aangezien deze niet meer constant worden uitgevoerd.
Watch()
Met een watcher kun je een reactive data property ‘watchen’, in de gaten houden dus. Naast data properties kun je ook computed properties watchen. Op het moment dat de waarde hiervan verandert zal de watcher uitgevoerd worden. Als parameters van je watcher heb je de nieuwe waarde en oude waarde tot je beschikking.
Dat was de Options API, nu terug naar de vernieuwde Composition API.
Composition API
Met de komst van de Composition API is de Vue lifecycle ook aangepast. Hieronder leggen we uit hoe de data properties, methods, computed properties en watchers gebruikt kunnen worden in de nieuwe Composition API.
Data()
Data, methods, computed en watch bevinden zich met de Composition API binnen de setup() method. Hiermee verdwijnt eigenlijk het data object en definieer je nu ‘normale’ variabelen om je data in op te slaan. Hierdoor ontstaat wel een probleem, namelijk dat deze data niet meer reactive is. Daarom introduceert Vue twee nieuwe methods: ‘ref’ en ‘reactive’.
Deze ref() en reactive() moet je apart importeren vanuit het Vue framework.
Ref()
De ref zorgt ervoor dat je variabele reactive wordt, door onderwater gebruik te maken van een JavaScript proxy. Wanneer je dus op een andere plek je variabele aanpast of uitleest, handelt deze ref() dit af door middel van getters en setters.
Let op: Dit betekent ook dat de ref zelf wel reactive is, maar de waarde in je ref is op zichzelf niet reactive. Zoals je in de afbeelding hieronder ziet worden de waardes van het ‘userData’ object op twee verschillende manieren exposed.
Wanneer je dit doet door middel van ‘userData.value.name’ lees je eigenlijk éénmalig de waarde uit en expose je deze naar de template. Wanneer je vervolgens in je template deze waarde aanpast detecteert Vue deze aanpassing niet, omdat dit dus niet ‘reactive’ is.
Wanneer je dit doet door userData in z’n geheel als object te exposen naar de template en vervolgens in je template de waardes van dit object aanpast zal Vue deze changes wel detecteren.
Reactive()
De reactive method werkt eigenlijk bijna precies hetzelfde als een ref, alleen is de reactive specifiek gemaakt om een object in op te slaan.
Zoals je hierboven ziet is ‘userData’ een ref en ‘carData’ een reactive. Beide bevatten ze een object. Wanneer je de ref uitleest, moet je eerst nog ‘value’ openen voordat je echt bij het object komt. Bij een reactive is het niet nodig om eerst ‘value’ nog te openen, dit handelt de reactive voor je af. Een reactive is altijd een object en een ref kan alle waardes bevatten.
Methods()
Methods worden nu eigenlijk gewone functies zoals je gewend bent in vanilla JavaScript.
Computed()
De computed method moet je nu apart importeren vanuit Vue en kun je aanroepen zoals je in de afbeelding ziet. Als argument van de computed property geef je de callback functie mee met daarin de logica van de computed property.
Watch()
De watcher moet je ook apart importeren vanuit Vue net zoals de computed en ref. Wanneer je de watcher aanroept geef je als eerste argument de ‘dependency’ mee die je wilt watchen, dit kan bijvoorbeeld een ref zijn of een computed property. Ook heb je de oldValue en newValue beschikbaar als arguments van de functie.
De Composition API: waarom en wanneer?
Nu je de verschillen tussen de Option API en de Composition API kent, vraag je jezelf wellicht af: waarom zou je de Composition API gebruiken en wanneer?
Waarom?
Door de Composition API te gebruiken kun je een complex component wat overzichtelijker maken doordat al je logica binnen de setup() method staat. Binnen de setup() method kun je de logica groeperen op basis van functionaliteit. Bijvoorbeeld logica die iets doet met user data kun je nu groeperen waarbij je dus je functies, computed properties, watchers etc. bij elkaar zet.
Bij de Options API wordt je logica gegroepeerd door je methods, computed properties, enzovoort. Hierdoor moet je als developer veel heen en weer scrollen om de logica die bij elkaar hoort te begrijpen.
Belangrijk: Het gebruik van de Composition API is optioneel, je kunt dus de Options API en Composition API door elkaar heen gebruiken.
Wanneer wel en wanneer niet?
Voor de performance is het voordeliger om in al je componenten de Composition API te gebruiken. Persoonlijk vind ik de Options API fijner werken als developer dan de Composition API. De Options API is wat duidelijker en Vue regelt automatisch een hoop zaken voor je zoals bijvoorbeeld ‘reactivity’. Dit is ook wat Vue zo geliefd maakt bij developers. Met de Composition API moet je dit meer zelf managen als developer, waardoor ook de leercurve iets steiler wordt.
Vue 2 naar Vue 3
Stel, je wilt van Vue 2 naar Vue 3. Welke grove stappen moet je dan precies ondernemen?
Installatie
In Vue 2 gaat de installatie als volgt:
Je roept de Vue constructor function aan. Hierin definieer je op welk element je Vue wilt mounten / initialiseren (‘#app’ in het geval van het voorbeeld).
Je kunt eventueel wat data in je data property zetten. Verder definieer je je methods etc.
In Vue 3 gaat de installatie als volgt:
I.p.v. de Vue constructor functie roep je nu de createApp method aan, zoals de naam je al doet vermoeden maak je hiermee de Vue app aan. Deze is nog niet gemount.
Voor het mounten van je app roep je een aparte method aan op je app genaamd ‘mount()’
Een belangrijk verschil is dat je data property nu altijd een method is in plaats van een object. Dit levert anders een error op.
Bovenstaande punten zijn dus niet backwards compatible, de Vue 2 manier zal kapot gaan in Vue 3.
Conclusie
In Vue.js 3 krijg je een hoop kleinere, leuke features en een nieuwe manier van werken. Deze nieuwe manier van werken met de Composition API is in principe optioneel. Wel gaat de performance van je Vue app omhoog wanneer je de Composition API in alle componenten gebruikt. Dus vanuit dat oogpunt is het gebruik van de Composition API misschien toch niet zo optioneel.
Uiteindelijk is het aan de developers en het team zelf om te bepalen hoe ze hiermee omgaan. Zelf zou ik zeggen: blijf de Options API gebruiken voor kleine componenten zodat je iets dat simpel is, ook simpel houdt. Gebruik wel de Composition API voor componenten die complex zijn, zodat in dat geval complex simpel wordt.