Cloud Services Firebase JAMstack Node.js

Se passer d'un backend : NuxtJS & Firebase (Partie 2)

Comme je le disais dans la partie 1, Nuxt c'est cool et on va dans ce tutoriel mettre en place un projet Nuxt en combinaison avec Firebase pour faire du SSR via une cloud function.

Ne divergeons pas plus longtemps, et entrons dans le vif du sujet.

Pré-requis

Pour suivre ce tutoriel il vous faudra en prérequis Node JS ainsi que le gestionnaire de packages npm.

Vous trouverez le bundle des deux ici : https://nodejs.org/ . Je vous conseille la version LTS.

Personnellement j'utilise Visual Studio Code avec comme plugins tout ce qu'il faut pour faire du VueJS comme si vous étiez dans vos chaussons.

Aller on y va !

Installation du projet

# On crée notre répertoire racine
mkdir nuxt-on-firebase

cd nuxt-on-firebase

# On crée dedans le répertoire src contenant le projet Nuxt
npx create-nuxt-app src
	-- Nom du projet ? nuxt-on-firebase
	-- Description ? Ce que vous voulez
	-- Nom auteur ? Pophip
	-- Gestionnaire de package ? Npm
	-- Framework interface utilisateur ? Vuetify.js
	-- Framework server ? Aucun
	-- Nuxt.js module ? Axios et PWA
	-- Linter ? Aucun
	-- Framework de test ? Jest
	-- Mode de rendu ? Universel
	-- Outil de développement ? js.config.json (si vous êtes sur visual studio code ce que je vous recommande)

On ne veut pas que git sois initialisé directement dans src/ donc on va supprimer la traçage sous ce répertoire. On pourra relancer un git init à la racine plus tard.

cd src/ && rm -rf .git

Configuration du nuxt.config.js sous src :

Commencez tout d'abord par remplacer le export default { par module.exports = {.

Supprimez ensuite la ligne d'import des couleurs vuetify, on en aura pas besoin et cela risque de nous embêter plus qu'autre chose.

import colors from 'vuetify/es5/util/colors'

Enfin n'oubliez pas de remettre les couleurs hexadécimales en dur sous vuetify {}.

Si vous êtes un bourrin, supprimez littéralement tout ce qu'il y a sous vuetify {} et le framework vous mettra les couleurs Vuetify par défaut.

Au dessus de module.exports, on va importer un json bien connu :

const package = require('./package')
//En fait c'est le package.json sous src/

On va pouvoir mettre à jour la propriéré title sous head: {} :

title: package.name 
//C'est donc le nom du projet indiqué dans le package.json

Petit bonus pour utiliser le material design : rajouter sous link: [] :

{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' }

Et enfin ajouter la configuration du build sous module.exports:

 buildDir: '.nuxt',
  build: {
    publicPath: '/assets/',

    babel: {
      presets({ isServer }) {
        return [
          [ require.resolve('@nuxt/babel-preset-app'), 
            { 
              // targets
              buildTarget: isServer ? 'server' : 'client',
              corejs: { version: 3 }
            } 
          ]
        ]
      },
      'env': {
        'production': {
          'plugins': []
        }
      }
    }
  }

Initialisation du projet racine NPM :

cd ../ && npm init

Script de démarrage de nuxt en local :

cd src/
mkdir server
cd server && touch index.js

On a donc nuxt-on-firebase/src/server/index.js qui se présentera ainsi :

const consola = require('consola')
const express = require('express')
const { Nuxt, Builder } = require('nuxt')
const app = express()

// On importe la configuration de nuxt
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')

async function start() {
  //Initialisation de Nuxt
  const nuxt = new Nuxt(config)

  const { host, port } = nuxt.options.server

  // Build pour le mode environnement de dev
  if (config.dev) {
    const builder = new Builder(nuxt)
    await builder.build()
  } else {
    await nuxt.ready()
  }

  // On passe le middleware de nuxt à express
  app.use(nuxt.render)

  // Et on écoute le serveur
  app.listen(port, host)
  consola.ready({
    message: `Server is listening on http://${host}:${port}`,
    badge: true
  })
}

//Démarrage du serveur
start()

On retourne dans src/ :

cd ..

Installation des dépendances

Dans package.json sous src/ on va installer ces dépendances. Je vous invite à les copier coller. Nous aurions pu exécuter des npm install à n'en plus finir, j'ai choisi de vous donner toutes les dépendances directement. Normalement la commande d'installation de nuxt vous aura mis nuxt 2.0.0 par défaut en dépendance. Je vous fait cadeau de la dernière version à ce jour le 28/10/2019.

"engines": {
    "node": "10"
},
"dependencies": {
    "@nuxtjs/axios": "^5.8.0",
    "@nuxtjs/pwa": "^2.6.0",
    "@nuxtjs/vuetify": "^1.9.0",
    "express": "^4.17.1",
    "firebase-admin": "^8.7.0",
    "firebase-functions": "^3.3.0",
    "node-fetch": "^2.6.0",
    "nuxt": "^2.10.2"
  },
  "devDependencies": {
    "@babel/runtime-corejs3": "^7.7.1",
    "@vue/test-utils": "^1.0.0-beta.29",
    "babel-jest": "^24.9.0",
    "core-js": "^3.3.6",
    "cross-env": "^6.0.3",
    "jest": "^24.9.0",
    "nodemon": "^1.19.4",
    "vue-jest": "^4.0.0-0"
  }

On retourne à la racine du projet et dans package.json on écrit la dépendance cross-env.

 "dependencies": {
    "cross-env": "^6.0.3"
  }

On a donc toutes nos dépendances, il est temps de mettre en place l'environnement Firebase.

Mise en place de Firebase

Tout d'abord vous pouvez créer un nouveau projet Firebase dans la Firebase Console. Une fois le projet créé, dans les Settings vous trouverez l'ID du projet.

Notez le quelque part (du genre sur votre avant-bras ou le front de votre voisin).

Retournez sous VSCode, et installez les outils Firebase.

# Ici vous êtes sous nuxt-on-firebase/
# Outils
npm install --global firebase-tools

# Se connecter à votre compte firebase
firebase login

# Et c'est parti
firebase init hosting
	-- Proceed ? Yep go
	-- Select a project ? Pas de projet par defaut  
# (vous pouvez si vous voulez mais on fera cela après)
	-- public directory ? public
	-- Configure as singles page app ? Non

On supprime ce qui nous sert à rien pour le moment et on crée le répertoire des assets sous public/.

rm .firebaserc && rm public/* && mkdir public/assets

On va créer un fichier qui nous permettra de mettre en place automatiquement le fichier .firebaserc lors de l'installation finale.

touch .setup-firebaserc

Ouvrir .setup-firebaserc et y coller le json suivant :

{
  "projects": {
    "default": "FIREBASE_PROJECT_ID",
    "develop": "FIREBASE_PROJECT_ID",
    "staging": "FIREBASE_PROJECT_ID",
    "production": "FIREBASE_PROJECT_ID"
  }
}

Evidemment je vous laisse remplacer FIREBASE_PROJECT_ID par l'id de votre projet (il est temps de rappeler votre voisin).

Ouvrir maintenant firebase.json. On y écrira le json suivant :

{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "**",
        "function": "nuxtapp"
      }
    ]
  },
  "functions": {
    "source": "src",
    "predeploy": "npm run build && npm run pre:deploy",
    "ignore":[
      "static",
      "node_modules",
      "**/**/dist/client"
    ]
  }
}

Mise en place de la Cloud Function

On retourne dans src/ et on va mettre en place ce qu'il faut pour la cloud function:

cd src/

touch index.js

Il se présente ainsi :

const functions = require("firebase-functions");
const { Nuxt } = require("nuxt");
const express = require("express");
const app = express();


const config = {
  dev: false,
  buildDir: ".nuxt",
  build: {
    publicPath: "/assets/"
  }
};
const nuxt = new Nuxt(config);

exports.nuxtapp = functions.https.onRequest(async (req, res) => {

  if (config.dev) {
    const builder = new Builder(nuxt)
    await builder.build()
  } else {
    res.set("Cache-Control", "public, max-age=300, s-maxage=600");
    await nuxt.ready()
  }
  app.use(nuxt.render)
  return app(req, res);
});

Création des commandes :

Pour finir il ne nous reste plus qu'à entrer les différentes commandes pour le build, le lancement et le déploiement de l'application.

Dans package.json à la racine nuxt-on-firebase/ :

On va mettre en place un certain nombre de runnables :

.
.
.
"scripts": {
    "setup:client": "cd \"src\" && npm i",
    "setup:firebase": "cp .setup-firebaserc .firebaserc",
    "setup": "npm i && npm run setup:firebase && npm run setup:client",
    "dev": "cd ./src && npm run dev",
    "build": "cd ./src && npm run build",
    "copyassets": "cp -R ./src/.nuxt/dist/client/* ./public/assets",
    "copystatic": "cp -R ./src/static/* ./public",
    "pre:deploy": "npm run copyassets && npm run copystatic",
    "firebase:serve": "npm run build && npm run serve",
    "serve": "cross-env DEBUG=nuxt:*  firebase serve --only hosting,functions",
    "deploy": "firebase deploy && rm -rf .firebase"
  },
.
.
.

Respectivement :

  • Installer l'environnement applicatif
  • Installer l'environnement firebase
  • Installer l'environnement complet (applicatif et firebase)
  • Lancer l'application en local depuis la racine
  • Build l'application depuis la racine
  • Copier les assets depuis le répertoire de build vers public
  • Copier les fichiers statiques vers public
  • Build l'application et lancer firebase en local
  • Uniquement lancer firebase en local
  • Déployer l'application sous firebase

Et dans package.json sous nuxt-on-firebase/src/ :

.
.
.
"scripts": {
    "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
    "build": "nuxt build",
    "start": "cross-env NODE_ENV=production node server/index.js",
    "test": "jest"
  },
.
.
.
  • Démarrer en local en environnement de developpement
  • Builder l'application
  • Démarrer en local en environnement de production
  • Eventuellement lancer les tests sous jest

Let's build !

Maintenant on va pouvoir lancer l'installation complète !

# Ici vous devez être à la racine du projet
npm run setup

Suite à quoi on va lier le projet à Firebase :

firebase use default
# ou tout profil souhaité inscrit dans le fichier .setup-firebaserc précédemment édité

Let's run !

Tout est installé correctement ? Testons de lancer Nuxt en local.

npm run dev

Punchez moi ce lien : http://localhost:3000 et vous devriez trouver votre super application.

Et maintenant firebase (en local encore un peu de patience)

npm run firebase:serve

Cliquez sur celui-ci http://localhost:5000 pour la même chose mais cette fois c'est firebase et votre cloud function qui tournent en local !

Let's deploy !

npm run deploy

Normalement vous devriez avoir une superbe application NuxtJS serverless en SSR tournant sous Firebase avec la Firebase Cloud Function.

Mes félicitations !

Ceci-dit, il est minuit quarante, demain il y a boulot. Merci d'avoir lu, j'espère que le tutoriel vous a plu et je vous donne rendez-vous pour une prochaine publication !

Bien à vous,

Pophip

Author image

A propos de Rémi Pereira

Je suis issu d'une formation ingénieur informatique à l'UTBM. Je suis actuellement ingénieur développeur Web m'orientant progressivement vers le DevOps.
  • Strasbourg - France