Colpisci il campo con Vue.js e Firestore

Pubblicato: 2022-03-10
Riepilogo rapido ↬ Creare un MVP significa creare molte funzionalità in un breve lasso di tempo. Vue.js è una buona opzione, con un minimo di standard architettonico e molta potenza pura. Tutto ciò di cui ha bisogno è un posto dove archiviare i dati.

Google Firebase ha una nuova possibilità di archiviazione dei dati chiamata "Firestore" (attualmente in fase beta) che si basa sul successo di Firebase Realtime Database , ma aggiunge alcune interessanti funzionalità. In questo articolo, imposteremo le basi di un'app Web utilizzando Vue.js e Firestore.

Diciamo che hai questa grande idea per un nuovo prodotto (es. il prossimo Twitter, Facebook o Instagram, perché non possiamo mai avere troppi social, giusto?). Per iniziare, si desidera realizzare un prototipo o un prodotto minimo vivibile ( MVP ) di questo prodotto. L'obiettivo è creare il nucleo dell'app il più velocemente possibile in modo da poterlo mostrare agli utenti e ottenere feedback e analizzare l'utilizzo. L'enfasi è fortemente sulla velocità di sviluppo e sull'iterazione rapida.

Ma prima di iniziare a costruire, il nostro fantastico prodotto ha bisogno di un nome. Chiamiamola "Amazeballs". Sarà legen - aspettalo - dario!

Ecco uno scatto di come me lo immagino:

Screenshot dell'app Amazeballs
La leggendaria app Amazeballs

La nostra app Amazeballs è, ovviamente, tutta incentrata sulla condivisione di bocconcini di formaggio della tua vita personale con gli amici, nei cosiddetti Balls. In alto c'è un modulo per pubblicare le Palle, sotto ci sono le Palle dei tuoi amici.

Quando crei un MVP, avrai bisogno di strumenti che ti diano la potenza per implementare rapidamente le funzionalità chiave e la flessibilità per aggiungere e modificare rapidamente le funzionalità in un secondo momento. La mia scelta ricade su Vue.js in quanto è un framework di rendering Javascript, supportato dalla suite Firebase (di Google) e dal suo nuovo database in tempo reale chiamato Firestore.

Altro dopo il salto! Continua a leggere sotto ↓

È possibile accedere direttamente a Firestore utilizzando i normali metodi HTTP, il che lo rende una soluzione completa di back-end come servizio in cui non è necessario gestire nessuno dei propri server ma archiviare comunque i dati online.

Sembra potente e scoraggiante, ma non preoccuparti, ti guiderò attraverso i passaggi per creare e ospitare questa nuova app web. Nota quanto è grande la barra di scorrimento in questa pagina; non ci sono molti passaggi per farlo. Inoltre, se vuoi sapere dove inserire ciascuno dei frammenti di codice in un repository di codice, puoi vedere una versione completamente funzionante di Amazeballs su github.

Iniziamo

Iniziamo con Vue.js. È ottimo per i principianti di Javascript, poiché inizi con l'HTML e aggiungi gradualmente la logica. Ma non sottovalutare; racchiude molte potenti funzionalità. Questa combinazione lo rende la mia prima scelta per un framework front-end.

Vue.js ha un'interfaccia a riga di comando (CLI) per progetti di scaffolding. Lo useremo per ottenere rapidamente la configurazione essenziale. Innanzitutto, installa la CLI, quindi utilizzala per creare un nuovo progetto basato sul modello "webpack-simple".

 npm install -g vue-cli vue init webpack-simple amazeballs

Se segui i passaggi sullo schermo ( npm install e npm run dev ) si aprirà un browser con un grande logo Vue.js.

Congratulazioni! È stato facile.

Successivamente, dobbiamo creare un progetto Firebase. Vai su https://console.firebase.google.com/ e crea un progetto. Un progetto inizia con il piano Spark gratuito, che ti offre un database limitato (1 GB di dati, 50.000 letture al giorno) e 1 GB di hosting. Questo è più che sufficiente per il nostro MVP e facilmente aggiornabile quando l'app guadagna terreno.

Fai clic su "Aggiungi Firebase alla tua app Web" per visualizzare la configurazione di cui hai bisogno. Useremo questa configurazione nella nostra applicazione, ma in un bel modo Vue.js usando lo stato condiviso.

Innanzitutto npm install firebase , quindi crea un file chiamato src/store.js . Questo è il punto in cui inseriremo lo stato condiviso in modo che ogni componente Vue.js possa accedervi indipendentemente dall'albero dei componenti. Di seguito il contenuto del file. Lo stato contiene solo alcuni segnaposto per ora.

 import Vue from 'vue'; import firebase from 'firebase/app'; import 'firebase/firestore'; // Initialize Firebase, copy this from the cloud console // Or use mine :) var config = { apiKey: "AIzaSyDlRxHKYbuCOW25uCEN2mnAAgnholag8tU", authDomain: "amazeballs-by-q42.firebaseapp.com", databaseURL: "https://amazeballs-by-q42.firebaseio.com", projectId: "amazeballs-by-q42", storageBucket: "amazeballs-by-q42.appspot.com", messagingSenderId: "972553621573" }; firebase.initializeApp(config); // The shared state object that any vue component can get access to. // Has some placeholders that we'll use further on! export const store = { ballsInFeed: null, currentUser: null, writeBall: (message) => console.log(message) };

Ora aggiungeremo le parti di Firebase. Un pezzo di codice per ottenere i dati dal Firestore:

 // a reference to the Balls collection const ballsCollection = firebase.firestore() .collection('balls'); // onSnapshot is executed every time the data // in the underlying firestore collection changes // It will get passed an array of references to // the documents that match your query ballsCollection .onSnapshot((ballsRef) => { const balls = []; ballsRef.forEach((doc) => { const ball = doc.data(); ball.id = doc.id; balls.push(ball); }); store.ballsInFeed = balls; });

E quindi sostituisci la funzione writeBall con una che esegue effettivamente una scrittura:

 writeBall: (message) => ballsCollection.add({ createdOn: new Date(), author: store.currentUser, message })

Nota come i due sono completamente disaccoppiati. Quando inserisci in una raccolta, onSnapshot viene attivato perché hai inserito un elemento. Questo rende la gestione dello stato molto più semplice.

Ora hai un oggetto di stato condiviso a cui qualsiasi componente Vue.js può accedere facilmente. Facciamolo buon uso.

Posta roba!

Per prima cosa, scopriamo chi è l'utente corrente.

Firebase ha API di autenticazione che ti aiutano con il grugnito del lavoro per conoscere il tuo utente. Abilita quelli appropriati sulla console Firebase in AutenticazioneMetodo di accesso. Per ora, utilizzerò Google Login, con un pulsante molto semplice.

Screenshot della pagina di accesso con autenticazione di Google
Autenticazione con Google Login

Firebase non ti fornisce alcun aiuto per l'interfaccia, quindi dovrai creare i tuoi pulsanti "Accedi con Google/Facebook/Twitter" e/o campi di immissione nome utente/password. Il tuo componente di accesso sarà probabilmente simile a questo:

 <template> <div> <button @click.prevent="signInWithGoogle">Log in with Google</button> </div> </template> <script> import firebase from 'firebase/app'; import 'firebase/auth'; export default { methods: { signInWithGoogle() { var provider = new firebase.auth.GoogleAuthProvider(); firebase.auth().signInWithPopup(provider); } } } </script>

Ora c'è un altro pezzo del puzzle di accesso e sta ottenendo la variabile currentUser nel negozio. Aggiungi queste righe al tuo store.js :

 // When a user logs in or out, save that in the store firebase.auth().onAuthStateChanged((user) => { store.currentUser = user; });

A causa di queste tre righe, ogni volta che l'utente attualmente connesso cambia (login o out), anche store.currentUser cambia. Pubblichiamo delle Palle!

Screenshot dell'opzione di disconnessione
Lo stato di accesso è memorizzato nel file store.js

Il modulo di input è un componente Vue.js separato che è collegato alla funzione writeBall nel nostro negozio, in questo modo:

 <template> <form @submit.prevent="formPost"> <textarea v-model="message" /> <input type="submit" value="DUNK!" /> </form> </template> <script> import { store } from './store'; export default { data() { return { message: null, }; }, methods: { formPost() { store.writeBall(this.message); } }, } </script>

Stupendo! Ora le persone possono accedere e iniziare a pubblicare Balls. Ma aspetta, ci manca l'autorizzazione. Vogliamo che tu possa pubblicare Balls solo tu stesso, ed è qui che entrano in gioco le regole di Firestore . Sono costituite da codice Javascript che definisce i privilegi di accesso al database. Puoi inserirli tramite la console Firestore, ma puoi anche utilizzare l'interfaccia a riga di comando di Firebase per installarli da un file su disco. Installalo ed eseguilo in questo modo:

 npm install -g firebase-tools firebase login firebase init firestore

Riceverai un file denominato firestore.rules in cui puoi aggiungere l'autorizzazione per la tua app. Vogliamo che ogni utente sia in grado di inserire le proprie palline, ma non di inserire o modificare quelle di qualcun altro. L'esempio seguente funziona bene. Consente a tutti di leggere tutti i documenti nel database, ma puoi inserirli solo se sei loggato e la risorsa inserita ha un campo "autore" che è lo stesso dell'utente attualmente connesso.

 service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read: if true; allow create: if request.auth.uid != null && request.auth.uid == request.resource.data.author; } } }

Sembrano solo poche righe di codice, ma è molto potente e può diventare complesso molto rapidamente. Firebase sta lavorando su strumenti migliori attorno a questa parte, ma per ora è una prova ed errore finché non si comporta nel modo desiderato.

Se esegui firebase deploy , le regole di Firestore verranno implementate e proteggeranno i tuoi dati di produzione in pochi secondi.

Aggiunta della logica del server

Sulla tua home page, vuoi vedere una sequenza temporale con le palle dei tuoi amici. A seconda di come si desidera determinare quali Ball vede un utente, l'esecuzione di questa query direttamente sul database potrebbe causare un collo di bottiglia delle prestazioni. Un'alternativa è creare una Firebase Cloud Function che si attivi su ogni Ball postata e la aggiunga alle bacheche di tutti gli amici dell'autore. In questo modo è asincrono, non bloccante e alla fine coerente. O in altre parole, ci arriverà.

Per semplificare gli esempi, farò una piccola demo sull'ascolto dei Balls creati e sulla modifica del loro messaggio. Non perché questo sia particolarmente utile, ma per mostrarti quanto sia facile rendere operative le funzioni cloud.

 const functions = require('firebase-functions'); exports.createBall = functions.firestore .document('balls/{ballId}') .onCreate(event => { var createdMessage = event.data.get('message'); return event.data.ref.set({ message: createdMessage + ', yo!' }, {merge: true}); });

Oh, aspetta, ho dimenticato di dirti dove scrivere questo codice.

 firebase init functions

Questo crea la directory functions con un index.js . Questo è il file in cui puoi scrivere le tue funzioni cloud . Oppure copia e incolla il mio se ne sei molto colpito.

Le funzioni cloud ti offrono un bel posto per disaccoppiare diverse parti della tua applicazione e farle comunicare in modo asincrono. Oppure, in stile disegno architettonico:

Diagramma architetturale della logica del server di Cloud Functions
Comunicazione asincrona tra i diversi componenti dell'applicazione

Ultimo passaggio: distribuzione

Firebase ha la sua opzione di hosting disponibile per questo e puoi usarla tramite l'interfaccia a riga di comando di Firebase.

 firebase init hosting

Scegli dist come directory pubblica, quindi "Sì" per riscrivere tutti gli URL in index.html . Quest'ultima opzione ti consente di utilizzare vue-router per gestire graziosi URL all'interno della tua app.

Ora c'è un piccolo ostacolo: la cartella dist non contiene un file index.html che punta alla build corretta del tuo codice. Per risolvere questo problema, aggiungi uno script npm al tuo package.json :

 { "scripts": { "deploy": "npm run build && mkdir dist/dist && mv dist/*.* dist/dist/ && cp index.html dist/ && firebase deploy" } }

Ora esegui semplicemente npm deploy e la CLI di Firebase ti mostrerà l'URL del tuo codice ospitato!

Quando usare questa architettura

Questa configurazione è perfetta per un MVP. Alla terza operazione, in pochi minuti avrai un'app Web funzionante, supportata da un database scalabile ospitato gratuitamente. Puoi iniziare immediatamente a creare funzionalità.

Inoltre, c'è molto spazio per crescere. Se Cloud Functions non è abbastanza potente, puoi ricorrere, ad esempio, a un'API tradizionale in esecuzione su Docker in Google Cloud. Inoltre, puoi aggiornare la tua architettura Vue.js con vue-router e vuex e utilizzare la potenza del webpack incluso nel modello vue-cli.

Tuttavia, non sono tutti arcobaleni e unicorni. L'avvertenza più famigerata è il fatto che i tuoi clienti stanno immediatamente parlando con il tuo database. Non esiste un livello middleware che puoi utilizzare per trasformare i dati grezzi in un formato più semplice per il client. Quindi, devi conservarlo in un modo a misura di cliente. Ogni volta che i tuoi clienti richiedono una modifica, sarà piuttosto difficile eseguire le migrazioni dei dati su Firebase. Per questo, dovrai scrivere un client Firestore personalizzato che legga ogni record, lo trasformi e lo riscriva.

Prenditi del tempo per decidere il tuo modello di dati. Se è necessario modificare il modello di dati in un secondo momento, la migrazione dei dati è l'unica opzione.

Quindi quali sono gli esempi di progetti che utilizzano questi strumenti? Tra i big che usano Vue.js ci sono Laravel, GitLab e (per gli olandesi) nu.nl. Firestore è ancora in versione beta, quindi non ci sono ancora molti utenti attivi, ma la suite Firebase è già utilizzata da National Public Radio , Shazam e altri. Ho visto colleghi implementare Firebase per il gioco basato su Unity Road Warriors che è stato scaricato oltre un milione di volte nei primi cinque giorni. Può richiedere parecchio carico ed è molto versatile con client per il Web, dispositivi mobili nativi, Unity e così via.

Dove mi iscrivo?!

Se vuoi saperne di più, considera le seguenti risorse:

  • Esempio funzionante contenente tutto il codice sopra
  • Documentazione su Vue.js, vue-router, vue-cli
  • Documentazione su Firebase
  • Un modo divertente per conoscere meglio Firebase: il loro blog su YouTube

Buona codifica!