Skip to content

11. Voorbeeld [nuxt-08]: routing-middleware

In dit voorbeeld introduceren we het begrip routerings-middleware: scripts die bij elke routewijziging worden uitgevoerd.

Het voorbeeld [nuxt-08] wordt in eerste instantie verkregen door het project [nuxt-01] te kopiëren:

Image

De routing-middleware moet zich in een map met de naam [middleware] [2] bevinden. Er kan sprake zijn van een tweeledige routing:

  • een routering die op elke navigatie wordt toegepast. Deze wordt dan gedeclareerd in het bestand [nuxt.config.js];
  • routering die op een specifieke pagina wordt toegepast, wanneer deze pagina het doel van de routering is. Deze routering wordt dan in die doelpagina gedeclareerd;

11.1. Algemene routering

Het bestand [middleware / routing.js] zorgt voor de algemene routering. Dit wordt als volgt gedeclareerd in het bestand [nuxt.config.js]:


  router: {
    base: '/nuxt-08/',
    middleware: ['routing']
},

De middleware voor algemene routing is een eigenschap van de router (regel 1). Er kunnen meerdere routing-middleware-componenten zijn. Daarom is de waarde van de eigenschap [middleware] op regel 3 een array. We zien dat er geen pad wordt gebruikt om de middleware aan te duiden. Deze wordt automatisch gezocht in de map [middleware] van het project;

De middleware [routing] genereert hier alleen logbestanden:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // wie voert deze code uit?
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // aantal argumenten
  console.log(routing + ', il y a', args.length, 'argument(s)')

  // eerste argument
  const context = args[0]
  // context-sleutels
  dumpkeys(routing + ', context', context)
  // de applicatie
  dumpkeys(routing + ', context.app', context.app)
  // de route
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // de router
  dumpkeys(routing + ', context.app.router', context.app.router)
  // de router.options.routes
  dumpkeys(routing + ', context.app.router.options.routes', context.app.router.options.routes)
  console.log(routing + ', context.app.router.options.routes=', context.app.router.options.routes)
}

function dumpkeys(message, object) {
  // lijst met sleutels van [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // lijst met sleutels
  if (object) {
    console.log(Object.keys(object))
  }
}
  • regel 3: we zullen zien dat de middleware één argument ontvangt: de context van de uitvoerder (server of client);
  • regels 4-25: we geven de eigenschappen van verschillende objecten weer om te zien wat bruikbaar is. We zullen ontdekken dat de context van de middleware vrijwel identiek is aan de context van de plug-in;

11.2. Routering naar een specifieke pagina

We willen bepalen hoe de pagina [index] wordt bereikt. Hiervoor moeten we de eigenschap [middleware] invoegen in deze pagina [index]:


<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',
  // gebruikte componenten
  components: {
    Layout,
    Navigation
  },
  // levenscyclus
  beforeCreate() {
    // client en server
    console.log('[home beforeCreate]')
  },
  created() {
    // client en server
    console.log('[home created]')
  },
  beforeMount() {
    // alleen client
    console.log('[home beforeMount]')
  },
  mounted() {
    // alleen client
    console.log('[home mounted]')
  },
  // routering
  middleware: ['index-routing']
}
</script>
  • regel 34: de eigenschap [middleware] somt de scripts op die moeten worden uitgevoerd telkens wanneer de volgende weergegeven pagina de pagina [index] is. Ook hier worden deze scripts gezocht in de map [middleware] van het project;

De middleware [index-routing] is als volgt:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // wie voert deze code uit?
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // aantal argumenten
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')

  // eerste argument
  const context = args[0]
  // context-sleutels
  dumpkeys(indexRouting + ', context', context)
  // de applicatie
  dumpkeys(indexRouting + ', context.app', context.app)
  // de route
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // de router
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // de router.options.routes
  dumpkeys(indexRouting + ', context.app.router.options.routes', context.app.router.options.routes)
  console.log(indexRouting + ', context.app.router.options.routes=', context.app.router.options.routes)
  // waar komen we vandaan?
  if (context.from) {
    console.log('from=', context.from)
  }
}

function dumpkeys(message, object) {
  // lijst met sleutels van [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // lijst met sleutels
  if (object) {
    console.log(Object.keys(object))
  }
}

De code van [index-routing] is identiek aan die van [routing] en levert dezelfde resultaten op. Wat ons interesseert, is te zien wanneer deze twee middlewares worden uitgevoerd.

11.3. Uitvoering van het project

We voeren het project uit. De logbestanden zien er dan als volgt uit:

Het script [routing] wordt als eerste door de server uitgevoerd:

[routing], process.server= true process.client= false
[routing server], il y a 1 argument(s)
Liste des clés [[routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

Dit komt overeen met wat we met de plug-ins hadden verkregen.

  • regel 15: de eigenschap [redirect] wordt vaak gebruikt in middleware: hiermee kan het doel van de lopende routing worden gewijzigd;

Vervolgens, omdat de pagina die wordt weergegeven de pagina [index] is, voert de server het script [index-routing] uit en geeft de volgende logberichten weer:

[index-routing], process.server= true process.client= false
[index-routing server], il y a 1 argument(s)
Liste des clés [[index-routing server], context]
[ 'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios' ]
Liste des clés [[index-routing server], context.app]
[ 'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios' ]
Liste des clés [[index-routing server], context.route]
[ 'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
  'matched' ]
[index-routing server], context.route= { name: 'index',
  meta: [ {} ],
  path: '/',
  hash: '',
  query: {},
  params: {},
  fullPath: '/',
  matched:
   [ { path: '',
       regex: /^(?:\/(?=$))?$/i,
       components: [Object],
       instances: {},
       name: 'index',
       parent: undefined,
       matchAs: undefined,
       redirect: undefined,
       beforeEnter: undefined,
       meta: {},
       props: {} } ] }
Liste des clés [[index-routing server], context.app.router]
[ 'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
  'history' ]
Liste des clés [[index-routing server], context.app.router.options.routes]
[ '0', '1', '2' ]
[index-routing server], context.app.router.options.routes= [ { path: '/page1',
    component: [Function: _61cefe10],
    name: 'page1' },
  { path: '/page2',
    component: [Function: _61dd1591],
    name: 'page2' },
  { path: '/', component: [Function: _00d5e140], name: 'index' } ]

De resultaten die worden verkregen met het script [index-routing] zijn vergelijkbaar met die van het script [routing].

Zodra de pagina [index] door de browser van de client is ontvangen, nemen de clientscripts het over. De logbestanden zien er dan als volgt uit:

1
2
3
4
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]

We zien dus dat de client bij het opstarten van de applicatie geen middleware uitvoert. Dit betekent dat dit elke keer zal gebeuren wanneer de gebruiker een verzoek naar de server verstuurt. De middleware wordt door de client alleen uitgevoerd tijdens het navigeren binnen de client. Laten we bijvoorbeeld naar de pagina [page1] navigeren (we bevinden ons op de pagina [index]) via de link [Page 1]. De logbestanden zien er dan als volgt uit:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[page1 beforeCreate]
[page1 created]
[page1 beforeMount]
[page1 mounted]
  • regel 2: de middleware [routing] wordt uitgevoerd door de client;
  • regel 4: let op de eigenschap [from]: dit is de route waar we vandaan komen;
  • regel 9: [context.route] is de route waar we naartoe gaan;
  • regels 15-18: weergave van de pagina [page1];

Laten we nu teruggaan naar de pagina [index] via de link [Home]. De logbestanden zien er dan als volgt uit:

[routing], process.server= false process.client= true
[routing client], il y a 1 argument(s)
Liste des clés [[routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
[index-routing], process.server= false process.client= true
[index-routing client], il y a 1 argument(s)
Liste des clés [[index-routing client], context]
(18) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios", "from"]
Liste des clés [[index-routing client], context.app]
(14) ["router", "nuxt", "head", "render", "data", "beforeCreate", "created", "mounted", "watch", "computed", "methods", "components", "context", "$axios"]
Liste des clés [[index-routing client], context.route]
(8) ["name", "meta", "path", "hash", "query", "params", "fullPath", "matched"]
[index-routing client], context.route= {name: "index", meta: Array(1), path: "/", hash: "", query: {}, }
Liste des clés [[index-routing client], context.app.router]
(10) ["app", "apps", "options", "beforeHooks", "resolveHooks", "afterHooks", "matcher", "fallback", "mode", "history"]
Liste des clés [[index-routing client], context.app.router.options.routes]
(3) ["0", "1", "2"]
[index-routing client], context.app.router.options.routes= (3) [{}, {}, {}]0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
from= {name: "page1", meta: Array(1), path: "/page1", hash: "", query: {}, }
[home beforeCreate]
[home created]
[home beforeMount]
[home mounted]
  • regels 1-15: de client voert de middleware [routing] uit. Dit is normaal. Deze wordt bij elke routewijziging uitgevoerd;
  • regels 16-29: de client voert de middleware [index-routing] uit, en wel omdat:
    • [index] het doel is van de huidige route (zie regel 23);
    • de pagina [index] heeft een middleware gedefinieerd, namelijk [index-routing];

We zien dus dat de algemene routeringsmiddleware door de client wordt uitgevoerd vóór de middleware die aan de pagina’s is gekoppeld.