6. Exemplo [nuxt-03]: nuxtServerInit
O projeto [nuxt-03] tem como objetivo demonstrar uma função de armazenamento [Vuex] chamada [nuxtServerInit]. Permite que o servidor inicialize o armazenamento [Vuex], tal como a função [fetch] faz. Mas, ao contrário da função [fetch], a função [nuxtServerInit] nunca é executada pelo cliente.

O projeto [nuxt-03] é inicialmente criado através da clonagem do projeto [nuxt-01], do qual são removidas a página [page2] na pasta [pages] e o componente [navigation]. A pasta [store] é criada através da clonagem da pasta [nuxt-02/store].
6.1. O armazenamento [Vuex]
O armazenamento [Vuex] será implementado pelo seguinte ficheiro [store/index.js]:
/* eslint-disable no-console */
export const state = () => ({
// meter
counter: 0
})
export const mutations = {
// increment counter by one [inc] value
increment(state, inc) {
state.counter += inc
}
}
export const actions = {
async nuxtServerInit(store, context) {
// who executes this code?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server)
// waiting for a promise to be fulfilled
await new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// success
resolve()
}, 1000)
})
// modify the blind
store.commit('increment', 34)
// log
console.log('nuxtServerInit commit terminé')
}
}
- linhas 1–12: são semelhantes às do projeto [nuxt-02];
- linhas 14–32: exportamos um objeto [actions]. Este é um termo reservado no armazenamento [Vuex];
- linha 15: definimos a função [nuxtServerInit]. Esta será executada pelo servidor quando a aplicação for iniciada. A sua função habitual é inicializar um armazenamento [Vuex] utilizando dados externos obtidos através de uma função assíncrona. O [nuxt] aguarda que esta função retorne os seus resultados antes de iniciar o ciclo de vida da página solicitada. A função recebe dois parâmetros:
- o armazenamento [Vuex] a ser inicializado;
- o contexto [Nuxt] atual;
- linhas 19–26: aguardamos a conclusão da ação assíncrona, neste caso uma espera artificial de um segundo (linha 15);
- linha 28: o contador é definido para 34;
- linhas 17 e 30: registos para acompanhar a execução da função [nuxtServerInit];
6.2. A página [index]
A página [index] será a seguinte:
<!-- 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',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[home created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
}
}
</script>
- Linha 37: O valor do contador inicializado pela função [nuxtServerInit] é atribuído à propriedade [value] na linha 27. Este valor é exibido pela linha 7;
- a linha 37 será executada tanto pelo servidor como pelo cliente. Em ambos os casos, a propriedade [value] receberá o mesmo valor, garantindo que a página gerada pelo servidor corresponde à gerada pelo cliente;
6.3. A página [page1]
A página [page1] é obtida através da cópia da página [index]. Em seguida, modificamos o seu texto para substituir [home] por [page1]:
<!-- 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',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page1 beforeCreate]')
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page1 created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[page1 beforeMount]')
},
mounted() {
// customer only
console.log('[page1 mounted]')
}
}
</script>
Esta página existe apenas para permitir a navegação entre duas páginas.
6.4. Execução
O ficheiro [nuxt.config.js] é modificado da seguinte forma:
// source code directory
srcDir: 'nuxt-03',
// router
router: {
// application URL root
base: '/nuxt-03/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: 'localhost'
}
A página exibida após a execução é então a seguinte:

- em [5], vemos que a função [nuxtServerInit] foi executada pelo servidor antes do ciclo de vida da página [index]. O [nuxt] aguardou que a função assíncrona concluísse o seu trabalho antes de prosseguir para o ciclo de vida;
- em [4], vemos que o cliente não executou a função [nuxtServerInit];
Agora, vamos navegar duas vezes: index --> page1 --> index. Os registos ficam então assim:

- Em [1-2], vemos que a função [nuxtServerInit] não é executada pelo cliente;
Agora vamos digitar manualmente a URL da página [página1] para forçar uma chamada ao servidor:

Em [3-4], vemos o mesmo mecanismo que precedeu o carregamento da página [index] no arranque. Vamos recapitular o que foi mencionado anteriormente: quando forçamos uma página a chamar o servidor, é como se a aplicação estivesse a reiniciar com uma página inicial que é a página solicitada;