Skip to content

11. Przykład [nuxt-08]: moduły pośredniczące routingu

W tym przykładzie wprowadzamy pojęcie modułów pośredniczących routingu, czyli skryptów uruchamianych przy każdej zmianie trasy.

Przykład [nuxt-08] uzyskano początkowo poprzez skopiowanie projektu [nuxt-01]:

Image

Moduły pośredniczące routingu muszą znajdować się w folderze o nazwie [middleware] [2]. Możliwe jest zastosowanie routingu dwupoziomowego:

  • routing stosowany przy każdej nawigacji. Jest on wówczas zadeklarowany w pliku [nuxt.config.js];
  • routing stosowany do konkretnej strony, gdy jest ona celem routingu. Routing ten jest wówczas zadeklarowany na tej stronie docelowej;

11.1. Routing ogólny

Plik [middleware / routing.js] zapewni routing ogólny. Jest on przedmiotem następującej deklaracji w pliku [nuxt.config.js]:


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

Middleware'y routingu ogólnego są właściwością routera (wiersz 1). Może istnieć wiele middleware'ów routingu. Dlatego w wierszu 3 wartość właściwości [middleware] jest tablicą. Widać, że do wskazania modułu pośredniczącego nie używa się ścieżki. Zostanie on automatycznie wyszukany w folderze [middleware] projektu;

Middleware [routing] służy tutaj wyłącznie do generowania logów:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // kto wykonuje ten kod?
  console.log('[routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const routing = '[routing ' + who + ']'
  // liczba argumentów
  console.log(routing + ', il y a', args.length, 'argument(s)')

  // pierwszy argument
  const context = args[0]
  // klucze kontekstu
  dumpkeys(routing + ', context', context)
  // aplikacja
  dumpkeys(routing + ', context.app', context.app)
  // trasa
  dumpkeys(routing + ', context.route', context.route)
  console.log(routing + ', context.route=', context.route)
  // router
  dumpkeys(routing + ', context.app.router', context.app.router)
  // 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 kluczy [object]
  const ligne = 'Liste des clés [' + message + ']'
  console.log(ligne)
  // lista kluczy
  if (object) {
    console.log(Object.keys(object))
  }
}
  • wiersz 3: zobaczymy, że middleware otrzymuje argument: kontekst wykonawcy (serwer lub klient);
  • wiersze 4–25: wyświetlamy właściwości różnych obiektów, aby sprawdzić, co można wykorzystać. Okazuje się, że kontekst oprogramowania pośredniczącego jest niemal identyczny z kontekstem wtyczki;

11.2. Przekierowanie do konkretnej strony

Chcemy kontrolować sposób, w jaki użytkownik trafia na stronę [index]. W tym celu musimy wprowadzić właściwość [middleware] na tej stronie [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',
  // używane komponenty
  components: {
    Layout,
    Navigation
  },
  // cykl życia
  beforeCreate() {
    // klient i serwer
    console.log('[home beforeCreate]')
  },
  created() {
    // klient i serwer
    console.log('[home created]')
  },
  beforeMount() {
    // tylko klient
    console.log('[home beforeMount]')
  },
  mounted() {
    // tylko klient
    console.log('[home mounted]')
  },
  // routing
  middleware: ['index-routing']
}
</script>
  • wiersz 34: właściwość [middleware] zawiera listę skryptów, które mają być wykonywane za każdym razem, gdy następną wyświetlaną stroną jest strona [index]. Również w tym przypadku skrypty te będą wyszukiwane w folderze [middleware] projektu;

Oprogramowanie pośredniczące [index-routing] ma następującą postać:


/* eslint-disable no-undef */
/* eslint-disable no-console */
export default function(...args) {
  // kto wykonuje ten kod?
  console.log('[index-routing], process.server=', process.server, 'process.client=', process.client)
  const who = process.server ? 'server' : 'client'
  const indexRouting = '[index-routing ' + who + ']'
  // liczba argumentów
  console.log(indexRouting + ', il y a', args.length, 'argument(s)')

  // pierwszy argument
  const context = args[0]
  // klucze kontekstu
  dumpkeys(indexRouting + ', context', context)
  // aplikacja
  dumpkeys(indexRouting + ', context.app', context.app)
  // trasa
  dumpkeys(indexRouting + ', context.route', context.route)
  console.log(indexRouting + ', context.route=', context.route)
  // router
  dumpkeys(indexRouting + ', context.app.router', context.app.router)
  // 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)
  // skąd pochodzimy?
  if (context.from) {
    console.log('from=', context.from)
  }
}

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

Kod [index-routing] jest identyczny z kodem [routing] i daje te same wyniki. Interesuje nas, kiedy te dwa moduły pośredniczące są uruchamiane.

11.3. Uruchomienie projektu

Uruchamiamy projekt. W tym momencie logi wyglądają następująco:

Serwer najpierw uruchamia skrypt [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' } ]

Widzimy tu to samo, co uzyskaliśmy przy użyciu wtyczek.

  • wiersz 15: właściwość [redirect] jest często wykorzystywana w oprogramowaniu pośredniczącym (middleware): pozwala ona zmienić cel bieżącego routingu;

Następnie, ponieważ strona, która ma zostać wyświetlona, to strona [index], serwer uruchamia skrypt [index-routing] i wyświetla następujące logi:

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

Wyniki uzyskane przy użyciu skryptu [index-routing] są analogiczne do tych uzyskanych przy użyciu skryptu [routing].

Po odebraniu strony [index] przez przeglądarkę klienta kontrolę przejmują skrypty klienckie. Logi przyjmują następujący wygląd:

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

Widać zatem, że podczas uruchamiania aplikacji klient nie uruchamia żadnego oprogramowania pośredniczącego. Oznacza to, że sytuacja ta będzie miała miejsce za każdym razem, gdy użytkownik wymusi wywołanie serwera. Oprogramowanie pośredniczące jest uruchamiane przez klienta wyłącznie podczas nawigacji w obrębie klienta. Przejdźmy na przykład do strony [page1] (jesteśmy na stronie [index]) za pomocą linku [Page 1]. Logi wyglądają wtedy następująco:

[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]
  • wiersz 2: oprogramowanie pośredniczące [routing] jest uruchamiane przez klienta;
  • wiersz 4: zwróć uwagę na właściwość [from]: jest to trasa, z której pochodzimy;
  • wiersz 9: [context.route] to trasa docelowa;
  • wiersze 15–18: wyświetlenie strony [page1];

Teraz wróćmy do strony [index] za pomocą linku [Home]. Logi wyglądają wówczas następująco:

[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]
  • wiersze 1–15: klient uruchamia oprogramowanie pośredniczące [routing]. Jest to normalne zachowanie. Jest ono uruchamiane przy każdej zmianie trasy;
  • wiersze 16–29: klient uruchamia oprogramowanie pośredniczące [index-routing], ponieważ:
    • [index] jest celem bieżącej trasy (patrz wiersz 23);
    • strona [index] zdefiniowała moduł pośredniczący o nazwie [index-routing];

Widać zatem, że moduły pośredniczące routingu ogólnego są uruchamiane przez klienta przed modułami pośredniczącymi przypisanymi do stron.