6. Przykład [nuxt-03]: nuxtServerInit
Projekt [nuxt-03] ma na celu przedstawienie funkcji magazynu [Vuex] o nazwie [nuxtServerInit]. Pozwala ona serwerowi zainicjować magazyn [Vuex], tak jak robi to funkcja [fetch]. Jednak w przeciwieństwie do funkcji [fetch], funkcja [nuxtServerInit] nigdy nie jest wykonywana przez klienta.

Projekt [nuxt-03] powstaje początkowo poprzez skopiowanie projektu [nuxt-01], z którego usuwa się stronę [page2] z folderu [pages] oraz z komponentu [navigation]. Folder [store] powstaje poprzez skopiowanie folderu [nuxt-02/store].
6.1. Szablon [Vuex]
Plik [Vuex] zostanie zaimplementowany przez następujący plik [store/index.js]:
/* eslint-disable no-console */
export const state = () => ({
// licznik
counter: 0
})
export const mutations = {
// zwiększenie licznika o jedną wartość [inc]
increment(state, inc) {
state.counter += inc
}
}
export const actions = {
async nuxtServerInit(store, context) {
// kto wykonuje ten kod?
console.log('nuxtServerInit, client=', process.client, 'serveur=', process.server)
// czekamy na zakończenie obietnicy
await new Promise(function(resolve, reject) {
// zwykle mamy tu do czynienia z funkcją asynchroniczną
// symulujemy ją, czekając jedną sekundę
setTimeout(() => {
// powodzenie
resolve()
}, 1000)
})
// modyfikujemy zmienną
store.commit('increment', 34)
// log
console.log('nuxtServerInit commit terminé')
}
}
- wiersze 1–12: są analogiczne do tych z projektu [nuxt-02];
- wiersze 14–32: eksportowany jest obiekt [actions]. Jest to termin zarezerwowany dla magazynu [Vuex];
- wiersz 15: definiuje się funkcję [nuxtServerInit]. Zostanie ona wykonana przez serwer podczas uruchamiania aplikacji. Jej typową rolą jest zainicjowanie magazynu [Vuex] przy użyciu danych zewnętrznych uzyskanych za pomocą funkcji asynchronicznej. [nuxt] czeka, aż funkcja ta zwróci wyniki, zanim rozpocznie cykl życia żądanej strony. Funkcja otrzymuje dwa parametry:
- magazyn [Vuex] do zainicjowania;
- bieżący kontekst [nuxt];
- wiersze 19–26: oczekuje się na zakończenie akcji asynchronicznej, w tym przypadku sztucznego oczekiwania trwającego jedną sekundę (wiersz 15);
- wiersz 28: nadajemy licznikowi wartość 34;
- wiersze 17 i 30: logi służące do śledzenia przebiegu wykonywania funkcji [nuxtServerInit];
6.2. Strona [index]
Strona [index] będzie wyglądać następująco:
<!-- strona [index] -->
<template>
<Layout :left="true" :right="true">
<!-- nawigacja -->
<Navigation slot="left" />
<!-- komunikat-->
<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',
// używane komponenty
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// cykl życia
beforeCreate() {
// klient i serwer
console.log('[home beforeCreate]')
},
created() {
// klient i serwer
this.value = this.$store.state.counter
console.log('[home created], value=', this.value)
},
beforeMount() {
// tylko klient
console.log('[home beforeMount]')
},
mounted() {
// tylko klient
console.log('[home mounted]')
}
}
</script>
- wiersz 37: wartość licznika zainicjowanego przez funkcję [nuxtServerInit] jest przypisywana do właściwości [value] z wiersza 27. Wartość ta jest wyświetlana w wierszu 7;
- wiersz 37 zostanie wykonany zarówno przez serwer, jak i przez klienta. W obu przypadkach właściwość [value] otrzyma tę samą wartość, co zapewnia zgodność strony wygenerowanej przez serwer ze stroną wygenerowaną przez klienta;
6.3. Strona [page1]
Strona [page1] powstaje poprzez skopiowanie strony [index]. Następnie modyfikuje się jej tekst, zastępując [home] na [page1]:
<!-- strona [page1]] -->
<template>
<Layout :left="true" :right="true">
<!-- nawigacja -->
<Navigation slot="left" />
<!-- komunikat-->
<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',
// używane komponenty
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// cykl życia
beforeCreate() {
// klient i serwer
console.log('[page1 beforeCreate]')
},
created() {
// klient i serwer
this.value = this.$store.state.counter
console.log('[page1 created], value=', this.value)
},
beforeMount() {
// tylko klient
console.log('[page1 beforeMount]')
},
mounted() {
// tylko klient
console.log('[page1 mounted]')
}
}
</script>
Ta strona służy wyłącznie do umożliwienia nawigacji między dwiema stronami.
6.4. Exécution
Plik [nuxt.config.js] zostaje zmodyfikowany w następujący sposób:
// katalog kodu źródłowego
srcDir: 'nuxt-03',
// router
router: {
// katalog główny aplikacji URL
base: '/nuxt-03/'
},
// serwer
server: {
// port usługi, domyślnie 3000
port: 81,
// adresy sieciowe, na których nasłuchuje, domyślnie localhost: 127.0.0.1
// 0.0.0.0 = wszystkie adresy sieciowe komputera
host: 'localhost'
}
Strona wyświetlana podczas działania wygląda wówczas następująco:

- W pliku [5] widać, że funkcja [nuxtServerInit] została wykonana przez serwer przed cyklem życia strony [index]. [nuxt] poczekała, aż funkcja asynchroniczna zakończy swoją pracę, zanim przeszła do cyklu życia;
- w [4] widać, że klient nie wykonał funkcji [nuxtServerInit];
Teraz przejdźmy dwukrotnie: index --> strona1 --> index. Logi wyglądają wówczas następująco:

- w [1-2] widać, że funkcja [nuxtServerInit] nie została wykonana przez klienta;
Teraz ręcznie wpiszmy URL ze strony [page1], aby wymusić wywołanie serwera:

w [3-4] obserwujemy ten sam mechanizm, co ten, który poprzedzał załadowanie strony [index] podczas uruchamiania. Przypomnijmy tutaj to, co już zostało powiedziane: gdy wymuszamy wywołanie strony na serwerze, wszystko przebiega tak, jakby aplikacja uruchamiała się ponownie ze stroną startową, którą jest żądana strona;