Skip to content

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.

Image

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:

Image

  • 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:

Image

  • 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:

Image

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;