Skip to content

11. Ejemplo [nuxt-08]: middlewares de enrutamiento

En este ejemplo, introducimos el concepto de middlewares de enrutamiento, que son scripts que se ejecutan cada vez que cambia la ruta.

El ejemplo [nuxt-08] se obtiene inicialmente al copiar el proyecto [nuxt-01]:

Image

Los middlewares de enrutamiento deben estar en una carpeta llamada [middleware] [2]. Puede haber un enrutamiento de dos niveles:

  • un enrutamiento aplicado a cada navegación. Este se declara en el archivo [nuxt.config.js];
  • un enrutamiento aplicado a una página específica, cuando esta es el destino del enrutamiento. Este enrutamiento se declara en dicha página de destino;

11.1. Enrutamiento general

El archivo [middleware / routing.js] se encargará del enrutamiento general. Se declara de la siguiente manera en el archivo [nuxt.config.js]:


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

Los middlewares de enrutamiento general son una propiedad del enrutador (línea 1). Puede haber varios middlewares de enrutamiento. Por eso, en la línea 3, el valor de la propiedad [middleware] es un array. Se observa que no se utiliza una ruta para designar el middleware. Se buscará automáticamente en la carpeta [middleware] del proyecto;

El middleware [routing] aquí solo genera registros:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // ¿Quién ejecuta este código?
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // número de argumentos
  console.log(routing + ', il y a', args.length, 'argument(s)')

  // primer argumento
  const context = args[0]
  // claves del contexto
  dumpkeys(routing + ', context', context)
  // la aplicación
  dumpkeys(routing + ', context.app', context.app)
  // la ruta
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // el enrutador
  dumpkeys(routing + ', context.app.router', context.app.router)
  // el 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) {
  // lista de claves de [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // lista de claves
  if (object) {
    console.log(Object.keys(object))
  }
}
  • línea 3: veremos que el middleware recibe un argumento: el contexto del ejecutor (servidor o cliente);
  • líneas 4-25: se muestran las propiedades de diferentes objetos para saber qué se puede utilizar. Veremos que el contexto del middleware es casi idéntico al contexto del complemento;

11.2. Enrutamiento para una página específica

Queremos controlar la forma en que se llega a la página [index]. Para ello, debemos introducir la propiedad [middleware] en esta página [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',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // ciclo de vida
  beforeCreate() {
    // cliente y servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente y servidor
    console.log('[home created]')
  },
  beforeMount() {
    // solo cliente
    console.log('[home beforeMount]')
  },
  mounted() {
    // solo cliente
    console.log('[home mounted]')
  },
  // enrutamiento
  middleware: ['index-routing']
}
</script>
  • línea 34: la propiedad [middleware] enumera los scripts que se deben ejecutar cada vez que la siguiente página que se muestre sea la página [index]. Una vez más, estos scripts se buscarán en la carpeta [middleware] del proyecto;

El middleware [index-routing] es el siguiente:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // ¿Quién ejecuta este código?
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // número de argumentos
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')

  // primer argumento
  const context = args[0]
  // claves del contexto
  dumpkeys(indexRouting + ', context', context)
  // la aplicación
  dumpkeys(indexRouting + ', context.app', context.app)
  // la ruta
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // el enrutador
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // el 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)
  // ¿de dónde venimos?
  if (context.from) {
    console.log('from=', context.from)
  }
}

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

El código de [index-routing] es idéntico al de [routing] y produce los mismos resultados. Lo que nos interesa es ver cuándo se ejecutan estos dos middlewares.

11.3. Ejecución del proyecto

Ejecutamos el proyecto. Los registros son los siguientes:

El servidor ejecuta primero el script [routing]:

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

Aquí vemos lo mismo que obtuvimos con los complementos.

  • línea 15: la propiedad [redirect] se utiliza con frecuencia en los middlewares: permite cambiar el destino del enrutamiento en curso;

Luego, dado que la página que se va a mostrar es la página [index], el servidor ejecuta el script [index-routing] y muestra los siguientes registros:

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

Los resultados obtenidos con el script [index-routing] son similares a los obtenidos con el script [routing].

Una vez que el navegador del cliente recibe la página [index], los scripts del cliente toman el control. Los registros pasan a ser los siguientes:

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

Así pues, vemos que al iniciar la aplicación, el cliente no ejecuta ningún middleware. Esto significa que esto ocurrirá cada vez que el usuario inicie una llamada al servidor. El cliente solo ejecuta los middlewares cuando navega dentro de la propia aplicación. Naveguemos, por ejemplo, a la página [page1] (estamos en la página [index]) mediante el enlace [Page 1]. Los registros son entonces los siguientes:

[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]
  • línea 2: el middleware [routing] es ejecutado por el cliente;
  • línea 4: fíjate en la propiedad [from]: es la ruta de la que venimos;
  • línea 9: [context.route] es la ruta a la que nos dirigimos;
  • líneas 15-18: visualización de la página [page1];

Ahora regresemos a la página [index] mediante el enlace [Home]. Los registros son entonces los siguientes:

[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]
  • líneas 1-15: el cliente ejecuta el middleware [routing]. Esto es normal. Se ejecuta cada vez que cambia la ruta;
  • líneas 16-29: el cliente ejecuta el middleware [index-routing], debido a que:
    • [index] es el destino de la ruta actual (véase la línea 23);
    • la página [index] ha definido un middleware, llamado [index-routing];

Por lo tanto, se observa que los middlewares de enrutamiento general son ejecutados por el cliente antes que los middlewares asociados a las páginas.