ACA Group Blog | Inzichten over Softwareontwikkeling, UX/UI, Data & Innovatie

Snel schaalbare applicaties ontwikkelen met VueJS en Firebase (deel één)

Geschreven door Dorien Jorissen | 10-aug-2018 4:00:00

Tegenwoordig vinden we heel veel van de functionaliteit die vroeger in de backend werd afgehandeld nu in de frontend. Ik laat je als frontend designer zien hoe je een simpele SPA (Single Page Application) kunt creëren zonder gedoe met onderhoud in de backend.

Wat maken we?

We maken een eenvoudige CRUD (Create, Read, Update, Delete) applicatie in de vorm van een notitie app. Voor deze demo gebruiken we:VueJS CLI,VueRouter,ElementUI enGoogle Firebase.

Houd er rekening mee dat dit deel één is van een blogpostserie. In dit deel gaan we Firebase opzetten, VueJS lokaal installeren via de command line interface, de nodige views aanmaken en de routing instellen. Onze databaseverbinding wordt beperkt tot 'alleen lezen'. Het aanmaken, bijwerken en verwijderen van notities via onze app zal binnenkort beschikbaar zijn in deel twee van de blogpostserie.

Waarom VueJS?

Er zijn veel frameworks en technologieën die geschikt kunnen zijn voor dit project, dus de keuze voor VueJS is een persoonlijke voorkeur. Ik heb VueJS boven andere frameworks gekozen omdat:

  • VueJS maakt gebruik van HTML templates, waardoor het veel leesbaarder aanvoelt dan bijvoorbeeld JSX in React.
  • De leercurve is veel acceptabeler voor frontend ontwikkelaars die meer naar design neigen dan naar backend ontwikkeling, wat goed past bij ons creatieve team bij ACA.
  • Componenten in één bestand (HTML/CSS/JS) en hun grote herbruikbaarheid.
  • Het wordt geleverd met een geïntegreerde state manager (vuex) en router (vue-router) in plaats van afhankelijk te zijn van externe bibliotheken zoals bijvoorbeeld redux.
  • Het is lichtgewicht en gemakkelijk te integreren in bestaande projecten. Angular alleen is enorm en heeft een behoorlijk steile leercurve. De aanpak van React voelt voor mij gewoon veel te rommelig.

Aan de andere kant heeft het ook wat nadelen:

  • Het is minder aangepast in het Westen. VueJS is gemaakt door Evan You, een voormalige Google-ingenieur. Evan heeft Chinese roots, en VueJS heeft veel marktaandeel in China. Het kan voorkomen dat je wat Chinese documentatie tegenkomt als je op zoek bent naar addons van derden.
  • Er zijn niet zoveel VueJS banen / ontwikkelaars beschikbaar in Europa, hoewel er steeds meer kennis over het framework beschikbaar komt.
  • Het wordt (nog) niet ondersteund / overgenomen door een multinational, als je dat belangrijk vindt. Maar het heeft veel Github-bijdragen van veel mensen die gewoon van VueJS houden. Het was vorig jaar het #1 meest gewaardeerde project op Github.

Waarom Firebase?

Firebase is een geweldige service waarmee je je kunt richten op wat het belangrijkst is: het maken van fantastische gebruikerservaringen. Firebase gebruiken betekent dat je geen servers hoeft te beheren of API's hoeft te schrijven. Firebase kan je hosting, authenticatietool, API en datastore zijn. Het kan worden aangepast aan veel van je behoeften en bovendien kan het perfect meeschalen met je project als het in de loop van de tijd groeit.

Het 'Spark'-plan, dat helemaal gratis is, biedt je tot 100 gelijktijdige verbindingen, 1GB opslag en een downloadlimiet van 10GB. Genoeg voor een klein project, startups of voor indie-ontwikkelaars die hun idee(ën) gevalideerd willen hebben.

De applicatie maken

Afhankelijk van je vaardigheidsniveau duurt hetongeveer30 tot 60 minuten omde volgende stappen uit te voeren.

Stap 1: Onze Firebase-omgeving opzetten

Ga naar https://firebase.google.com/en meld je aan met je Google-account. Zodra dat gedaan is, ga je naar de Firebase console en maak je een nieuw project aan. Ik heb het mijne 'FireNotes' genoemd.

Omdat we de Firestore-database gaan gebruiken, ga je naar het tabblad 'Database' in de zijbalk onder de sectie 'Ontwikkelen' en schakel je databasegebruik in testmodus* in, zoals hieronder te zien is.

* Belangrijkeopmerking: dit geeft iedereen toegang tot je database. Als je van plan bent een project uit te brengen met Firebase, verdiep je dan in dedocumentatie over databaserechten enstel het goed in.

Laten we nu wat notities toevoegen aan onze database. Voeg een nieuwe collectie toe en noem deze 'notes'. Dit wordt de bovenliggende verzameling waar al onze notities in staan. Vul deze met een aantal dummy notities zoals in de schermafbeelding hieronder, met een automatische ID, postdatum, titel en inhoud:

Stap 2: Ons VueJS Project opzetten

Redelijk eenvoudig tot nu toe, toch? Laten we nu de focus verleggen naar onze applicatie.

Open je console en navigeer naar je projecten map. Ervan uitgaande dat jeNPM al geïnstalleerdhebt, installeer je Vue CLI via het volgende commando:

npm install -g @vue/cli
Standaard

Laten we vervolgens je project opstarten met het volgende commando:

vue create firenotes
Standaard

Dit vraagt je om een keuze voor standaard of handmatige voorinstelling. Laten we nu beginnen met de standaard optie met NPM. Ga na de installatie naar je map firenotes en start je webserver met het volgende commando:

npm run serve
Standaard

Als u naar het opgegeven IP-adres navigeert (normaal gesproken localhost:8080), ziet u de standaard 'hello world'-weergave die Vue biedt:

Stap 3: De hoofdlay-out maken

Laten we nu visualiseren hoe onze applicatie eruit zou moeten zien. Ik ga in deze blogpost niet door de styling details heen, dus ik gebruik de ElementUI kit om de dingen te versnellen.

# In je ~/projects/appname map npm install element-ui -S 
Standaard

Ga naar /src/main.js en voeg de ElementUI imports toe en registreer het in onze VueJS app, direct onder de 'import Vue' zoals hieronder getoond:

import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI)
Standaard

Nu kunnen we ElementUI componenten gaan gebruiken in onze sjablonen. Ik heb het Vue-logo vervangen door mijn eigen logo(hier te downloaden) en het App.vue-sjabloon als volgt gewijzigd:

<template> <div id="app"> <el-container> <el-header> <img class="logo" src="./assets/logo.png" /> </el-header> <el-container> <el-aside width="300px"> <el-menu default-active="home" class="el-menu-vertical-demo">
            <el-menu-item index="home"> <i class="el-icon-menu"></i> <span>Home</span> </el-menu-item> <el-menu-item index="notes"> <i class="el-icon-document"></i> <span>Notes</span> </el-menu-item> </el-menu>.
        </el-aside> <el-main> <h1>Welkom bij FireNotes</h1> <p>Een eenvoudige CRUD-toepassing (Create, Read, Update, Delete) in de vorm van een notitie-app.</p> <p>Voor deze toepassing gebruiken we: VueJS CLI, VueRouter, ElementUI en Google Firebase.</p> </el-main> </el-container> </el-container> </div> </template> <script> export default {naam: 'App' } } </script> <style> html, body { margin: 0; } #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; } .el-header { border-bottom: 1px solid #e6e6e6; display: flex; align-items: center; width: 100%; } .el-header button { float: right; } .el-menu-item { border-bottom: 1px solid #e6e6e6; } .logo { max-width: 50%; max-height: 50%; margin-right: auto; } </style>
Standaard

Zo ziet het eruit:

Stap 4: Onze routes instellen

Tot zover alles goed! Vervolgens kunnen we vue-router installeren, wat de officiële VueJS router is. Het integreert diep met de kern van je VueJS-applicatie, waardoor single page-applicaties een fluitje van een cent worden. Met vue-router kunnen we navigeren naar onze notitiepagina, die we later zullen instellen.

# In je ~/projects/appname map npm install vue-router
Standaard

Net als ElementUI moet de vue-router worden geïmporteerd en geregistreerd binnen onze VueJS app. Ga naar main.js en vervang deze door de volgende code:

import Vue from 'vue' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI) import VueRouter from 'vue-router' Vue.use(VueRouter) import App from '@/App' import HelloWorld from '@/components/HelloWorld' import Notes from '@/components/Notes' const routes = [ { path: '*', redirect: '/home' }, { path: '/', redirect: '/home' }, { path: '/home', name: 'HelloWorld', component: HelloWorld }, { path: '/notes', name: 'Notes', component: Notes }, ] const router = new VueRouter({routes }) new Vue({ el: '#app', router: router, render: h => h(App), components: { App } })
Standaard

Wat is hier gebeurd? In principe hebben we de URL's van onze twee navigatie-items gespecificeerd en ze toegewezen aan twee verschillende componenten. We hebben ook regels toegevoegd om automatisch naar de homepage te gaan bij het laden of wanneer een URL een niet-geregistreerde route triggert. Last but not least hebben we de routes geregistreerd via 'new VueRouter', die nu is ingebed in de kern van onze applicatie omdat deze wordt doorgegeven aan onze 'new Vue'-instantie.

Dit opslaan zal waarschijnlijk wat fouten veroorzaken, omdat we nog niets gedaan hebben aan de Notes component. Laten we een eenvoudig Notes.vue-bestand maken in de map components.

<template> <div class="notes"> Notities komen hier </div> </template> <script> export default {naam: 'Notes' } </script>
Standaard

Vervolgens moeten we ervoor zorgen dat onze app de juiste onderdelen weergeeft op basis van deze gespecificeerde routes. Dit vereist enkele wijzigingen in ons App.vue-bestand voor zowel de navigatie als het inhoudspaneel (el-main).

<template> <div id="app"> <el-container> <el-header> <img class="logo" src="./assets/logo.png" /> </el-header> <el-container> <el-aside width="300px"> <el-menu default-active="home" :router="true" class="el-menu-vertical-demo"> <el-menu-item index="home"> <i class="el-icon-menu"></i> <span>Home</span> </el-menu-item> <el-menu-item index="notes"> <i class="el-icon-document"></i> <span>Noten</span> </el-menu-item> </el-menu> </el-aside> <el-main> <router-view/> </el-main> </el-container> </el-container> </div> </template> <script> export default {naam: 'App'}} </script> <style> html, body { margin: 0; } #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2c3e50; }. el-header { border-bottom: 1px solid #e6e6e6; display: flex; align-items: center; width: 100%; }. el-header button { float: right; }. el-menu-item { border-bottom: 1px solid #e6e6e6; }. logo { max-width: 50%; max-height: 50%; margin-right: auto; }</style>
CSS

Hier hebben we router="true" toegevoegd aan het component, waardoor de 's indexen kunnen worden gebruikt als 'pad' om de route-actie te activeren. We hebben ook de introductiekop en paragrafen verplaatst naar HelloWorld.vue (dat zou jij ook moeten doen ;-)) en vervangen door<router-view/>. Nu is de router volledig verantwoordelijk voor welk component wordt weergegeven in dat paneel. Geweldig!

Vervolgens gaan we Notes.vue aanpassen om daadwerkelijk notities weer te geven. Voorlopig is alle inhoud statisch. Later zullen we de notitietabel vullen met gegevens uit onze Firestore-database.

<template> <div class="notes"> <h1> Notities <el-button type="primary" size="medium"><i class="el-icon-circle-plus"></i> Notitie toevoegen</el-button> </h1> <el-table :data="tableData" border> <el-table-column type="expand"> <template slot-scope="props"><p></p></template> </el-table-column> <el-table-column label="Note title"> <template slot-scope="props"> </template> </el-table-column> <el-table-column label="Datum toegevoegd/gewijzigd" prop="date"> </el-table-column> <el-table-column fixed="right" label="" width="90"> <template slot-scope="scope"> <el-button type="info" size="small" icon="el-icon-edit" circle></el-button> <el-button type="danger" size="small" icon="el-icon-delete" circle style="margin-left:  5px;"></el-button> </template> </el-table-column> </el-table> </div> </template> <script> export default {naam: 'Notities', data() {retour {tableData: [ {datum: '2018-07-03', naam: 'Lorem ipsum dolor sit amet', details: 'Lorem Ipsum is simpelweg dummytekst van de druk- en zetindustrie.  Lorem Ipsum is al de standaard dummytekst van de industrie sinds de jaren 1500, toen een onbekende drukker een lettergalei nam en deze door elkaar husselde om er een specimenboek van te maken." }}, {datum: "2018-07-02", naam: "Consectetur adipiscing", details: 'Lorem Ipsum is simpelweg dummytekst van de druk- en zetindustrie.  Lorem Ipsum is de standaard dummytekst van de industrie sinds de jaren 1500, toen een onbekende drukker een proefdruk nam en deze door elkaar husselde om een proefdrukboek te maken.'}] };} </script> <style> h1 { margin-top: 0; display: flex; align-items: center; width: 100%; }.el-button { margin-left: auto; }.el-collapse-item__header { font-size: 16px; }.el-table { font-size: 14px; font-weight: 700; }.el-table__expanded-cell p { font-size: 16px; font-weight: 400; }.el-table th { background: #fafafa; }.el-table th > .cell { color: #333; }</style>
CSS

Zo ziet het eruit:

Stap 5: Firebase koppelen aan ons project

Geweldig! Nu staat alles klaar om de statische applicatie om te zetten naar een Firestore data driven applicatie. Laten we de afhankelijkheden installeren om verbinding te maken met Firebase:

# In je ~/projects/appname map npm install firebase
Standaard
import firebase from 'firebase' import 'firebase/firestore' firebase.initializeApp({ apiKey: '', projectId: '' }) export const db = firebase.firestore() const settings = { timestampsInSnapshots: true } db.settings(settings)
Standaard

Hier moet je nog de 'apiKey' en 'projectId' invullen, die je kunt vinden onder de link Projectinstellingen via het tandwiel:

Ga vervolgens naar het Notes.vue component waar we de statische array van notities leegmaken en vullen met de notities die we eerder in onze Firestore database hebben aangemaakt. We hebben ook een lege tekst op de tabel gedefinieerd, die zal worden getoond terwijl er gegevens in onze tabel worden geladen.

<template> <div class="notes"> <h1> Notities <el-button type="primary" size="medium"><i class="el-icon-circle-plus"></i> Notitie toevoegen</el-button> </h1> <el-table :data="tableData" empty-text="Bezig met laden, of geen records te tonen." border> <el-table-column type="expand"> <template slot-scope="props"><p></p></template> </el-table-column> <el-table-column label="Note title"> <template slot-scope="props"> </template> </el-table-column> <el-table-column label="Datum toegevoegd/gewijzigd" prop="date"> </el-table-column> <el-table-column fixed="right" label="" width="90"> <template slot-scope="scope"> <el-button type="info" size="small" icon="el-icon-edit" circle></el-button> <el-button type="danger" size="small" icon="el-icon-delete" circle style="margin-left:  5px;"></el-button> </template> </el-table-column> </el-table> </div> </template> <script> import { db } from '@/main' export default {naam: 'Notes', data() { return { tableData: [] } }, created () { db.collection('notes').get().then(querySnapshot => { querySnapshot.forEach(doc => { const data = {' id': doc.id,' date': doc.data().date,' title': doc.data().title,' content': doc.data().content }this.tableData.push(data)})} </script> <style> h1 { margin-top: 0; display: flex; align-items: center; width: 100%; }.el-button { margin-left: auto; }.el-collapse-item__header { font-size: 16px; }.el-table { font-size: 14px; font-weight: 700; }.el-table__expanded-cell p { font-size: 16px; font-weight: 400; }.el-table th { background: #fafafa; }.el-table th > .cell { color: #333; }</style>
CSS

Dit zorgt ervoor dat de notities die we eerder handmatig hebben toegevoegd in onze Firestore-database te zien zijn in onze applicatie, waardoor deze iets minder statisch wordt. Geweldig succes!

Hoe nu verder?

In onze vervolg blogpost over dit onderwerp gaan we verder in op de overige functionaliteiten: het aanmaken, bijwerken en verwijderen van notities in onze Firebase database, volledig aangestuurd door onze VueJS app. Omdat we in de comments een vraag kregen over inlogfunctionaliteit, hebben we die ook toegevoegd als bonus!