Skip to content

5. Exemplo [nuxt-02]: páginas do servidor e do cliente

Neste projeto, mostramos:

  • que a página construída pelo cliente pode ser visualmente diferente daquela recebida do servidor. Temos, então, uma mudança rápida de página, perceptível pelo usuário, o que prejudica a usabilidade do aplicativo. Portanto, essa é uma opção a ser evitada;
  • uma solução para que a página do cliente recrie a mesma página enviada pelo servidor;

O projeto [nuxt-02] é obtido inicialmente por meio da cópia do projeto [nuxt-01].

Image

Uma pasta [store] é adicionada ao projeto, juntamente com duas novas páginas. Voltaremos a esse assunto.

5.1. A página [index]

5.1.1. O código da página

O código da página [index] passa a ser o seguinte:


<!-- página principal -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem-->
    <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 Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Home',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[home created]')
    // somente servidor
    if (process.server) {
      this.value = 10
    }
    // cliente e servidor
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[home beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[home mounted]')
  }
}
</script>

Comentários

  • linha 7: a página [index] exibirá o valor de sua propriedade [value] (linha 28);
  • linhas 36-45: é importante lembrar aqui que a função [created] é executada tanto no lado do servidor quanto no lado do cliente. Nas linhas 40-42, o servidor definirá o valor da propriedade [value] como 10. O cliente, por sua vez, não altera esse valor. Queremos simplesmente saber se esse valor é mantido pelo cliente. Vamos descobrir que não;

5.1.2. Execução

Alteramos o arquivo [/nuxt.config.js] para executar o projeto [nuxt-02]:


...
  // diretório do código-fonte
  srcDir: 'nuxt-02',
  // roteador
  router: {
    // raiz dos URL do aplicativo
    base: '/nuxt-02/'
  },
  // servidor
  server: {
    // porta de serviço, 3000 por padrão
    port: 81,
    // endereços de rede monitorados, por padrão localhost: 127.0.0.1
    // 0.0.0.0 = todos os endereços de rede da máquina
    host: 'localhost'
  }
...

Executamos o projeto [1]:

Image

A página [index] é então exibida como [2-3]. Ela exibe o valor [10] por alguns instantes e, em seguida, exibe o valor [0]. O que aconteceu?

Etapa 1

O servidor é executado primeiro. Ele executa o código da página [index]:


export default {
  name: 'Home',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[home created]')
    // somente servidor
    if (process.server) {
      this.value = 10
    }
    // cliente e servidor
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[home beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[home mounted]')
  }
}
  • devido à linha 23, a propriedade [value] da linha 10 assume o valor 10;

É possível verificar isso observando o código-fonte da página recebida pelo navegador (opção [code source] no navegador):


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-02/">
  <link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
  ....
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
              <h4>[nuxt-02] : page serveur, page client</h4>
            </div> <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-02/" target="_self" class="nav-link active nuxt-link-active">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page2" target="_self" class="nav-link">
                        Page 2
                      </a>
                    </li>
                  </ul>
                </div> <div class="col-10">
                  <div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-warning">
                    Home - value= 10
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = ....;</script>
  <script src="/nuxt-02/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
  • linha 46: na página recebida, [value] tinha o valor 10;

etapa 2

Sabemos que, após o recebimento da página, os scripts das linhas 57 a 60 assumem o controle e alteram o comportamento da página recebida, inclusive as informações exibidas, como neste caso. Esses scripts formam o cliente, que também executa o código da página [index], o mesmo código do servidor:


export default {
  name: 'Home',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[home created]')
    // somente servidor
    if (process.server) {
      this.value = 10
    }
    // cliente e servidor
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[home beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[home mounted]')
  }
}
  • para entender o que está acontecendo, é preciso compreender que o cliente [nuxt] não executará as linhas 22 a 24 (process.server=false);
  • em uma aplicação [vue] clássica, a propriedade [value] da linha 10 permanece em 0. É por isso que, assim que o cliente acessa a página recebida, o valor exibido passa a ser [0];

O valor gerado pelo servidor [nuxt] para a propriedade [value] não serviu para nada.

5.2. A página [page1]

5.2.1. A loja [Vuex]

Adicionamos uma pasta [store] ao projeto [nuxt-02]:

Image

A presença desse arquivo faz com que, automaticamente, o [nuxt] implemente um store [Vuex]. É o arquivo [index.js] que implementa esse store. Aqui, o arquivo [index.js] é o seguinte:


export const state = () => ({
  counter: 0
})

export const mutations = {
  increment(state, inc) {
    state.counter += inc
  }
}

[nuxt] implementa um store [Vuex] a partir do conteúdo de [index.js]:

  • linhas 1-3: definição do estado [state] do store. Esse estado é retornado por uma função. Aqui, o estado possui apenas uma propriedade, o contador da linha 2. A função exportada deve se chamar [state];
  • linhas 5-9: as operações possíveis no estado do store. Elas são chamadas de [mutations]. Aqui, a modificação [increment] permite incrementar a propriedade [counter] em uma quantidade [inc]. O objeto exportado deve se chamar [mutations];

O [store] Vuex implementado por [nuxt] está disponível em diferentes locais. Nas visualizações, ele está disponível na propriedade [this.$store].

5.2.2. O código da página

Assim como a página [index], a página [page1] exibirá um valor, o do contador do store Vuex:


<!-- página 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem-->
    <b-alert slot="right" show variant="primary"> Page 1 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page1',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[home created]')
    // somente servidor
    if (process.server) {
      this.$store.commit('increment', 25)
    }
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[home beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[home mounted]')
  }
}
</script>

Comentários

  • linhas 38-40: o servidor incrementará o contador em 25;
  • linha 42: tanto o servidor quanto o cliente exibirão o valor do contador;
  • linha 7: o valor do contador é exibido;

Ao ler este código, é preciso entender duas coisas:

  • o código executado é o mesmo tanto para o servidor quanto para o cliente;
  • o objeto [this], por sua vez, não é o mesmo: há uma versão [this] no lado do servidor e outra no lado do cliente, [client];

Queremos saber se o [this.$store] do servidor é o mesmo que o [this.$store] do cliente. Como é o servidor que é executado primeiro (ao iniciar o aplicativo), isso equivale a perguntar: o [store] inicializado pelo servidor é transmitido ao cliente?

5.2.3. Execução

Executamos o projeto [nuxt-02] e digitamos [localhost:81/nuxt-02/page1] manualmente para que o servidor seja acionado. Assim como na inicialização da página [index]:

  • o servidor executa a página [page1.vue];
  • envia a página gerada ao navegador. Ela é exibida;
  • os scripts do cliente incorporados na página enviada assumem o controle e executam novamente a página [page1.vue];
  • a página exibida é então modificada;

O resultado final é o seguinte:

Image

Desta vez, o valor exibido é, de fato, aquele definido pelo servidor e, visualmente, não se observa a página “pular” devido a uma alteração feita pelo cliente no valor exibido pelo servidor. O que aconteceu desta vez?

O servidor executou a página [page1] a seguir:


...

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page1',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page1 beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[page1 created]')
    // somente servidor
    if (process.server) {
      this.$store.commit('increment', 25)
    }
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page1 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page1 mounted]')
  }
}
</script>
  • as linhas 30 a 32 foram executadas sem erros. Isso significa que, também no lado do servidor, [this.$store] se refere ao store [Vuex]. A linha 31 aumentou o contador do store para 25;
  • feito isso, a página foi enviada ao cliente;

Se observarmos a página recebida pelo cliente, encontramos os seguintes elementos:


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-02/">
  <link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
  ...
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
              <h4>[nuxt-02] : page serveur, page client</h4>
            </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-02/" target="_self" class="nav-link">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page1" target="_self" class="nav-link active nuxt-link-active">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page2" target="_self" class="nav-link">
                        Page 2
                      </a>
                    </li>
                  </ul>
                </div> <div class="col-10">
                  <div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-primary">
                    Page 1 - value = 25
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>
  window.__NUXT__ = (function (a, b, c) {
      return {
        layout: "default", data: [{}], error: null, state: { counter: 25 }, serverRendered: true,
        logs: [
          { date: new Date(1574085336802), args: ["[home beforeCreate]"], type: a, level: b, tag: c },
          { date: new Date(1574085336839), args: ["[home created]"], type: a, level: b, tag: c },
          { date: new Date(1574085336869), args: ["value=", "25"], type: a, level: b, tag: c }
        ]
      }
    }("log", 2, ""));</script>
  <script src="/nuxt-02/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
  • linha 47: o valor enviado pelo servidor;
  • linha 60: verifica-se que o estado do store [Vuex] foi incorporado à página. Isso permitirá que o cliente, ao ser executado após o recebimento da página, reconstitua um novo store [Vuex] com 25 como valor inicial do contador;

Após o recebimento e a exibição da página recebida do servidor, o cliente assume o controle e, por sua vez, executa a página [page1]:


...

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page1',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page1 beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[page1 created]')
    // somente servidor
    if (process.server) {
      this.$store.commit('increment', 25)
    }
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page1 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page1 mounted]')
  }
}
</script>
  • linha 34: a propriedade [value] da linha 18 recebe, por sua vez, o valor 25 do contador;

O store de [nuxt] permite, portanto, que o servidor transmita informações ao cliente durante o carregamento inicial da página, quando esta é solicitada ao servidor. Vale lembrar que, uma vez obtida essa página, o servidor não é mais consultado e o aplicativo funciona como um aplicativo [vue] clássico, no modo SAP.

5.3. A página [page2]

Na página [page2], mostramos outra maneira de fazer com que:

  • o servidor inclua informações calculadas na página;
  • o cliente não altere essas informações;

5.3.1. O código da página

O código da página [page2] é alterado da seguinte forma:


<!-- página 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page2',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  asyncData(context) {
    // quem executa esse código?
    console.log('asyncData, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retornamos uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // esse resultado será incluído nas propriedades de [data]
          resolve({ value: 87 })
          // log
          console.log('asynData terminée')
        }, 1000)
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page2 beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[page2 created]')
  },
  beforeMount() {
    // somente cliente
    console.log('[page2 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page2 mounted]')
  }
}
</script>
  • linha 7: a página exibe o valor de uma propriedade chamada [value];
  • a propriedade [value] não existe como elemento de um objeto retornado pela função [data]. Aqui, essa função não existe. A propriedade [value] é criada dinamicamente pela linha 36;
  • linha 25: a função [asyncData] é uma função [nuxt]. Como o próprio nome indica, trata-se normalmente de uma função assíncrona. Sua função habitual é buscar dados externos. A função [nuxt] garante que a página não seja enviada ao navegador do cliente antes que a função [asyncData] tenha retornado seus dados assíncronos;
  • a função [asyncData] recebe como parâmetro o contexto [nuxt]. Esse objeto é muito rico e dá acesso a muitas informações sobre a aplicação [nuxt]. Vamos descobrir isso nas seções a seguir;
  • linha 31: implementamos a função [asyncData] com um [Promise] (consulte o documento |Introdução à linguagem ECMASCRIPT 6 por meio de exemplos|). O construtor dessa classe aceita como parâmetro uma função assíncrona que:
    • indica sucesso retornando dados com a função [resolve]. O objeto retornado por essa função é automaticamente incluído nas propriedades [data] da página;
    • indica uma falha retornando um erro com a função [reject];
  • linha 34: simula-se uma função assíncrona com a função [setTimeout]. Essa função retorna o objeto [{ value: 87 }] (linha 36) após um segundo (linha 31) por meio da função [resolve], que sinaliza o sucesso da função [Promise]. O objeto retornado pela função assíncrona é incluído automaticamente nas propriedades [data] da página. E é, portanto, essa propriedade que a linha 7 exibe;
  • linha 27: veremos que a função [asyncData] é executada pelo servidor, mas não pelo cliente;
  • linha 29: a inicialização da propriedade [value] é feita pelo servidor;

Observação: o objeto [this] não é reconhecido na função [asyncData], pois o objeto que encapsula o componente [vue] ainda não foi criado;

5.3.2. Execução

Executamos o projeto [nuxt-02] e digitamos manualmente [localhost:81/nuxt-02/page2] para que o servidor seja acionado. Assim como no início, para a página [index]:

  • o servidor executa a página [page2.vue];
  • envia a página gerada ao navegador. Ela é exibida;
  • os scripts do cliente incorporados na página enviada assumem o controle e executam novamente a página [page2.vue];
  • a página exibida é então modificada;

O resultado final é o seguinte:

Image

Desta vez, o valor exibido é, de fato, aquele definido pelo servidor e, visualmente, não se observa a página “pular” devido a uma alteração feita pelo cliente no valor exibido pelo servidor. O que aconteceu desta vez?

O servidor executou a página [page2] a seguir:


<!-- página 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page2',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  asyncData(context) {
    // quem executa esse código?
    console.log('asyncData, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retornamos uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // esse resultado será incluído nas propriedades de [data]
          resolve({ value: 87 })
          // log
          console.log('asynData terminée')
        }, 1000)
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page2 beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[page2 created]')
  },
  beforeMount() {
    // somente cliente
    console.log('[page2 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page2 mounted]')
  }
}
</script>

Foi a linha 36 que definiu o valor exibido pela linha 7. Portanto, foi isso que o navegador do cliente recebeu. Mais precisamente, ele recebe a seguinte página:


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-02/">
  <link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
  ...
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
              <h4>[nuxt-02] : page serveur, page client</h4>
            </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-02/" target="_self" class="nav-link">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page2" target="_self" class="nav-link active nuxt-link-active">
                        Page 2
                      </a>
                    </li>
                  </ul>
                </div>
                <div class="col-10">
                  <div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
                    Page 2 - value = 87
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>
  window.__NUXT__ = (function (a, b, c) {
      return {
        layout: "default", data: [{ value: 87 }], error: null, state: { counter: 0 }, serverRendered: true,
        logs: [
          { date: new Date(1574096608555), args: ["asyncData, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
          { date: new Date(1574096608575), args: ["[page2 beforeCreate]"], type: a, level: b, tag: c },
          { date: new Date(1574096608599), args: ["[page2 created]"], type: a, level: b, tag: c }
        ]
      }
    }("log", 2, ""));</script>
  <script src="/nuxt-02/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
  • linha 48: vemos que o valor na página recebida é 87;
  • linha 61: na resposta do servidor, vemos dois objetos: [data] e [state]:
    • [state] é o estado do store [Vuex]. Este foi instanciado a partir do conteúdo da pasta [store] do aplicativo [nuxt-02];
    • [data] contém as propriedades criadas pelo servidor por meio da função [asyncData]. Encontramos a propriedade [value : 87] criada pelo servidor. Os scripts do cliente irão integrar essa propriedade às da página [page2];

Voltemos ao código da página [page2]:


<!-- página 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page2',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  asyncData(context) {
    // quem executa esse código?
    console.log('asyncData, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retornamos uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // esse resultado será incluído nas propriedades de [data]
          resolve({ value: 87 })
          // log
          console.log('asynData terminée')
        }, 1000)
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page2 beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[page2 created]')
  },
  beforeMount() {
    // somente cliente
    console.log('[page2 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page2 mounted]')
  }
}
</script>
  • a linha 7 utiliza a propriedade [value]. No entanto, a página não define nenhuma propriedade chamada [value]. Contudo, os scripts do cliente criaram automaticamente essa propriedade por meio do objeto [data: [{ value: 87 }]] recebido do servidor;

Os logs mostram, além disso, que a função [asyncData] não foi executada pelo cliente:

Image

A função [asyncData] foi executada pelo servidor [1], mas não pelo cliente [2]. Além disso, observa-se que as funções do ciclo de vida não são executadas pelo servidor antes do término da função [asyncData]. É possível aumentar o tempo de espera na função [asyncData] para verificar isso.

5.4. A página [page3]

Adicionamos uma nova página [page3] à nossa aplicação:

Image

5.4.1. O componente [navigation]

O componente [vavigation] é modificado para permitir a navegação para a nova página:


<template>
  <!-- menu Bootstrap com três opções -->
  <b-nav vertical>
    <b-nav-item to="/" exact exact-active-class="active">
      Home
    </b-nav-item>
    <b-nav-item to="/page1" exact exact-active-class="active">
      Page 1
    </b-nav-item>
    <b-nav-item to="/page2" exact exact-active-class="active">
      Page 2
    </b-nav-item>
    <b-nav-item to="/page3" exact exact-active-class="active">
      Page 3
    </b-nav-item>
  </b-nav>
</template>

5.4.2. O código de [page3]

O código da página [page3] é o seguinte:


<!-- página 3 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page3',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  fetch(context) {
    // quem executa esse código?
    console.log('fetch, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retorna uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // sucesso
          resolve()
        }, 1000)
      }).then(() => {
        // modifica-se o store
        context.store.commit('increment', 28)
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page3 beforeCreate]')
  },
  created() {
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('[page3 created], value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page3 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page3 mounted]')
  }
}
</script>
  • linha 30: a função [fetch] tem um comportamento semelhante ao da função [asyncData]:
    • ela é executada antes das funções do ciclo de vida;
    • o objeto [this] não é reconhecido nesta função;
    • seu funcionamento é assíncrono;
    • o ciclo de vida não começa enquanto a função assíncrona não tiver retornado seu resultado;
    • o resultado é retornado aqui pelo método [then] da função [Promise], linha 43;
    • a função [fetch] recebe o parâmetro [context]. Este representa o contexto [nuxt] do momento;
  • linha 30: entre suas inúmeras propriedades, o objeto [context] possui uma propriedade [store] que representa o store [Vuex] do aplicativo;
  • linha 41: artificialmente, sinaliza-se o sucesso do [Promise] após um segundo (cf. documento |Introdução à linguagem ECMASCRIPT 6 por meio de exemplos|);
  • linha 45: o método [then] é então executado. Nele, incrementa-se o contador do [store];

5.4.3. Execução

Executa-se o projeto [nuxt-02] e digita-se [localhost:81/nuxt-02/page3] manualmente para que o servidor seja acionado. Assim como no início, para a página [index]:

  • o servidor executa a página [page3.vue];
  • envia a página gerada ao navegador. Ela é exibida;
  • os scripts do cliente incorporados na página enviada assumem o controle e executam novamente a página [page3.vue];
  • a página exibida é então modificada;

O resultado final é o seguinte:

Image

O valor exibido é, de fato, aquele definido pelo servidor e, visualmente, não se percebe que a página “pule” devido a uma alteração feita pelo cliente no valor exibido pelo servidor. O que aconteceu desta vez?

O servidor executou a página [page3] a seguir:


<!-- página 3 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page3',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  fetch(context) {
    // quem executa esse código?
    console.log('fetch, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retornamos uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // sucesso
          resolve()
        }, 1000)
      }).then(() => {
        // modifica-se o store
        context.store.commit('increment', 28)
        // registro
        console.log('fetch commit terminé')
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page3 beforeCreate]')
  },
  created() {
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('[page3 created], value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page3 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page3 mounted]')
  }
}
</script>
  • linha 45: a função assíncrona [fetch] é a primeira das funções acima a ser executada. Ela recebe como parâmetro um objeto chamado [context], que é o contexto [nuxt] do momento. Entre as inúmeras propriedades desse objeto, a propriedade [context.store] representa o store [Vuex];
  • linha 45: na função assíncrona [fetch], o servidor define o contador do store como 28;
  • linha 56: quando a função [created] é executada, [nuxt] garante que a função assíncrona [fetch] tenha concluído seu trabalho;
  • linha 58: o valor do contador da persiana é atribuído à propriedade [value] da linha 27;
  • linha 7: exibição do valor de [value], ou seja, do contador do store;

O navegador do cliente recebe a seguinte página:


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-02/">
  <link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-02/_nuxt/app.js" as="script">
  ...
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
              <h4>[nuxt-02] : page serveur, page client</h4>
            </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-02/" target="_self" class="nav-link">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page2" target="_self" class="nav-link">
                        Page 2
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-02/page3" target="_self" class="nav-link active nuxt-link-active">
                        Page 3
                      </a>
                    </li>
                  </ul>
                </div> <div class="col-10">
                  <div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
                    Page 3 - value = 28
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>
  window.__NUXT__ = (function (a, b, c) {
      return {
        layout: "default", data: [{}], error: null, state: { counter: 28 }, serverRendered: true,
        logs: [
          { date: new Date(1574169916025), args: ["fetch, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
          { date: new Date(1574169917038), args: ["fetch commit terminé"], type: a, level: b, tag: c },
          { date: new Date(1574169917137), args: ["[page3 beforeCreate]"], type: a, level: b, tag: c },
          { date: new Date(1574169917167), args: ["[page3 created], value=", "28"], type: a, level: b, tag: c }
        ]
      }
    }("log", 2, ""));</script>
  <script src="/nuxt-02/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
  • linha 52: percebe-se que o valor na página recebida é 28;
  • linha 65: na resposta do servidor, percebe-se que o servidor enviou ao cliente o estado [state] do armazenamento [Vuex]. Graças a essa informação, os scripts do cliente poderão reconstruir um armazenamento [Vuex];

Os scripts do cliente, por sua vez, executarão o código da página [page3]:


<!-- página 3 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page3',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  fetch(context) {
    // quem executa esse código?
    console.log('fetch, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retornamos uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // sucesso
          resolve()
        }, 1000)
      }).then(() => {
        // modifica-se o store
        context.store.commit('increment', 28)
        // registro
        console.log('fetch commit terminé')
      })
    }
  },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[page3 beforeCreate]')
  },
  created() {
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('[page3 created], value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page3 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page3 mounted]')
  }
}
</script>
  • linha 58: a função [created] executada pelo cliente atribui o valor do contador à propriedade [value] da linha 27;
  • a linha 7 exibe esse valor. Como é o mesmo valor enviado pelo servidor, não se observa a página “pular” devido a uma alteração;

Além disso, os logs mostram que a função [fetch] não foi executada pelo cliente:

Image

A função [fetch] foi executada pelo servidor [1], mas não pelo cliente [2]. Além disso, observa-se que as funções do ciclo de vida não são executadas pelo servidor antes do término da função [fetch] [3]. É possível aumentar o tempo de espera na função [fetch] para verificar isso.

As páginas [page1] e [page3] mostraram dois métodos que utilizam o store [Vuex] para transmitir informações do servidor ao cliente. É possível questionar se eles são equivalentes. Criamos uma página [page4] para verificar isso.

5.5. A página [page4]

Adicionamos uma nova página [page4] ao nosso aplicativo:

Image

5.5.1. O componente [navigation]

O componente [navigation] é modificado para permitir a navegação para a nova página:


<template>
  <!-- menu Bootstrap com cinco opções -->
  <b-nav vertical>
    <b-nav-item to="/" exact exact-active-class="active">
      Home
    </b-nav-item>
    <b-nav-item to="/page1" exact exact-active-class="active">
      Page 1
    </b-nav-item>
    <b-nav-item to="/page2" exact exact-active-class="active">
      Page 2
    </b-nav-item>
    <b-nav-item to="/page3" exact exact-active-class="active">
      Page 3
    </b-nav-item>
    <b-nav-item to="/page4" exact exact-active-class="active">
      Page 4
    </b-nav-item>
  </b-nav>
</template>

5.5.2. O código de [page4]

O código da página [page4] é o seguinte:


<!-- página 4 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary"> Page 4 - value = {{ value }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page4',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  async beforeCreate() {
    // cliente e servidor
    console.log('[page4 beforeCreate]')
    // apenas para o servidor
    if (process.server) {
      // executa-se a função assíncrona
      const valeur = await new Promise(function(resolve, reject) {
        // normalmente, aqui há uma função assíncrona
        // simula-se com uma espera de 10 segundos
        setTimeout(() => {
          // sucesso — retorna-se o valor do contador
          resolve(52)
        }, 10000)
      })
      // modifica-se o store
      this.$store.commit('increment', valeur)
      // registro
      console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
    }
  },
  created() {
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('[page4 created], value=', this.value)
  },
  beforeMount() {
    // somente cliente
    console.log('[page4 beforeMount]')
  },
  mounted() {
    // somente cliente
    console.log('[page4 mounted]')
  }
}
</script>
  • linha 30: o que antes era feito na função [fetch] agora é feito no método [beforeCreate]. Utiliza-se o par async (linha 30) / await (linha 36) para aguardar o término da função assíncrona;
  • linha 36: recupera-se o resultado da função assíncrona, retornado na linha 41 após 10 segundos (linha 42);
  • linhas 50-54: no método [created], executado tanto no lado do servidor quanto no lado do cliente, o contador é atribuído à propriedade [value] da página;

5.5.3. Execução

Executa-se o projeto [nuxt-02] e digita-se manualmente [localhost:81/nuxt-02/page4] para que o servidor seja acionado. Assim como na inicialização da página [index]:

  • o servidor executa a página [page4.vue];
  • envia a página gerada ao navegador. Ela é exibida;
  • os scripts do cliente incorporados na página enviada assumem o controle e executam novamente a página [page4.vue];
  • a página exibida é então modificada;

O resultado final é o seguinte:

Image

Ao contrário do esperado, o valor exibido em [2] não é 52. O que aconteceu?

Os logs são os seguintes:

Image

Pode-se observar que, em [1], o registro de conclusão da ação assíncrona não foi exibido. A função [created], que exibe o valor do contador, mostra 0. Tudo isso sugere que [nuxt] não aguardou o término da ação assíncrona.

Se voltarmos ao terminal da função VSCode, que foi usada para iniciar o aplicativo, encontramos os registros da função [3-4]. Percebemos que a função assíncrona foi efetivamente executada no lado do servidor.

No final das contas, a função [beforeCreate] foi executada integralmente no lado do servidor, mas [nuxt] não aguardou o término de sua execução para enviar a página ao navegador do cliente, embora tenha aguardado o término da função [fetch]. Portanto, é esse método que deve ser utilizado se quisermos que o servidor inicialize um store [Vuex].

5.6. Navegação no aplicativo [vue]

Mostramos o que acontecia quando cada uma das páginas [index, page1, page2, page3, page4] era carregada inicialmente pelo servidor. Na prática, não é isso que ocorre: em funcionamento normal, apenas a página [index] é buscada no servidor. Vejamos as três páginas nesse caso:

página [index]

Image

Já explicamos esse resultado no parágrafo sobre links.

Agora, vamos clicar no link [Page 1]:

Image

O valor exibido é 0. Era 25 quando a página foi solicitada pela primeira vez ao servidor, digitando manualmente seu endereço URL. A explicação é simples. O código executado é o seguinte:


  created() {
    // cliente e servidor
    console.log('[page1 created]')
    // somente servidor
    if (process.server) {
      this.$store.commit('increment', 25)
    }
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('value=', this.value)
},

Era a linha 6 que definia o contador para 25. Como a página não foi solicitada ao servidor, as linhas 5 a 7 não foram executadas e o contador do store [Vuex] permaneceu em 0.

Agora, vamos clicar no link [Page 2]:

Image

Desta vez, nenhum valor é exibido e, além disso, aparece um aviso nos logs do console:

Image

  • Em [1], descobrimos que a função [asyncData] foi executada pelo cliente. É sempre assim:
    • ela é executada pelo servidor se a página for solicitada ao servidor. Nesse caso, ela não é executada pelo cliente;
    • e, sempre que a página for o destino da rota atual do cliente;
  • em [2]: [nuxt] emite um aviso porque, no modelo da página, há uma expressão reativa {{ value }}, embora a página não possua a propriedade [value];

Lembrando o código executado pelo cliente:


asyncData() {
    // quem executa esse código?
    console.log('asyncData, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retorna uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, aqui teríamos uma função assíncrona — mas não neste caso
        // esse resultado será incluído nas propriedades de [data]
        resolve({ value: 87 })
      })
    }
  },
  • a linha 3 permitiu constatar que a função [asyncData] foi executada pelo cliente antes mesmo das funções do ciclo de vida;
  • a linha 5 impediu a execução do restante do código que criava a propriedade [value], pois esse código é executado pelo cliente;

Agora, vamos passar para a página [page3]:

Image

  • em [2], o valor era 28 quando a página foi fornecida pelo servidor. Aqui, esse não é o caso;
  • na [4], vemos que a função [fetch] foi executada no lado do cliente;

Vamos examinar o código executado pelo cliente:


...
fetch(context) {
    // quem executa esse código?
    console.log('fetch, client=', process.client, 'serveur=', process.server)
    // apenas para o servidor
    if (process.server) {
      // retorna-se uma promessa
      return new Promise(function(resolve, reject) {
        // normalmente, temos aqui uma função assíncrona
        // simulamos isso com uma espera de um segundo
        setTimeout(() => {
          // sucesso
          resolve()
        }, 1000)
      }).then(() => {
        // modifica-se o store
        context.store.commit('increment', 28)
        // registro
        console.log('fetch commit terminé')
      })
    }
},
...
  • o cliente executa o método [fetch], linha 2;
  • as linhas 6 a 21 não são executadas porque a condição [process.server] é falsa. Portanto, a linha 17, que define o contador como 28, não é executada. Ele permanece em zero. É por isso que o cliente exibe 0 em vez de 28;

Passemos agora para a página [page4]. Temos o seguinte resultado:

Image

  • em [2], o valor do contador;
  • em [3], os logs do cliente;

O código executado pelo cliente é o seguinte:


...
data() {
    return {
      value: 0
    }
  },
  // ciclo de vida
  async beforeCreate() {
    // cliente e servidor
    console.log('[page4 beforeCreate]')
    // apenas para o servidor
    if (process.server) {
      // é executada a função assíncrona
      const valeur = await new Promise(function(resolve, reject) {
        // normalmente, aqui temos uma função assíncrona
        // simulamos com uma espera de 10 segundos
        setTimeout(() => {
          // sucesso — retorna-se o valor do contador
          resolve(52)
        }, 10000)
      })
      // modifica-se o store
      this.$store.commit('increment', valeur)
      // registro
      console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
    }
  },
  created() {
    // cliente e servidor
    this.value = this.$store.state.counter
    console.log('[page4 created], value=', this.value)
  },
...
  • as linhas 12 a 26 não são executadas pelo cliente, pois a condição [process.server] da linha 12 é falsa. Portanto, o contador do store [Vuex] tem valor 0 (seu valor inicial no store) e é esse valor que a página exibe;

Podemos nos perguntar o que acontece quando comentamos a condição [if] das linhas 12 e 26. Aqui está a resposta:

  • desta vez, o cliente executa as linhas 14 a 25, mas [nuxt] não aguarda o término da função assíncrona (como no caso do servidor) e, portanto, mantém o contador em 0;
  • após 10 s, a função assíncrona é concluída e o contador é definido como 52 na linha 23;
  • quando se navega novamente para a página [page4], é exibido o valor 52;

5.7. Résumé

A partir de nossos diversos testes, destacamos os seguintes pontos:

  • se a página [index] precisar conter dados externos, estes podem ser buscados pelo servidor por meio da função [asyncData];
  • se o servidor precisar inicializar um store [Vuex] com dados externos ao carregar a página [index], ele fará isso na função [fetch];
  • a página gerada pelo servidor e a página gerada pelo cliente devem ser idênticas para evitar o efeito de “salto” causado pelo fato de a página do cliente substituir visualmente a página enviada pelo servidor e exibida inicialmente;

Vamos explorar outros aspectos da função [nuxt] por meio de um novo exemplo.