# 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>