Nuxt 3 en SSR mais sans serveur ?!
Le 9/26/2022

Bonjour !

Aujourd’hui un petit article pour vous montrer comment avec Nuxt3 faire du rendu coté serveur sans serveur 🤯
Je pars du principe que vous êtes habitué à NodeJs et qu’il est installé.

PS: N’hésitez pas à donner votre avis sur le discord, si vous voyez une coquille n’hésitez pas à la remonter 😋

# Qu’est ce que Nuxt

Attention
Nuxt3 est en release candidate à l'heure où j'écris cet article.
Info
Après beaucoups de bugs corrigés et de mauvaises 1ères impressions dissipées je fais cet article.
Il y a encore pas si longtemps je voyais Nuxt3 d'un mauvais oeil pour plein de raison technique, mais maintenant Nuxt3 est en bonne phase 😁

Nuxt est décrit comme “le framework vue hybride” sur la page principale
Pour faire une analogie il est à VueJs ce que Next est à react ou encore SvelteKit à Selvte.

Si vous faites du vue3 mais que vous ne connaissez pas nuxt je vous conseille d’y jeter un oeil 😉

En gros les points forts de Nuxt:

  • plusieurs modes de rendu
    • server side rendering
    • static site generation
    • single page app
    • mode hybride (pas encore dispo en RC11)
  • auto import (composable, components, layouts)
  • Configuration automatique de vue-router via l’arborescence des dossiers pages et layouts
  • système de plugins & modules

# Installation de Nuxt (et de quelques autres trucs)

# installation de Nuxt

Info
J'utilise pnpm plutôt que npm ou yarn, mais ça marche quasiment pareil.
si jamais voici le lien de la doc de nuxt.
pnpm dlx nuxi init mon-super-project

Et on crée un fichier .npmrc où l’on va mettre shamefully-hoist=true (plus d’info au pourquoi du comment ici)

# Quelques autres trucs

On installe un linter, avec la config d’Antfu parce que j’aime bien cette configuation, en gros un linter c’est un outil qui te gueule dessus si y’a une virgule en trop ou en moins ou bien si y’a un console.log (pas exemple).

exemple linter

par exemple avec l’extension eslint sur vscode

pnpm -D i @antfu/eslint-config eslint typescript

Le package.json doit ressembler à un truc comme ça:

{
  "private": true,
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "devDependencies": {
    "@antfu/eslint-config": "^0.27.0",
    "eslint": "^8.23.1",
    "nuxt": "3.0.0-rc.11",
    "typescript": "^4.8.3"
  }
}
package.json

Et puis bah c’est bien beau d’installer des packages mais faut il encore les utiliser 😋

On crée un fichier .eslintrc à la racine du projet:

{
  "extends": "@antfu"
}
.eslintrc

# Un peu de code

# vue-router et app.vue

Pour activer vue-router dans Nuxt3 il suffit de créer un dossier pages, on va créer un fichier index.vue dedans:

<script setup>
const { data } = await useAsyncData(() => new Date().toLocaleString())
</script>

<template>
  <div>
    bienvenue sur l'index, on est le {{ data }}
  </div>
</template>
pages/index.vue

Rien de bien compliqué, on demande au serveur une date, plus qu’à dire à Nuxt d’utiliser les pages: il suffit de modifier app.vue.

<template>
  <div>
    <NuxtPage />
  </div>
</template>
app.vue

Si maintenant je vais sur http://localhost:3000/ j’ai bien bienvenue sur l'index, on est le 24/09/2022, 14:16:00
Si par contre à la place je vais sur http://localhost:3000/page/qui/n/existe/pas j’ai bien une page d’erreur 404

# NitroJs, le moteur qui fait vroum vroum

NitroJs est le moteur utilisé par Nuxt (et développé pour à la base), il permet de deployer votre code pour divers acteurs du cloud (Google, Amazon, Heroku, Netlify, etc…) je vais utiliser le deployment sur firebase qui est un produit Google, mais vous pouvez utiliser un autre acteur du cloud.

# Ajout des dépendances

Toujours avec pnpm chez moi

pnpm install -D firebase-admin firebase-functions firebase-functions-test

et firebase-tools en global avec npm cette fois car c’est un binaire qu’on installe globallement :

npm install -g firebase-tools

# Création d’un compte sur firebase et d’un projet

Bon je vous avous j’ai un peu la flemme de recréer un compte pour vous montrer comment ça marche mais c’est super simple, faut juste une carte bancaire (Google offre 300$ de crédit pour les 3 mois suivant, de quoi tester Google Cloud Platform)

Une fois le projet créé (je vous assure y’en a pour 3 minutes chrono en main) il faut changer le type de facturation en Blaze pour pouvoir utiliser les clouds functions, c’est une formule où vous payez que ce que vous consommez.

console firebase

Les (tarifs) sont vraiment simples à comprendre et très accessible même à une large échelle, ça vous coutera bien moins cher qu’un VPS à titre d’exemple.

# firebase.json

Il n’y a plus qu’à créer un fichier firebase.json à la racine du projet :

{
  "functions": {
    "source": ".output/server"
  },
  "hosting": [
    {
      "site": "<votre_id_de_projet>",
      "public": ".output/public",
      "cleanUrls": true,
      "rewrites": [
        {
          "source": "**",
          "function": "server"
        }
      ]
    }
  ]
}
firebase.json

En remplacant la clef hosting.site par votre id de projet (pour moi test-nuxt3-faas) :

console firebase

# Login sur firebase

Pour se connecter il suffit de lancer firebase login, cela va vous ouvrir un nouvel onglet dans votre navigateur avec une page de connexion google classique.

# Deployment

il n’y a plus que deux commandes à faire:

  • pnpm run build pour générer le dossier .output
  • firebase deploy --project <votre_id_de_projet> pour deployer chez Google
Info
Si vous avez une erreur inconnue il faut aller dans le dossier .output/server et relancer un npm i.
Plus d'info ici.

Maintenant si je vais sur https://test-nuxt3-faas.web.app/ j’ai bien bienvenue sur l'index, on est le 9/25/2022, 10:31:03 AM, alors oui, je sais … Le formatage est en Anglais, c’est normal la fonction à été deployée dans la région us-central1 du coup on a une locale en_US et si on va sur https://test-nuxt3-faas.web.app/blablabla on a bien la page 404 😉.

screen erreur 404

# Bonus: avoir la bonne locale

On va utiliser le package negociator pour deviner la locale à utiliser

pnpm i negociator
pnpm i -D @types/negociator

Et on l’utilise

<script setup>
import Negotiator from 'negotiator'

const { data } = await useAsyncData(({ ssrContext }) => {
  if (process.server) {
    const negotiator = new Negotiator(ssrContext.event.req)
    const locale = negotiator.language(['fr-FR', 'en-US'])
    return new Date().toLocaleString(locale)
  }
  return new Date().toLocaleString()
})
</script>

<template>
  <div>
    bienvenue sur l'index, on est le {{ data }}
  </div>
</template>
pages/index.vue

Si je met le navigateur en Anglais j’ai bienvenue sur l'index, on est le 9/25/2022, 11:09:25 AM et en Français j’ai bienvenue sur l'index, on est le 25/09/2022 11:12:54 and voilà !