└── README.md /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | **Tutorial de NUXT** 4 | ==================== 5 | > Tutorial de [Nuxt](https://nuxtjs.org) en español 6 | 7 | Índice 8 | -------- 9 | 1. [¿Qué es el SSR o aplicaciones universales?](#isomorfica) 10 | 1. [Ventajas y desventajas](#isomorfica-ventajas) 11 | 2. [Alternativas](#isomorfica-alternativas) 12 | 2. [¿Qué es Nuxt?](#que-nuxt) 13 | 1. [¿Cómo funciona?](#que-nuxt-funciona) 14 | 2. [Características](#que-nuxt-caracteristicas) 15 | 3. [Ciclo de trabajo](#que-nuxt-ciclo) 16 | 4. [Tipos de renderizado](#que-nuxt-renderizado) 17 | 3. [Guía de inicio](#guide) 18 | 1. [Instalación](#guide-instalacion) 19 | 2. [Estructura del directorio](#guide-directorio) 20 | 3. [Jerarquía de vistas](#guide-jerarquia) 21 | 3. [Routing](#guide-routing) 22 | 4. [Store](#guide-store) 23 | 5. [Plugins](#guide-plugin) 24 | 6. [Assets](#guide-assets) 25 | 7. [Despliegue](#guide-despliegue) 26 | 4. [Ejemplo](#ejemplo) 27 | 5. [Ejemplo AWS Serverless](#ejemplo-aws) 28 | 29 | # ¿Qué es el SSR o aplicaciones universales? 30 | Cualquier framework de JavaScript (*Vue, React, Angular, …*), generan componentes que por defecto producen y manipulan DOM en el navegador como salida. El ***Server Side Rendering*** o SSR, nos ofrece la posibilidad de convertir los mismos componentes en cadenas de HTML en el servidor, enviarlos directamente al navegador y generar una aplicación en el navegador del cliente. 31 | 32 | Una aplicación JavaScript **isomórficas** o  **universal**, es aquella en la que su código puede ser interpretado, tanto en la parte de cliente (navegador) como en la parte de servidor (ex. [NodeJS](https://nodejs.org)). 33 | > Según [Kyle Simpson](https://github.com/getify/You-Dont-Know-JS), JavaScript no es exactamente un lenguaje "dínamico" o "interpretado", sino que se trata de un lenguage compilado. Éste no se compila con mucha antelación, ni los resultados de la compilación son portables entre varios sistemas distribuidos. [Más info](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch1.md#compiler-theory) 34 | 35 | En el caso de Nuxt, su principal ventaja es el renderizado UI (*interfaces de usuario*) abstrayendo al usuario la complejidad de saber si su código se está compilando en cliente o en servidor. 36 | 37 | ## Ventajas y desventajas 38 | ### 🙂 Ventajas 39 | 40 | En comparación con un SPA tradicional (aplicación de una sola página), la ventaja de la SSR radica principalmente en: 41 | 42 | - **Mejor SEO**, ya que los rastreadores de los motores de búsqueda verán directamente la página completamente renderizada. 43 | 44 | A partir de ahora motores de búsqueda como Google pueden indexar aplicaciones de JavaScript síncronas sin problemas. 45 | 46 | ¿Qué quiere decir aplicaciones síncronas?🤔 47 | 48 | Si la aplicación comienza con un proceso de carga de datos a través de una petición Ajax, el crawler no esperará a que termine. Esto significa que si tiene contenido obtenido de manera asíncrona en páginas donde SEO es importante, es muy posible que se necesite SSR. 49 | Aunque Google es capaz de hacer scraping en las aplicaciones SPA (*más info [aquí](https://goralewicz.com/blog/javascript-seo-experiment/)*). 50 | 51 | > “Times have changed. Today, as long as you're not blocking Googlebot from crawling your JavaScript or CSS files, [we are generally able to render and understand your web pages like modern browsers.](https://webmasters.googleblog.com/2014/05/understanding-web-pages-better.html) To reflect this improvement, we recently [updated our technical Webmaster Guidelines](https://webmasters.googleblog.com/2014/10/updating-our-technical-webmaster.html) to recommend against disallowing Googlebot from crawling your site's CSS or JS files.” 52 | 53 | - **Tiempo de carga de contenido más rápido**, especialmente en Internet lento o dispositivos lentos. La generación de HTML en el servidor no necesita esperar hasta que se haya descargado y ejecutado todo el JavaScript para que se muestre, de modo que su usuario verá una página completamente renderizada antes. En general, esto se traduce en una mejor experiencia del usuario. 54 | 55 | ### 🙁 Desventajas 56 | 57 | También hay algunos inconvenientes que considerar al usar SSR: 58 | 59 | - **Restricciones de desarrollo**. El código específico del navegador solo se puede usar dentro de ciertas etapas del ciclo de vida del component; algunas bibliotecas externas pueden necesitar un tratamiento especial para poder ejecutarse en una aplicación procesada por el servidor. 60 | 61 | - **Requisitos de instalación y despliegue más complicados**. A diferencia de un SPA totalmente estática que se puede implementar en cualquier servidor de archivos estático, una aplicación procesada por servidor requiere un entorno donde se puede ejecutar un servidor Node.js. 62 | 63 | - **Más carga en el servidor**. Es obvio que renderizar una aplicación completa en Node.js va a requerir más CPU que solo servir archivos estáticos, por lo que si espera mucho tráfico, hay que preparar el entorno para la carga del servidor correspondiente y manejar eficientemente las estrategias de almacenamiento en caché. 64 | 65 | ## Alternativas 66 | 67 | Si quieres conseguir las ventajas sobre SEO que ofrece SSR pero sin todas las desventajas que éste ofrece, entonces probablemente quieras usar otra herramienta en su lugar, esta herramienta se llama ***Prerendering***. 68 | 69 | El ***Prerender*** en lugar de utilizar un servidor web para compilar HTML sobre la marcha, simplemente genera archivos HTML estáticos para rutas específicas en tiempo de compilación. La ventaja de usar *prerender* es que la configuración inicial es mucho más simple y nos permite mantener nuestro frontal como un sitio totalmente estático. 70 | 71 | Si estás utilizando [**webpack**](https://webpack.github.io/), puedes agregar fácilmente *prerendering* con [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin). 72 | 73 | # ¿Qué es Nuxt? 74 | 75 | > The 25th of October 2016, the team behind [zeit.co](https://zeit.co/), announced [Next.js](https://zeit.co/blog/next), a framework for server-rendered React applications. A few hours after the announcement, the idea of creating server-rendered Vue.js applications the same way as Next.js was obvious: **Nuxt.js** was born. 76 | 77 | 78 | 📚 Nuxt.js es un *framework* que nos permite crear aplicaciones universales con [Vue.js](https://vuejs.org/). Nos permite crear componentes UI si tener que concentrarse en las distribuciones de cliente y servidor. 79 | 80 | Nuxt nos proporciona una capa de abstracción por encima de [Vue Server Renderer](https://ssr.vuejs.org/en/), haciéndonos más fácil y rápido el proceso de configuración y el desarrollo de aplicaciones isomórficas. 81 | 82 | ## ¿Cómo funciona? 83 |

84 | 85 | Nuxt.js usa el siguiente stack tecnológico para la creación de aplicaciones: 86 | 87 | - **[Vue 2](https://vuejs.org/)** 88 | 89 | Framework progresivo para la generación de SPA (*single page applications*). 90 | 91 | ¿Qué quiere decir progresivo?🤔 92 | 93 | Quiere decir que VUE está diseñado para ser adoptado incrementalmente, desde pequeñas aplicaciones simples hasta aplicaciones SPA más elaboradas. 94 | 95 | - **[Vue Router](https://router.vuejs.org/)** 96 | 97 | Nos da el servicio de *routing* para el cambio de vistas en la aplicación. 98 | - **[Vuex](https://vuex.vuejs.org/)** 99 | 100 | Gestión de estados centralizados de Vue.js 101 | - **[Vue Server Renderer](https://ssr.vuejs.org)** 102 | 103 | Librería que nos permite ejecutar código en servidor y cliente. 104 | - **[vue-meta](https://github.com/declandewet/vue-meta)** 105 | 106 | Librería que nos permite gestionar la meta información de la aplicación desde los componentes de Vue + SSR 107 | 108 | El peso total del framework es de 57kB min+gzip (53kB con Vuex). 109 | 110 | En el proceso de desarrollo Nuxt utiliza webpack con **vue-loader** y **babel-loader** para la generación de bundles. 111 | 112 | ## Características 113 | 114 | - **Escritura de código en ficheros VUE** (*.vue) 115 | 116 | - **Separación automática de código** (*Code Splitting*) 117 | 118 | ¿Qué quiere decir esto? 119 | 120 | Es una característica muy potente que nos ofrece **webpack** que consiste en dividir el código en varios paquetes, que luego pueden cargarse bajo demanda o en paralelo. 121 | 122 | - **Renderizado en servidor** 123 | 124 | Las vistas de la aplicación serán renderizadas en el servidor. Todos los cambios dinámicos son interceptados por Vue en cliente. Nuxt nos hace el SSR transparente. 125 | 126 | - **Sistema de routing con sincronismo de datos** 127 | 128 | Nuxt configurará el routing de la aplicación dependiendo de la estructura de carpetas que hayamos creado, además nos proporciona herramientas para la carga síncrona de datos y vistas en servidor. 129 | 130 | - **Servicio de ficheros estáticos** 131 | 132 | Ofrece capacidad de servir ficheros estáticos desde servidor. 133 | 134 | - **Transpilación de ES6/ES7** 135 | 136 | Webpack junto con [Babel](https://babeljs.io) nos ofrece la posibilidad de transpilar el código escrito en un estándar moderno a código que el navegador pueda entender. 137 | 138 | Todos conocemos las ventajas de ES6 pero cuáles son las novedades de ES7 (ES2016): 139 | - Object Rest / Spread Properties 140 | 141 | Object Rest 142 | ```javascript 143 | const {a, b, c, ...x} = {a: 1, b: 2, c: 3, x: 4, y: 5, z: 6}; 144 | 145 | console.log(a); // 1 146 | console.log(b); // 2 147 | console.log(c); // 3 148 | console.log(x); // { x: 4, y: 5, z: 6 } 149 | ``` 150 | 151 | Spread properties 152 | ```javascript 153 | const a = 1, b = 2, c = 3 154 | const x = { x: 4, y: 5, z: 6 } 155 | const obj = { a, b, c, ...x } 156 | 157 | console.log(obj) //{a: 1, b: 2, c: 3, x: 4, y: 5, z: 6}; 158 | ``` 159 | - Observables 160 | 161 | Los observables son una nueva herramienta que nos permitirá adentrarnos en la programación reactiva, es decir, programar con flujos de datos (streams) asíncronos. 162 | ```javascript 163 | const resize = new Observable((o) => { 164 | window.addEventListener("resize", () => { 165 | let height = window.innerHeight 166 | let width = window.innerWidth 167 | o.next({ height, width }) 168 | }) 169 | }) 170 | ``` 171 | 172 | - Async Functions 173 | 174 | Nueva manera para resolver la asincronía en Javascript. 175 | ```javascript 176 | async function createEmployeeWorkflow() { 177 | try { 178 | let employee = await createEmployee() 179 | await saveEmployee(employee) 180 | } catch (err) { 181 | throw new Error(err) 182 | } 183 | } 184 | ``` 185 | 186 | - **Bundling y minificación de JS & CSS** 187 | 188 | - **Pre-procesador: Sass, Less, Stylus, etc.** 189 | 190 | - **Manejo de los elementos de la etiqueta \ (, \<meta>, etc.)** 191 | 192 | Nos permite cambiar la meta información desde cualquier componente Vue 193 | 194 | - **Reemplazo de módulos de desarrollo en caliente** 195 | 196 | Con esta opción sólo recargamos aquellos módulos donde hemos realizado cambios, evitando así cargar toda la página para mostrar los cambios de un único componente. Evitando así pérdida de tiempo en el desarrollo. 197 | - **HTTP/2 push headers ready** 198 | 199 | Con esta funcionalidad, el servidor nos enviará los assets antes de que el navegador pregunte por ellos. 200 | 201 | - **Entesión de Nuxt con arquitecturas modulares** 202 | 203 | Podemos extender la funcionalidad de Nuxt con arquitecturas modulares. 204 | 205 | 206 | ## <a id="que-nuxt-ciclo"></a>Ciclo de trabajo 207 | 208 | Este esquema muestra que hace Nuxt.js cuando se llama al servidor o cuando el usuario navega a través de la aplicación usando <nuxt-link>: 209 | <p align="center"><img align="center" src="https://nuxtjs.org/nuxt-schema.png"/></p> 210 | 211 | 1. Un usuario realiza una petición de una ruta determinada a servidor. 212 | 2. El servidor ejecuta la acción nuxtServerInit del store principal si la tiene implementada. Esta acción nos permite cargar datos iniciales (*prefetching* de datos globales). 213 | 3. Se ejecutan todos aquellos middlewares que se encuentren en el fichero de configuración nuxt.config.js y los relacionados con el layout, la página raíz y las páginas hijas coincidentes que se hayan implementado. 214 | 4. Si existe un validador, se ejecuta. Si se resuelve con un true se sigue el proceso, si no se devuelve un 404 😭. 215 | 5. Se obtienen aquellos datos de la página para que sean renderizados. 216 | 6. Se renderiza en servidor y se sirve al usuario. 217 | 7. Si el usuario navega por la aplicación hacia otra ruta, se repite el ciclo. 218 | 219 | > *Info sacada del blog ["El abismo de null"](https://elabismodenull.wordpress.com/2017/07/25/vuejs-aplicaciones-universales-con-nuxt/)* 220 | 221 | ## <a id="que-nuxt-renderizado"></a>Tipos de renderizado 222 | 223 | Nuxt.js puede configurarse de tres formas diferentes para generar aplicaciones: 224 | - **Server Rendered** (*Universal SSR*) 225 | 226 | Podemos usar Nuxt.js como framework para manejar todo el renderizado UI de nuestro proyecto. 227 | 228 | - **Single Page Applications** (*SPA*) 229 | 230 | Si por alguna razón no necesitamos el renderizado en servidor, podemos habilitar la opción de SPA y usar Nuxt como si trabajáramos con Vue. 231 | 232 | - **Static Generated** (*Pre Rendering*) 233 | 234 | Una de las grandes innovaciones de Nuxt es esta funcionalidad, lo que nos permite generar los estáticos de nuestro proyecto y poder alojarlos en algún CDN (*content delivery network*) con toda la mejora de SEO que nos proporciona Nuxt. 235 | 236 | # <a id="guide"></a>Guía de inicio 237 | ## <a id="guide-instalacion"></a>Instalación 238 | Podemos comenzar a instalar nuestro proyecto Nuxt desde un template ya creado, este template ya nos dará todo el scaffolding básico necesario para crear nuestra aplicación. Tan sólo debemos de tener [vue-cli](https://github.com/vuejs/vue-cli) instalado en nuestra máquina. 239 | 240 | > Prerequisitos: Tener instalado Node.js y npm 241 | 242 | 1. Instalamos vue-cli: 243 | 244 | ``` bash 245 | $ npm install -g vue-cli 246 | ``` 247 | 248 | 2. Una vez instalado vue-cli comenzamos con la instalación del template predefinido: 249 | 250 | ``` bash 251 | $ vue init nuxt-community/starter-template <nombre-proyecto> 252 | ``` 253 | 254 | Si queremos que nuestro proyecto ya tenga una librería de componentes acoplada en el template de Nuxt, como es el caso de **[Vuetify](https://vuetifyjs.com/)**, debemos hacer: 255 | 256 | ``` bash 257 | $ vue init vuetifyjs/nuxt <nombre-proyecto> 258 | ``` 259 | 260 | 3. Una vez instalado el template, comenzamos a instalar las dependencias: 261 | 262 | ``` bash 263 | $ cd <nombre-proyecto> 264 | $ npm install 265 | ``` 266 | 267 | 4. Por último lanzamos el proyecto en modo desarrollo: 268 | 269 | ``` bash 270 | $ npm run dev 271 | ``` 272 | 273 | La aplicación estará ejecutándose 💻 en [http://localhost:3000](http://localhost:3000) 274 | 275 | ## <a id="guide-directorio"></a>Estructura del directorio 276 | 277 | El *scaffolding* del template de Nuxt nos genera un total de 8 carpetas más 1 archivo de configuración junto con el archivo *package.json*: 278 | ### Carpetas 279 | 280 | 1. La carpeta de ***assets*** 281 | 282 | La carpeta de assets contiene los archivos no compilados como *Less, Sass o JavaScript*. 283 | 284 | 2. La carpeta de **componentes** 285 | 286 | La carpeta de componentes contiene los componentes de Vue.js. Nuxt.js no sobrecarga el método *data* en estos componentes. 287 | 288 | 3. La carpeta de ***layouts*** 289 | 290 | La carpeta de *layouts* contiene todos los *layouts* de la aplicación. 291 | 292 | ###### *Este directorio no puede ser renombrado.* 293 | 294 | 4. La carpeta de ***middlewares*** 295 | 296 | La carpeta de *middleware* contiene los middlewares de la aplicación. Un middleware nos permite definir funciones personalizadas que se pueden ejecutar antes de visualizar una página o un grupo de páginas (*layouts*). 297 | 298 | 5. La carpeta de **páginas** 299 | 300 | La carpeta de páginas contiene las vistas de aplicaciones y sus rutas. El framework lee todos los archivos .vue dentro de este directorio y crea el enrutador de la aplicación. 301 | 302 | ###### *Este directorio no puede ser renombrado.* 303 | 304 | 6. La carpeta de ***plugins*** 305 | 306 | La carpeta de *plugins* contiene los complementos de Javascript que se desean ejecutar antes de crear una instancia de la aplicación raíz Vue.js. 307 | 308 | 7. La carpeta de **estáticos** 309 | 310 | La carpeta de estáticos contiene tus archivos estáticos. Cada archivo dentro de este directorio está mapeado a /. 311 | 312 | > Ejemplo: /static/robots.txt se asigna como /robots.txt 🤖 313 | 314 | ###### *Este directorio no puede ser renombrado.* 315 | 316 | 8. La carpeta de los ***stores*** 317 | 318 | La carpeta de la *stores* contiene sus archivos de almacenes Vuex 🏭. 319 | 320 | ###### *Este directorio no puede ser renombrado.* 321 | 322 | ### Archivos de configuración 323 | 324 | 1. El archivo ***nuxt.config.js*** 325 | 326 | El archivo nuxt.config.js 🛠 contiene la configuración personalizada de Nuxt.js. 327 | 328 | ###### *Este archivo no puede ser renombrado.* 329 | 330 | 2. El archivo ***package.json*** 331 | 332 | El archivo package.json contiene las dependencias y scripts de la aplicación. 333 | 334 | ###### *Este archivo no puede ser renombrado.* 335 | 336 | ## <a id="guide-jerarquia"></a>Jerarquía de vistas 337 | <p align="center"><img align="center" src="https://nuxtjs.org/nuxt-views-schema.png"/></p> 338 | 339 | En Nuxt.js existen tres niveles de jerarquía de vistas: 340 | - Document 341 | - Layout 342 | - Page 343 | 344 | ### Document 345 | 346 | Existe sólo un único *Document* del que parten el resto de vistas, este es el archivo `.nuxt/views/app.template.html`. 347 | 348 | Podremos sobrecargar la funcionalidad de este documento añadiendo un archivo `app.html` situado en el directorio raíz del proyecto. 349 | 350 | ### Layout 351 | 352 | Nuxt.js nos permite ampliar el *layout* principal o crear nuevos *layouts* personalizados insertándolos en la carpeta `layouts` de nuestro proyecto. 353 | 354 | ¿Qué es un *layout*?🤔 355 | 356 | La layout o plantilla es un esquema de la distribución de los elementos dentro de una página web. Se compone de una serie de bloques de ciertas dimensiones en los que se colocará el contenido. 357 | 358 | 1. **Layout por defecto** 359 | 360 | Podemos ampliar la funcionalidad del *layout* principal agregando o modificando el archivo `layouts/default.vue`. 361 | 362 | Debemos asegurarnos de incorporar el componente `<nuxt />` al crear un *layout* para mostrar el componente de la página. 363 | 364 | 2. **Página de error** 365 | 366 | Al igual que el *layout* por defecto tambien podemos personalizar la página de error añadiendo o modificando el archivo `layouts/error.vue`. 367 | 368 | 3. **Nuevos *layouts*** 369 | 370 | Podemos incluir nuevas plantillas de elementos. Cada archivo añadido en el directorio de *layouts* creará un *layout* personalizado y accesible con la propiedad *layout* al resto de páginas. 371 | 372 | Al igual que en el layout por defecto, no debemos olvidar el `<nuxt />` para mostrar las diferentes páginas que tengan asociado este nuevo layout. 373 | 374 | ### Page 375 | 376 | Cada componente de tipo página es un componente de Vue en el que Nuxt.js añade funcionalidad especial para hacer el desarrollo de la aplicación universal lo más fácil posible 377 | 378 | ATRIBUTO | DESCRIPCIÓN 379 | -------- | ----------- 380 | asyncData | El atributo más importante, puede ser una propiedad asíncrona y recibe el contexto de la aplicación como argumento. Se usa para conseguir datos y renderizarlos en servidor sin usar un *store*. Esta propiedad se llama cada vez, antes de cargar el componente. 381 | fetch | Esta propiedad se usa para completar el *store* antes de renderizar la página. 382 | head | Sete Meta Tags específicos para la página actual. 383 | layout | Especifica el *layout* al que corresponde la página. 384 | transition | Nombre de la animación de transición que usa el componente de página. 385 | scrollToTop | Booleano, para hacer scroll al inicio de la página antes de renderizarla. 386 | validate | Función validadora usada para rutas dinámicas. 387 | middleware | Uso de un middleware para la página, este middleware se llamara antes de renderizar la página. 388 | 389 | ## <a id="guide-routing"></a>Routing 390 | 391 | Nuxt.js genera automáticamente la configuración de `vue-router` basándose en la estructura en árbol de los archivos del directorio `pages`. 392 | 393 | Existen 4 tipos de enrutamiento: 394 | 395 | ### 1. Rutas básicas 396 | 397 | El árbol de archivos: 398 | ``` 399 | pages/ 400 | --| user/ 401 | -----| index.vue 402 | -----| one.vue 403 | --| index.vue 404 | ``` 405 | 406 | genera la siguiente configuración: 407 | 408 | ```javascript 409 | router: { 410 | routes: [ 411 | { 412 | name: 'index', 413 | path: '/', 414 | component: 'pages/index.vue' 415 | }, 416 | { 417 | name: 'user', 418 | path: '/user', 419 | component: 'pages/user/index.vue' 420 | }, 421 | { 422 | name: 'user-one', 423 | path: '/user/one', 424 | component: 'pages/user/one.vue' 425 | } 426 | ] 427 | } 428 | ``` 429 | 430 | ### 2. Rutas dinámicas 431 | 432 | Para definir una ruta dinámica con un parámetro, necesitamos definir un **archivo *.vue* o un directorio subrayado como prefijo**. 433 | 434 | El árbol de archivos: 435 | ``` 436 | pages/ 437 | --| _slug/ 438 | -----| comments.vue 439 | -----| index.vue 440 | --| users/ 441 | -----| _id.vue 442 | --| index.vue 443 | ``` 444 | 445 | genera la siguiente configuración: 446 | 447 | ```javasacript 448 | router: { 449 | routes: [ 450 | { 451 | name: 'index', 452 | path: '/', 453 | component: 'pages/index.vue' 454 | }, 455 | { 456 | name: 'users-id', 457 | path: '/users/:id?', 458 | component: 'pages/users/_id.vue' 459 | }, 460 | { 461 | name: 'slug', 462 | path: '/:slug', 463 | component: 'pages/_slug/index.vue' 464 | }, 465 | { 466 | name: 'slug-comments', 467 | path: '/:slug/comments', 468 | component: 'pages/_slug/comments.vue' 469 | } 470 | ] 471 | } 472 | ``` 473 | 474 | Como se puede ver, la ruta `users-id` tiene la variable `:id?`opcional, si queremos que sea obligatoria, debemos crear un archivo `index.vue` en el directorio `users/_id`. 475 | 476 | ##### Función validadora de parámetros 477 | Nuxt.js nos permite añadir un método de aprobación dentro de nuestro componente de ruta dinámica. 478 | 479 | ### 3. Rutas anidadas 480 | 481 | Nuxt.js nos permite crear rutas anidadas usando las rutas hijas de `vue-router`. 482 | Para definir el componente padre de una ruta anidad, necesitamos crear un archivo `.vue` con el mismo nombre que el directorio que contenga las vistas hijas. 483 | 484 | ‼️**Importante** no olvidar incluir el componente `<nuxt-child/>` dentro del componente padre (archivo `.vue`) 485 | 486 | El árbol de archivos: 487 | ``` 488 | pages/ 489 | --| users/ 490 | -----| _id.vue 491 | -----| index.vue 492 | --| users.vue 493 | ``` 494 | 495 | genera la siguiente configuración: 496 | 497 | ```javascript 498 | router: { 499 | routes: [ 500 | { 501 | path: '/users', 502 | component: 'pages/users.vue', 503 | children: [ 504 | { 505 | path: '', 506 | component: 'pages/users/index.vue', 507 | name: 'users' 508 | }, 509 | { 510 | path: ':id', 511 | component: 'pages/users/_id.vue', 512 | name: 'users-id' 513 | } 514 | ] 515 | } 516 | ] 517 | } 518 | ``` 519 | 520 | ### 4. Rutas anidadas dinámicas 521 | 522 | Este escenario no suele darse mucho, pero sería posible teniendo vistas hijas dinámicas dentro de vistas dinámicas padre. 523 | 524 | El árbol de archivos: 525 | ``` 526 | pages/ 527 | --| _category/ 528 | -----| _subCategory/ 529 | --------| _id.vue 530 | --------| index.vue 531 | -----| _subCategory.vue 532 | -----| index.vue 533 | --| _category.vue 534 | --| index.vue 535 | ``` 536 | 537 | genera la siguiente configuración: 538 | 539 | ```javascript 540 | router: { 541 | routes: [ 542 | { 543 | path: '/', 544 | component: 'pages/index.vue', 545 | name: 'index' 546 | }, 547 | { 548 | path: '/:category', 549 | component: 'pages/_category.vue', 550 | children: [ 551 | { 552 | path: '', 553 | component: 'pages/_category/index.vue', 554 | name: 'category' 555 | }, 556 | { 557 | path: ':subCategory', 558 | component: 'pages/_category/_subCategory.vue', 559 | children: [ 560 | { 561 | path: '', 562 | component: 'pages/_category/_subCategory/index.vue', 563 | name: 'category-subCategory' 564 | }, 565 | { 566 | path: ':id', 567 | component: 'pages/_category/_subCategory/_id.vue', 568 | name: 'category-subCategory-id' 569 | } 570 | ] 571 | } 572 | ] 573 | } 574 | ] 575 | } 576 | ``` 577 | 578 | #### Transiciones 579 | 580 | Nuxt.js nos permite usar el componente `<transition>` para dejarnos crear diferentes animaciones de transición entre rutas. 581 | 582 | #### Middleware 583 | 584 | Los middlewares nos dejan definir funciones personalizadas que pueden ser ejecutadas antes de renderizar una página o un grupo de ellas. 585 | Cada middleware estará situado dentro del directorio `middleware/`, el nombre del archivos será el nombre del middleware. 586 | 587 | ## <a id="guide-store"></a>Store 588 | 589 | Para el manejo de estados usaremos Vuex, Nuxt.js implementa Vuex en su core. 590 | 591 | ### Activar Store 592 | 593 | Para activar Vuex simplemente debe de existir la carpeta `store`dentro del directorio del proyecto, si no existe esta carpeta, entonces no se importa la librería Vuex. 594 | 595 | ### Formas de crear *stores* 596 | 597 | Existen dos maneras de usar los *stores* en Nuxt: 598 | 599 | #### 1. Clásico 600 | 601 | Para activar el store con el modo clásico, simplemente tenemos que crear el archivo `store/index.js` el cual debe exportar un método que devuelve una instancia de Vuex. 602 | 603 | #### 2. Módulos 604 | 605 | Nuxt nos permite tener un conjunto de *stores* correspondiendo cada uno de los ficheros dentro de la carpeta `store` a un módulo. Si usamos esta opción, tendremos que exportar los estados como una función y las mutaciones y acciones como objetos, en vez de como una instancia Vuex tal y como se hace en el modo clásico 606 | 607 | ### La acción *nuxtServerInit* 608 | 609 | Si la acción *nuxtServerInit* está definida en el store, Nuxt.js llamará a este método desde el contexto del servidor. Es muy útil cuando tenemos datos en el servidor que queremos mandar directamente al lado del cliente. 610 | 611 | ## <a id="guide-plugin"></a>Plugins 612 | 613 | Nuxt.js nos permite definir plugins de Javascript para ser lanzados antes de antes de la instanciación de la aplicación Vue.js. Esto nos sirve de ayuda cuando usamos nuestras librerías o módulos externos. 614 | 615 | > Es muy ‼️importante saber que en el ciclo de vida de una instancia de Vue, sólo los eventos ***beforeCreate*** y ***created*** pueden ser ejecutados tanto en el lado servidor como en el lado cliente, el resto de eventos sólo se llamarán desde el lado de cliente. 616 | 617 | ### Paquetes externos 618 | 619 | Es muy frecuente que nos encontremos en la situación de querer usar un módulo en diferentes componentes de la aplicación. 620 | 621 | Hay un **inconveniente** con esto y es que si volvemos a importar ese módulo en otro componente, se volverá a incluir el bundle completo de ese módulo. Si sólo queremos una instanciación de ese módulo por aplicación entonces debemos de incluir ese módulo en el apartado `build.vendor` dentro de nuestro fichero `nuxt.config.js` 622 | 623 | ### Vue Plugins 624 | 625 | Si queremos usar plugins en nuestra aplicación, necesitamos configurar el plugin antes de lanzar la aplicación. 626 | 627 | Esto se puede hacer siguiendo los siguientes pasos: 628 | 629 | #### 1. Crear un archivo dentro de la carpeta `plugins` 630 | 631 | ```javascript 632 | import Vue from 'vue' 633 | import VueNotifications from 'vue-notifications' 634 | 635 | Vue.use(VueNotifications) 636 | ``` 637 | 638 | #### 2. Añadimos el paquete dentro de la clave `plugins` del archivo `nuxt.config.js` 639 | 640 | ```javascript 641 | module.exports = { 642 | plugins: ['~/plugins/vue-notifications'] 643 | } 644 | ``` 645 | 646 | > Podemos querer que ese módulo se encuentre dentro del bundle de la app, porque se trate de una librería que vamos a usar en toda la aplicación, para ello lo incluimos dentro del *vendor* de *bundle* para un mejor **cacheo de la librería**. 647 | 648 | ### Inyección en $root & context 649 | 650 | Algunos plugins necesitan ser inyectados en el root de la aplicación para ser usados. Con Nuxt.js, podemos usar la `app` disponible dentro del contexto cuando exportemos el método. 651 | 652 | #### 1. Crear un archivo dentro de la carpeta `plugins` 653 | 654 | ```javascript 655 | import Vue from 'vue' 656 | import VueI18n from 'vue-i18n' 657 | 658 | Vue.use(VueI18n) 659 | 660 | export default ({ app }, inject) => { 661 | // Set `i18n` instance on `app` 662 | // This way we can use it in middleware and pages `asyncData`/`fetch` 663 | app.i18n = new VueI18n({ 664 | /* `VueI18n` options... */ 665 | }) 666 | } 667 | ``` 668 | 669 | #### 2. Añadimos el paquete dentro de la clave `plugins` del archivo `nuxt.config.js` 670 | 671 | ```javascript 672 | module.exports = { 673 | build: { 674 | vendor: ['vue-i18n'] 675 | }, 676 | plugins: ['~/plugins/i18n.js'] 677 | } 678 | ``` 679 | 680 | > Podemos querer que ese módulo se encuentre dentro del bundle de la app, porque se trate de una librería que vamos a usar en toda la aplicación, para ello lo incluimos dentro del *vendor* de *bundle* para un mejor **cacheo de la librería**. 681 | 682 | ### Sólo lado de cliente 683 | 684 | Algunos plugins podrían funcionar sólo del lado servidor, bien por que accedan a la variable `window`, porque necesiten `localStorage` o almacenamiento en `cookies`, etc. 685 | 686 | Si es el caso podemos configurar el plugin para que sólo funcione en el lado de cliente, esto se hace insertando una propiedad `ssr: false`dentro del archivo `config.nuxt.js`. 687 | 688 | ```javascript 689 | module.exports = { 690 | plugins: [ 691 | { src: '~/plugins/vue-notifications', ssr: false } 692 | ] 693 | } 694 | ``` 695 | 696 | ## <a id="guide-assets"></a>Assets 697 | 698 | Por defecto, Nuxt usa los loaders `vue-loader`, `file-loader` y `url-loader` de *webpack* para el servicio de assets. Pero también podemos servir estáticos desde la carpeta `static`. 699 | 700 | Estos dos servicios para servir estáticos son: 701 | 702 | ### 1. *Webpacked* 703 | Los recursos son administrados por *webpack*. 704 | 705 | ### 2. *Static* 706 | Subidos directamente a la carpeta `static` y servidos directamente desde ahí, sin la intervención de *webpack* 707 | 708 | ## <a id="guide-despliegue"></a>Despliegue 709 | 710 | ### Lista de comandos 711 | 712 | COMANDO | DESCRIPCIÓN 713 | -------- | ----------- 714 | nuxt | Lanza un servidor de desarrollo en *localhost:3000* con *hot-reloading* 715 | nuxt build | Crear la aplicación con wepack y minifica el JS & CSS (para producción) 716 | nuxt start | Arranca el servidor en modo producción (después de haber ejecutado *nuxt build*) 717 | nuxt generate | Genera la aplicación y genera cada ruta como un archivo HTML (usado para la generación de estáticos) 718 | 719 | ### Despliegue en producción 720 | 721 | Nuxt.js nos permite elegir entre tres modos de desplegar nuestra aplicación: 722 | 723 | #### 1. Server rendered deployment (Universal) 724 | 725 | Para desplegar, en lugar de ejecutar `nuxt`, probablemente queramos construir antes de tiempo. Por lo tanto construir y ejecutar son dos comandos separados. 726 | 727 | ```bash 728 | nuxt build 729 | nuxt start 730 | ``` 731 | 732 | #### 2. SPA 733 | 734 | Para desplegar en modo SPA, debemos hacer lo siguiente: 735 | 1. Cambiar el atributo `mode` en el archivo `nuxt.config.js` a `spa`. 736 | 2. Lanzar `npm run build` 737 | 3. Desplegar la carpeta `dist/` en el servidor web correspondiente. 738 | 739 | #### 3. Generación de estáticos 740 | 741 | Nuxt.js nos da la habilidad de servir nuestra aplicación web desde cualquier *hosting* estático. 742 | 743 | Para generar nuestra aplicación web en archivos estáticos: 744 | 745 | ```bash 746 | npm run generate 747 | ``` 748 | 749 | Con esto crearemos la carpeta `dist` que tendrá todo listo para ser desplegado en nuestro servidor estático. 750 | 751 | 752 | # <a id="ejemplo"></a>Ejemplo 753 | 754 | Vamos a hacer un ejercicio de *live coding* 755 | 756 | # <a id="ejemplo-aws"></a>Ejemplo AWS Serverless 757 | 758 | Comentaremos como hemos hecho una aplicación con Nuxt.js basándonos en una arquitectura **Serverless de AWS**. 759 | 760 | Puede verse en el repositorio: [myImageProject](https://github.com/i62navpm/myImageProject) 761 | --------------------------------------------------------------------------------