Guía de inicio con Nuxt.js para renderizado del lado del servidor

El desarrollo tradicional de aplicaciones de una sola página (SPA) con Vue.js a menudo plantea desafíos para la optimización de motores de búsqueda (SEO). Nuxt.js es un framework que facilita la creación de aplicaciones con renderizado del lado del servidor (SSR), mejorando significativamente la visibilidad en buscadores.

Instalación inicial

npx create-nuxt-app nombre-del-proyecto

Gestión de recursos estáticos

Directorio assets

Los archivos aquí contenidos son procesados por Webpack. Para usarlos en estilos CSS:

/* En un archivo CSS */
.fondo {
  background: url("~assets/imagen-fondo.svg");
}

En componentes Vue:

<img src="~/assets/logo.png">

Directorio static

Contiene archivos que no requieren procesamiento por Webpack. Se acceden mediante ruta relativa:

<img src="../static/imagen-publica.jpg"/>

Sistema de plantillas y páginas

Plantilla por defecto

Archivo layouts/default.vue:

<template>
  <div class="contenedor-principal">
    <slot/>
  </div>
</template>

Plantillas personalizadas

1. Crear archivo layouts/plantilla-especial.vue:

<template>
  <div class="estructura-especial">
    <header>Encabezado personalizado</header>
    <main><slot/></main>
    <footer>Pie de página especial</footer>
  </div>
</template>

2. Asignar en una página:

// En pages/pagina-especial.vue
export default {
  layout: 'plantilla-especial'
}

Manejo de errores

Archivo layouts/error.vue:

<template>
  <div class="pagina-error">
    <h1 v-if="error.statusCode === 404">Recurso no encontrado</h1>
    <h1 v-else>Ha ocurrido un error inesperado</h1>
    <nuxt-link to="/">Volver al inicio</nuxt-link>
  </div>
</template>

<script>
export default {
  props: ['error']
}
</script>

Sistema de plugins

Configuración de plugins globales

1. Crear archivo plugins/mi-plugin.js:

import Vue from 'vue'

Vue.prototype.$funcionGlobal = (mensaje) => {
  console.log(`Mensaje del plugin: ${mensaje}`)
}

2. Registrar en nuxt.config.js:

export default {
  plugins: ['~/plugins/mi-plugin.js']
}

3. Uso en componentes:

this.$funcionGlobal('Funcionando correctamente')

Inyección en el contexto de la aplicación

Archivo plugins/inyeccion-contexto.js:

export default ({ app }, inject) => {
  const funcionUtil = (parametro) => {
    return `Procesado: ${parametro}`
  }
  
  inject('utilidad', funcionUtil)
}

Configuración de rutas

Nuxt genera automáticamente las rutas basándose en la estructura del directorio pages.

Rutas dinámicas

Estructura de ejemplo:

pages/
├── articulos/
│   ├── _slug.vue
│   └── index.vue
├── usuarios/
│   └── _identificador.vue
└── index.vue

Configuración equivalente de Vue Router:

const rutas = [
  {
    nombre: 'inicio',
    ruta: '/',
    componente: 'pages/index.vue'
  },
  {
    nombre: 'usuarios-perfil',
    ruta: '/usuarios/:identificador?',
    componente: 'pages/usuarios/_identificador.vue'
  },
  {
    nombre: 'articulos-slug',
    ruta: '/articulos/:slug',
    componente: 'pages/articulos/_slug.vue'
  }
]

Validación de parámetros:

// En pages/usuarios/_identificador.vue
export default {
  validate({ params }) {
    return /^\d+$/.test(params.identificador)
  }
}

Middleware de aplicación

Los middlewares se ejecutan antes de la renderización de páginas.

Archivo middleware/registro-accesos.js:

export default function ({ route, req }) {
  const datos = {
    ruta: route.fullPath,
    timestamp: new Date().toISOString(),
    userAgent: process.server ? req.headers['user-agent'] : navigator.userAgent
  }
  
  // Ejemplo: enviar datos a un servicio de análisis
  console.log('Datos de acceso:', datos)
}

Configuración global en nuxt.config.js:

export default {
  router: {
    middleware: 'registro-accesos'
  }
}

O en una página específica:

export default {
  middleware: ['registro-accesos']
}

Gestión de estado con Vuex

Configuración modular

Estructura de directorios:

store/
├── carrito/
│   ├── actions.js
│   ├── getters.js
│   ├── mutations.js
│   └── state.js
└── usuario.js

Uso en componentes:

import { mapGetters, mapActions } from 'vuex'

export default {
  computed: {
    ...mapGetters({
      productos: 'carrito/obtenerProductos',
      perfil: 'usuario/perfilCompleto'
    })
  },
  methods: {
    ...mapActions({
      agregarProducto: 'carrito/agregarItem',
      actualizarPerfil: 'usuario/cambiarDatos'
    })
  }
}

Obtención de datos asíncronos

El método asyncData se ejecuta antes de la inicialización del componente en el servidor.

export default {
  async asyncData({ params, $axios, error }) {
    try {
      const articulo = await $axios.$get(`/api/articulos/${params.slug}`)
      return { contenido: articulo }
    } catch (e) {
      error({ statusCode: 404, mensaje: 'Artículo no encontrado' })
    }
  }
}

Para observar cambios en parámetros de consulta:

export default {
  watchQuery: ['pagina', 'orden']
}

Animaciones de transición

Configuración global

/* assets/estilos-transiciones.css */
.pagina-enter-active,
.pagina-leave-active {
  transition: opacity 0.3s ease;
}

.pagina-enter-from,
.pagina-leave-to {
  opacity: 0;
}

Registrra en nuxt.config.js:

export default {
  css: ['~/assets/estilos-transiciones.css']
}

Transiciones específicas por página

/* assets/animaciones.css */
.deslizar-enter-active {
  animation: deslizar-entrada 0.4s;
}

.deslizar-leave-active {
  animation: deslizar-salida 0.3s;
}

@keyframes deslizar-entrada {
  from { transform: translateX(-20px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

@keyframes deslizar-salida {
  from { transform: translateX(0); opacity: 1; }
  to { transform: translateX(20px); opacity: 0; }
}

Aplicación en página:

export default {
  transition: {
    name: 'deslizar',
    mode: 'out-in'
  }
}

Indicador de carga personalizado

Crear componente components/IndicadorCarga.vue:

<template>
  <div v-if="cargando" class="indicador-carga">
    <div class="spinner"></div>
    <p>Cargando contenido...</p>
  </div>
</template>

<script>
export default {
  data: () => ({ cargando: false }),
  methods: {
    iniciar() { this.cargando = true },
    finalizar() { this.cargando = false }
  }
}
</script>

Configuración en nuxt.config.js:

export default {
  loading: '~/components/IndicadorCarga.vue'
}

Variables de entorno y entorno de ejecución

Detección del entorno de ejecución:

// Determinar si estamos en servidor, cliente o modo estático
const entorno = process.static ? 'generador-estatico' : 
               (process.server ? 'servidor' : 'cliente')

// Ejemplo de uso condicional
if (process.server) {
  // Código exclusivo para servidor
}

if (process.client) {
  // Código exclusivo para cliente
}

Etiquetas: nuxt.js ssr vue.js renderizado-servidor spa-seo

Publicado el 6-11 22:33