Skip to content

10. Ejemplo [nuxt-07]: los contextos de cliente y servidor

10.1. Présentation

El ejemplo [nuxt-07] tiene como objetivo explorar el objeto [context] tanto del lado del servidor como del lado del cliente. No hay que olvidar que estos dos actores de las aplicaciones [nuxt] están separados: no comparten nada, salvo:

  • lo que el servidor decide enviar al cliente (en la respuesta HTTP y la página enviada);
  • lo que el cliente decide enviar al servidor (en su solicitud HTTP);

Por lo tanto, aunque, como veremos, los objetos manipulados por el servidor y los manipulados por el cliente tengan el mismo nombre, no son idénticos: a veces pueden ser copias entre sí, pero nunca tienen la misma referencia. Modificar un objeto del cliente no tiene ningún efecto sobre el objeto del mismo nombre en el lado del servidor, y viceversa.

El ejemplo [nuxt-07] se obtiene inicialmente mediante una copia del ejemplo [nuxt-01]:

Image

  • en [2], vamos a añadir un complemento común al cliente y al servidor;
  • en [3], modificaremos ligeramente la página [index];

10.2. El complemento [common / main.js]

El complemento [common / main.js] se ejecuta tanto en el cliente como en el servidor: esto se debe a la siguiente configuración [nuxt.config.js]:


/*
   ** Plugins to load before mounting the App
   */
plugins: [{ src: '~/plugins/common/main.js' }],
  • línea 4: la ausencia de la propiedad [mode] hace que el complemento [~/plugins/common/main.js] se ejecute tanto en el cliente como en el servidor: primero en el servidor y después en el cliente;

Este complemento será el siguiente:


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

  // primer argumento
  const context = args[0]
  // claves del contexto
  dumpkeys(main + ', context', context)
  // la aplicación
  dumpkeys(main + ', context.app', context.app)
  // la ruta
  dumpkeys(main + ', context.route', context.route)
  console.log(main + ', context.route=', context.route)
  // el router
  dumpkeys(main + ', context.app.router', context.app.router)
  // el router.options.routes
  dumpkeys(main + ', context.app.router.options.routes', context.app.router.options.routes)
  console.log(main + ', context.app.router.options.routes=', context.app.router.options.routes)

  // segundo argumento
  const inject = args[1]
  console.log('inject=', typeof inject)
}

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íneas 31-39: la función [dumpkeys] enumera las propiedades del objeto pasado como segundo parámetro. Esta lista va precedida del mensaje pasado como primer parámetro;
  • línea 3: queremos saber cuántos argumentos recibe la función. Para ello, utilizamos la notación [...args], que tendrá como efecto colocar los parámetros efectivos de la función en la matriz [args]. Descubriremos que hay dos argumentos;
  • línea 5: se muestra quién ejecuta el código, si es el servidor o el cliente;
  • línea 6: el ejecutor del código, cliente o servidor;
  • línea 7: una cadena de caracteres constante utilizada en los registros;
  • línea 12: veremos que el primer argumento que recibe el plugin es el contexto del ejecutor;
  • línea 14: lista de claves del objeto [context];
  • línea 16: veremos que el objeto [context] tiene una propiedad [app] que representa la aplicación [nuxt];
  • línea 18: veremos que el objeto [context] tiene una propiedad [route] que representa la ruta actual del enrutador;
  • línea 21: veremos que el objeto [app] tiene una propiedad [router] que representa el enrutador;
  • línea 23: el objeto [router.options.routes] representa las diferentes rutas de la aplicación;
  • líneas 27-28: el segundo argumento del plugin es la función [inject] que hemos utilizado en el ejemplo [nuxt-06];

10.3. El complemento ejecutado por el servidor

Al ejecutarse, el servidor muestra lo siguiente:

[main server], process.server= true process.client= false
[main server], il y a 2 arguments
Liste des clés [[main server], context]
[
  'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios'
]
  • líneas 11-12: ya hemos tenido ocasión de utilizar las propiedades [base] y [env], cuyos valores proceden del archivo [nuxt.config.js];
  • línea 8: la propiedad [app] designa la aplicación [nuxt];
  • línea 18: la propiedad [route] indica la ruta actual del enrutador, es decir, la página que va a enviar el servidor;
  • línea 13: la solicitud HTTP del navegador del cliente;
  • línea 14: la respuesta HTTP del servidor;

La lista de propiedades de [context.app] es la siguiente:

Liste des clés [[main server], context.app]
[
  'router',
  'nuxt',
  'head',
  'render',
  'data',
  'beforeCreate',
  'created',
  'mounted',
  'watch',
  'computed',
  'methods',
  'components',
  'context',
   '$axios'
]
  • línea 3: la propiedad [router] nos da acceso al enrutador de la aplicación. Esto es importante en [nuxt], ya que el enrutador lo define el propio [nuxt] y no el desarrollador. Esta propiedad es un acceso que se concede al desarrollador para modificar el enrutador;

La lista de propiedades de [context.route] es la siguiente:

Liste des clés [[main server], context.route]
[
  'name',
  'meta',
  'path',
  'hash',
  'query',
  'params',
  'fullPath',
   'coincidente'
]

La ruta [context.route] al iniciar el servidor es la siguiente:

[main 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: {}
    }
  ]
}
  • línea 2: se observa que la siguiente página del servidor es [index] y que su ruta es [/] (línea 10);
  • línea 22: la propiedad [meta] permite añadir propiedades a las rutas;

Las propiedades del enrutador [context.app.router] del servidor son las siguientes:

Liste des clés [[main server], context.app.router]
[
  'app',
  'apps',
  'options',
  'beforeHooks',
  'resolveHooks',
  'afterHooks',
  'matcher',
  'fallback',
  'mode',
   'historial'
]

En la propiedad [context.app.router.options.routes] se encuentran las diferentes rutas de la aplicación:

Liste des clés [[main server], context.app.router.options.routes]
[
  '0',
  '1',
  '2'
]
[main server], context.app.router.options.routes= [
  {
    path: '/page1',
    component: [Function: _d7b6c762],
    name: 'page1'
  },
  {
    path: '/page2',
    component: [Function: _d79a9860],
    name: 'page2'
  },
  {
    path: '/',
    component: [Function: _31eaad9f],
    name: 'index'
  }
]

Por último, el segundo argumento:

inject= function

10.4. La página [index] del servidor

La página [index] es la siguiente:


<!-- página principal -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegación -->
    <Navigation slot="left" />
    <!-- mensaje-->
    <b-alert slot="right" show variant="warning">
      Home
    </b-alert>
  </Layout>
</template>

<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
  },
  data() {
    return {
      who: process.server ? 'server' : 'client'
    }
  },

  // ciclo de vida
  beforeCreate() {
    // cliente y servidor
    console.log('[home beforeCreate]')
  },
  created() {
    // cliente y servidor
    console.log('[home ' + this.who + ' created]')
    this.dumpkeys('[home ' + this.who + ' created], this.$nuxt', this.$nuxt)
    this.dumpkeys('[home ' + this.who + ' created], this.$nuxt.context', this.$nuxt.context)
  },
  beforeMount() {
    // solo cliente
    console.log('[home ' + this.who + ' beforeMount]')
  },
  mounted() {
    // solo cliente
    console.log('[home ' + this.who + ' mounted]')
  },
  methods: {
    dumpkeys(message, object) {
      // lista de claves de [object]
      const ligne = 'Liste des clés [' + message + ']'
      console.log(ligne)
      if (object) {
        console.log(Object.keys(object))
      }
    }
  }
}
</script>
  • línea 43: ya hemos visto que el contexto de una página se puede encontrar en [this.$nuxt.context];
  • línea 42: también se muestran las propiedades del objeto [this.$nuxt];

Al ejecutarse en el servidor, esta página genera los siguientes registros:

[home beforeCreate]
[home server created]
Liste des clés [[home server created], this.$nuxt]
[
  '_uid',
  '_isVue',
   '$options',
  '_renderProxy',
  '_self',
   '$parent',
   '$root',
   '$children',
   '$refs',
  '_watcher',
  '_inactive',
  '_directInactive',
  '_isMounted',
  '_isDestroyed',
  '_isBeingDestroyed',
  '_events',
  '_hasHookEvent',
  '_vnode',
  '_staticTrees',
   '$vnode',
   '$slots',
   '$scopedSlots',
  '_c',
   '$createElement',
   '$attrs',
   '$listeners',
  '_routerRoot',
  '_router',
  '_route',
  '_bv__modal',
  '_bv__toast',
  '_vueMeta',
  'nuxt',
  '_watchers',
  'refreshOnlineStatus',
  'refresh',
  'errorChanged',
  'setLayout',
  'loadLayout',
  '_data',
  'layoutName',
  'layout',
  'isOnline',
  '_computedWatchers',
  'isOffline',
  'error',
   'contexto'
]

Las propiedades del contexto del servidor en la página [index] son las siguientes:

Liste des clés [[home server created], this.$nuxt.context]
[
  'isStatic',
  'isDev',
  'isHMR',
  'app',
  'payload',
  'error',
  'base',
  'env',
  'req',
  'res',
  'ssrContext',
  'redirect',
  'beforeNuxtRender',
  'route',
  'next',
  '_redirected',
  '_errored',
  'params',
  'query',
   '$axios'
]

Son las mismas propiedades que las del objeto [context] del complemento.

10.5. El complemento ejecutado por el cliente

Una vez que el servidor ha enviado la página [index] al navegador del cliente, los scripts del cliente toman el control. A continuación, se ejecutará el complemento [main.js]. Estos son los registros:

[main server], process.server= false process.client= true
[main client], il y a 2 arguments
Liste des clés [[main client], context]
Array(17)0: "isStatic"1: "isDev"2: "isHMR"3: "app"4: "payload"5: "error"6: "base"7: "env"8: "redirect"9: "nuxtState"10: "route"11: "next"12: "_redirected"13: "_errored"14: "params"15: "query"16: "$axios"length: 17__proto__: Array(0)
Liste des clés [[main client], context.app]
Array(14)0: "router"1: "nuxt"2: "head"3: "render"4: "data"5: "beforeCreate"6: "created"7: "mounted"8: "watch"9: "computed"10: "methods"11: "components"12: "context"13: "$axios"length: 14__proto__: Array(0)
Liste des clés [[main client], context.route]
Array(8)0: "name"1: "meta"2: "path"3: "hash"4: "query"5: "params"6: "fullPath"7: "matched"length: 8__proto__: Array(0)
[main client], context.route= ObjectfullPath: "/"hash: ""matched: [{…}]meta: [{…}]name: "index"params: {}path: "/"query: {}__proto__: Object
Liste des clés [[main client], context.app.router]
Array(10)0: "app"1: "apps"2: "options"3: "beforeHooks"4: "resolveHooks"5: "afterHooks"6: "matcher"7: "fallback"8: "mode"9: "history"length: 10__proto__: Array(0)
Liste des clés [[main client], context.app.router.options.routes]
Array(3)0: "0"1: "1"2: "2"length: 3__proto__: Array(0)
[main client], context.app.router.options.routes= Array(3)0: {path: "/page1", name: "page1", component: ƒ}1: {path: "/page2", name: "page2", component: ƒ}2: {path: "/", name: "index", component: ƒ}length: 3__proto__: Array(0)
inject= function

Encontramos propiedades similares a las que se observan en el lado del servidor, aunque algunas han desaparecido y otras han aparecido. Así, en la línea 4, no aparecen las propiedades [req, res], que correspondían a las solicitudes HTTP del navegador del cliente y a la respuesta HTTP del servidor.

10.6. La página [index] del cliente

La página [index] del cliente genera los siguientes registros:

1
2
3
4
5
6
7
8
[home beforeCreate]
[home client created]
Liste des clés [[home client created], this.$nuxt]
(51) ["_uid", "_isVue", "$options", "_renderProxy", "_self", "$parent", "$root", "$children", "$refs", "_watcher", "_inactive", "_directInactive", "_isMounted", "_isDestroyed", "_isBeingDestroyed", "_events", "_hasHookEvent", "_vnode", "_staticTrees", "$vnode", "$slots", "$scopedSlots", "_c", "$createElement", "$attrs", "$listeners", "_routerRoot", "_router", "_route", "_bv__modal", "_bv__toast", "_vueMeta", "nuxt", "_watchers", "refreshOnlineStatus", "refresh", "errorChanged", "setLayout", "loadLayout", "_data", "layoutName", "layout", "isOnline", "_computedWatchers", "isOffline", "error", "context", "_name", "setTransitions", "$loading", "$el"]
Liste des clés [[home client created], this.$nuxt.context]
(17) ["isStatic", "isDev", "isHMR", "app", "payload", "error", "base", "env", "redirect", "nuxtState", "route", "next", "_redirected", "_errored", "params", "query", "$axios"]
[home client beforeMount]
[home client mounted]
  • línea 4: las propiedades del objeto [this.$nuxt]. Se trata de un objeto complejo con 51 propiedades;
  • línea 6: las propiedades del objeto [this.$nuxt.context]. Se observan las mismas propiedades que en el objeto [context] del complemento del cliente;