Skip to content

11. Esempio [nuxt-08]: middleware di routing

In questo esempio, introduciamo il concetto di middleware di routing, ovvero script eseguiti ogni volta che cambia un percorso.

L'esempio [nuxt-08] viene inizialmente creato clonando il progetto [nuxt-01]:

Image

Il middleware di routing deve essere collocato in una cartella denominata [middleware] [2]. È possibile avere un routing a due livelli:

  • routing applicato a ogni navigazione. Questo viene poi dichiarato nel file [nuxt.config.js];
  • routing applicato a una pagina specifica, quando tale pagina è la destinazione del routing. Questo routing viene quindi dichiarato in quella pagina di destinazione;

11.1. Routing generale

Il file [middleware/routing.js] gestirà il routing generale. Viene dichiarato come segue nel file [nuxt.config.js]:


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

Il middleware di routing generale è una proprietà del router (riga 1). Possono esserci più componenti di middleware di routing. Ecco perché, alla riga 3, il valore della proprietà [middleware] è un array. Si noti che non usiamo un percorso per specificare il middleware. Verrà cercato automaticamente nella cartella [middleware] del progetto;

Il middleware [routing] registra i log solo qui:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // who executes this code?
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // number of arguments
  console.log(routing + ', il y a', args.length, 'argument(s)')
 
  // 1st argument
  const context = args[0]
  // key context
  dumpkeys(routing + ', context', context)
  // the application
  dumpkeys(routing + ', context.app', context.app)
  // the road
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // the router
  dumpkeys(routing + ', context.app.router', context.app.router)
  // on 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) {
  // list of [object] keys
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // kEY LIST
  if (object) {
    console.log(Object.keys(object))
  }
}
  • riga 3: vedremo che il middleware riceve un argomento: il contesto dell'esecutore (server o client);
  • righe 4–25: visualizziamo le proprietà di vari oggetti per determinare cosa è utilizzabile. Scopriremo che il contesto del middleware è quasi identico al contesto del plugin;

11.2. Routing per una pagina specifica

Vogliamo controllare come gli utenti arrivano alla pagina [index]. Per farlo, dobbiamo aggiungere la proprietà [middleware] a questa 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',
  // components used
  components: {
    Layout,
    Navigation
  },
  // life cycle
  beforeCreate() {
    // client and server
    console.log('[home beforeCreate]')
  },
  created() {
    // client and server
    console.log('[home created]')
  },
  beforeMount() {
    // customer only
    console.log('[home beforeMount]')
  },
  mounted() {
    // customer only
    console.log('[home mounted]')
  },
  // routing
  middleware: ['index-routing']
}
</script>
  • riga 34: la proprietà [middleware] elenca gli script da eseguire ogni volta che la pagina successiva visualizzata è la pagina [index]. Anche in questo caso, questi script verranno cercati nella cartella [middleware] del progetto;

Il middleware [index-routing] è il seguente:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // who executes this code?
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // number of arguments
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')
 
  // 1st argument
  const context = args[0]
  // key context
  dumpkeys(indexRouting + ', context', context)
  // the application
  dumpkeys(indexRouting + ', context.app', context.app)
  // the road
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // the router
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // on 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)
  // where do we come from?
  if (context.from) {
    console.log('from=', context.from)
  }
}
 
function dumpkeys(message, object) {
  // list of [object] keys
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // kEY LIST
  if (object) {
    console.log(Object.keys(object))
  }
}

Il codice per [index-routing] è identico a quello di [routing] e produce gli stessi risultati. Ciò che ci interessa è vedere quando vengono eseguiti questi due middleware.

11.3. Esecuzione del progetto

Eseguiamo il progetto. I log sono i seguenti:

Lo script [routing] viene eseguito per primo dal server:

[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' } ]

Questo è lo stesso risultato che abbiamo ottenuto con i plugin.

  • riga 15: la proprietà [redirect] è spesso utilizzata nel middleware; consente di modificare la destinazione del routing corrente;

Quindi, poiché la pagina da visualizzare è la pagina [index], il server esegue lo script [index-routing] e visualizza i seguenti log:

[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' } ]

I risultati ottenuti con lo script [index-routing] sono simili a quelli ottenuti con lo script [routing].

Una volta che la pagina [index] viene ricevuta dal browser del client, subentrano gli script del client. I log diventano i seguenti:

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

Possiamo quindi notare che, all'avvio dell'applicazione, il client non esegue alcun middleware. Ciò significa che ciò accadrà ogni volta che l'utente invia una richiesta al server. Il middleware viene eseguito dal client solo durante la navigazione all'interno dell'applicazione. Ad esempio, navighiamo alla pagina [page1] (attualmente ci troviamo sulla pagina [index]) utilizzando il link [Page 1]. I log risultano quindi i seguenti:

[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]
  • riga 2: il middleware [routing] viene eseguito dal client;
  • riga 4: nota la proprietà [from]: questa è la route da cui proveniamo;
  • riga 9: [context.route] è il percorso verso cui ci stiamo dirigendo;
  • righe 15–18: visualizzazione della pagina [page1];

Ora torniamo alla pagina [index] utilizzando il link [Home]. I log sono quindi i seguenti:

[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]
  • righe 1-15: il client esegue il middleware [routing]. Questo è normale. Viene eseguito ogni volta che cambia il percorso;
  • righe 16–29: il client esegue il middleware [index-routing], perché:
    • [index] è la destinazione del percorso corrente (vedi riga 23);
    • la pagina [index] ha definito un middleware denominato [index-routing];

Possiamo quindi vedere che il middleware di routing generale viene eseguito dal client prima del middleware associato alle pagine.