# Rendu côté serveur (SSR)

WARNING

Nécessite Vue 2.6+ avec serverPrefetch

# Plugin Vue CLI

J'ai créé un plugin pour vue-cli (opens new window) afin que vous puissiez ajouter Apollo (ainsi qu'un serveur GraphQL optionnel!) en deux minutes ! ✨🚀

Dans votre projet Vue CLI 3 :

vue add @akryum/ssr

Plus d'informations (opens new window)

# Récupération de component

TIP

Suivez le guide SSR officiel (opens new window) pour en savoir plus sur le rendu côté serveur avec Vue.

Par défaut, avez vue-server-renderer, toutes les requêtes GraphQL de vos composant rendus côté serveur sont pré-récupérées automatiquement.

TIP

Vous avec accès à this dans les options telles que variables, même côté serveur !

Exemple :

export default {
  apollo: {
    allPosts: {
      query: gql`query AllPosts {
        allPosts {
          id
          imageUrl
          description
        }
      }`,
    }
  }
}

Exemple 2 :

export default {
  apollo: {
    post: {
      query: gql`query Post($id: ID!) {
        post (id: $id) {
          id
          imageUrl
          description
        }
      }`,
      variables () {
        return {
          id: this.id,
        }
      },
    }
  }
}

# Sauter la pré-récupération de données

Vous pouvez ne pas pré-récupérer de données côté serveur pour une requête spécifique en assignant l'option prefetch à false.

Voici un exemple qui ne pré-récupère pas la requête :












 




export default {
  apollo: {
    allPosts: {
      query: gql`query AllPosts {
        allPosts {
          id
          imageUrl
          description
        }
      }`,
      // Pas de pré-récupération
      prefetch: false,
    }
  }
}

Si vous souhaitez ne pas pré-récupérer de données pour toutes les requêtes, vous pouvez utiliser l'option $prefetch option :




 












export default {
  apollo: {
    // Pas de pré-récupération
    $prefetch: false,
    allPosts: {
      query: gql`query AllPosts {
        allPosts {
          id
          imageUrl
          description
        }
      }`,
    }
  }
}

# Créer le client Apollo

Il est recommandé de créer les clients Apollo dans une fonction prenant un argument ssr, assigné à true côté serveur et false côté client.

Lorsque ssr est false, nous essayons de récupérer l'état du cache Apollo avec cache.restore, en récupérant la variable window.__APOLLO_STATE__ qui est injectée dans le fichier HTML sur le serveur lors du rendu.

Voici un exemple :





















 
 
 
 
 
 
 
 
 
 
















// apollo.js

import Vue from 'vue'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import VueApollo from 'vue-apollo'

// Installation du plugin Vue
Vue.use(VueApollo)

// Création du client Apollo
export function createApolloClient (ssr = false) {
  const httpLink = new HttpLink({
  // Vous devez utiliser un URL absolu
    uri: ENDPOINT + '/graphql',
  })

  const cache = new InMemoryCache()

  // Côté client, on récupère l'état injecté
  if (!ssr) {
    if (typeof window !== 'undefined') {
      const state = window.__APOLLO_STATE__
      if (state) {
        // Si vous utilisez plusieurs clients, utilisez `state.<client_id>`
        cache.restore(state.defaultClient)
      }
    }
  }

  const apolloClient = new ApolloClient({
    link: httpLink,
    cache,
    ...(ssr ? {
      // On active cette option côté serveur pour optimiser les requêtes lors du SSR
      ssrMode: true,
    } : {
      // Désactivation temporaire de la récupération forcée de requêtes
      ssrForceFetchDelay: 100,
    }),
  })

  return apolloClient
}

# Création de l'application

AU lieu de créer notre instance Vue racine tout de suite, nous utilisons une fonction createApp qui accepte un paramètre context.

Cette fonction est utilisée côté client et côté serveur avec une valeur ssr différente dans le context. Nous utilisons cette valeur dans la méthode createApolloClient que nous avons écrite plus tôt.

Voici un exemple d'une fonction createApp classique :









 



























 




















// app.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Vuex from 'vuex'
import { sync } from 'vuex-router-sync'

import VueApollo from 'vue-apollo'
import { createApolloClient } from './apollo'

import App from './ui/App.vue'
import routes from './routes'
import storeOptions from './store'

Vue.use(VueRouter)
Vue.use(Vuex)

function createApp (context) {
  const router = new VueRouter({
    mode: 'history',
    routes,
  })

  const store = new Vuex.Store(storeOptions)

  // On synchronise  le router avec le store Vuex
  // Cela enregistre `store.state.route`
  sync(store, router)

  // Restauration de l'état Vuex
  if (!context.ssr && window.__INITIAL_STATE__) {
    // On initialise l'état du store avec la donnée injectée depuis le serveur
    store.replaceState(window.__INITIAL_STATE__)
  }

  // Apollo
  const apolloClient = createApolloClient(context.ssr)
  const apolloProvider = new VueApollo({
    defaultClient: apolloClient,
  })

  return {
    app: new Vue({
      el: '#app',
      router,
      store,
      apolloProvider,
      ...App,
    }),
    router,
    store,
    apolloProvider,
  }
}

export default createApp

# Côté client

La partie client est simple -- on appelle createApp avec ssr passé à false :

// client-entry.js

import createApp from './app'

createApp({
  ssr: false,
})

# Côté serveur

Nous n'avons besoin de rien faire de particulier, à part de stocker le cache Apollo pour pouvoir l'injecter dans le HTML du client. Vous pouvez trouver plus d'informations sur le routage côté serveur (opens new window) et la pré-récupération de données (opens new window) dans le guide SSR officiel.

Voici un exemple avec Vue Router et un store Vuex :



 






















 





// server-entry.js

import ApolloSSR from 'vue-apollo/ssr'
import createApp from './app'

export default () => new Promise((resolve, reject) => {
  const { app, router, store, apolloProvider } = createApp({
    ssr: true,
  })

  // Ajout de l'emplacement du routeur
  router.push(context.url)

  // On attend que le routeur ait résolu les possibles hooks asynchrones
  router.onReady(() => {
    // Ce hook `rendered` est appelé lorsque l'application est rendue
    context.rendered = () => {
      // Un fois l'application rendue, notre store est maintenant
      // rempli avec l'état de nos composants.
      // Lorsque nous attachons un état au contexte et que l'option `template`
      // est utilisée comme moteur de rendu, l'état est automatiquement
      // sérialisé et injecté dans le HTML dans `window.__INITIAL_STATE__`.
      context.state = store.state

      // On injecte également l'état du cache Apollo
      context.apolloState = ApolloSSR.getStates(apolloProvider)
    }
    resolve(app)
  })
})

Vous pouvez utiliser la méthode ApolloSSR.getStates pour récupérer le code JavaScript nécessaire à l'injection dans la page générée pour passer la donnée du cache Apollo au client.

Dans le template de page (opens new window), utilisez l'utilitaire renderState :

{{{ renderState({ contextKey: 'apolloState', windowKey: '__APOLLO_STATE__' }) }}}

Voici un exemple complet :















 




<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>{{ title }}</title>
    {{{ renderResourceHints() }}}
    {{{ renderStyles() }}}
  </head>
  <body>
    <!--vue-ssr-outlet-->
    {{{ renderState() }}}
    {{{ renderState({ contextKey: 'apolloState', windowKey: '__APOLLO_STATE__' }) }}}
    {{{ renderScripts() }}}
  </body>
</html>
Dernière mise à jour: 11/02/2021, 11:08:30