Exemple [nuxt-03] : nuxtServerInit¶
Le projet [nuxt-03] vise à présenter une fonction du store [Vuex] appelée [nuxtServerInit]. Elle permet au serveur d’initialiser le store [Vuex] comme le fait la fonction [fetch]. Mais contrairement à la fonction [fetch], la fonction [nuxtServerInit] n’est jamais exécutée par le client.
Le projet [nuxt-03] est initialement obtenu par recopie du projet [nuxt-01] duquel on supprime la page [page2] du dossier [pages] et du composant [navigation]. Le dossier [store] est obtenu par recopie du dossier [nuxt-02/store].
Le store [Vuex]¶
Le store [Vuex] sera implémenté par le fichier [store/index.js] suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /* eslint-disable no-console */
export const state = () => ({
// compteur
counter: 0
})
export const mutations = {
// incrémentation du compteur d'une valeur [inc]
increment(state, inc) {
state.counter += inc
}
}
export const actions = {
async nuxtServerInit(store, context) {
// qui exécute ce code ?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server)
// on attend la fin d'une promesse
await new Promise(function(resolve, reject) {
// on a normalement ici une fonction asynchrone
// on la simule avec une attente d'une seconde
setTimeout(() => {
// succès
resolve()
}, 1000)
})
// on modifie le store
store.commit('increment', 34)
// log
console.log('nuxtServerInit commit terminé')
}
}
|
lignes 1-12 : sont analogues à ce qu’elles étaient dans le projet [nuxt-02] ;
lignes 14-32 : on exporte un objet [actions]. C’est un terme réservé du store de [Vuex] ;
ligne 15 : on définit la fonction [nuxtServerInit]. Celle-ci sera exécutée au démarrage de l’application par le serveur. Son rôle usuel est d’initialiser un store [Vuex] à l’aide de données externes obtenues avec une fonction asynchrone. [nuxt] attend que celle-ci rende ses résultats avant d’entamer le cycle de vie de la page demandée. La fonction reçoit deux paramètres :
- le store [Vuex] à initialiser ;
- le contexte [nuxt] du moment ;
lignes 19-26 : on attend la fin de l’action asynchrone, ici une attente artificielle d’une seconde (ligne 15) ;
ligne 28 : on donne au compteur la valeur 34 ;
lignes 17 et 30 : des logs pour suivre le déroulement de l’exécution de la fonction [nuxtServerInit] ;
La page [index]
La page [index] sera la suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | <!-- page [index] -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<b-alert slot="right" show variant="warning"> Home - value= {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Layout from '@/components/layout'
import Navigation from '@/components/navigation'
export default {
name: 'Home',
// composants utilisés
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// cycle de vie
beforeCreate() {
// client et serveur
console.log('[home beforeCreate]')
},
created() {
// client et serveur
this.value = this.$store.state.counter
console.log('[home created], value=', this.value)
},
beforeMount() {
// client seulement
console.log('[home beforeMount]')
},
mounted() {
// client seulement
console.log('[home mounted]')
}
}
</script>
|
ligne 37 : la valeur du compteur initialisé par la fonction [nuxtServerInit] est affectée à la propriété [value] de la ligne 27. Cette valeur est affichée par la ligne 7 ;
la ligne 37 sera exécutée aussi bien par le serveur que par le client. Dans les deux cas, la propriété [value] recevra la même valeur ce qui assure l’identité de la page générée par le serveur avec celle générée par le client ;
La page [page1]
La page [page1] est obtenue par recopie de la page [index]. On modifie ensuite son texte pour remplacer [home] par [page1] :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <!-- page [page1]] -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<b-alert slot="right" show variant="warning"> Page1 - value= {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Layout from '@/components/layout'
import Navigation from '@/components/navigation'
export default {
name: 'Page1',
// composants utilisés
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// cycle de vie
beforeCreate() {
// client et serveur
console.log('[page1 beforeCreate]')
},
created() {
// client et serveur
this.value = this.$store.state.counter
console.log('[page1 created], value=', this.value)
},
beforeMount() {
// client seulement
console.log('[page1 beforeMount]')
},
mounted() {
// client seulement
console.log('[page1 mounted]')
}
}
</script>
|
Cette page n’est là que pour rendre possible la navigation entre deux pages.
Exécution¶
Le fichier [nuxt.config.js] est modifié de la façon suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // répertoire du code source
srcDir: 'nuxt-03',
// routeur
router: {
// racine des URL de l'application
base: '/nuxt-03/'
},
// serveur
server: {
// port de service, 3000 par défaut
port: 81,
// adresses réseau écoutées, par défaut localhost : 127.0.0.1
// 0.0.0.0 = toutes les adresses réseau de la machine
host: 'localhost'
}
|
La page affichée à l’exécution est alors la suivante :
- en [5], on voit que la fonction [nuxtServerInit] a été exécutée par le serveur avant le cycle de vie de la page [index]. [nuxt] a attendu que la fonction asynchrone ait terminé son travail avant de passer au cycle de vie ;
- en [4], on voit que le client n’a pas exécuté la fonction [nuxtServerInit] ;
Maintenant naviguons deux fois : index –> page1 –> index. Les logs sont alors les suivants :
- en [1-2], on voit que la fonction [nuxtServerInit] n’est pas exécutée par le client ;
Maintenant tapons l’URL de la page [page1] à la main pour forcer un appel au serveur :
en [3-4], on retrouve le même mécanisme que celui qui avait précédé le chargement de la page [index] au démarrage. On rappelle ici ce qui a déjà été dit : lorsqu’on force l’appel d’une page au serveur, tout se passe comme si l’application redémarrait avec une page d’accueil qui serait la page demandée ;