Primeros pasos con Axios en Nuxt
Publicado: 2022-03-10ayncData
y fetch
para obtener datos en el lado del servidor usando Axios y las diferencias entre los dos métodos. Finalmente, aprenderemos cómo agregar autenticación a nuestra aplicación usando el módulo Auth.Nuxt.js proporciona un módulo Axios para una fácil integración con su aplicación. Axios es un cliente HTTP basado en promesas que funciona en el navegador y en el entorno Node.js o, en términos más simples, es una herramienta para realizar solicitudes (por ejemplo, llamadas API) en aplicaciones del lado del cliente y en el entorno Node.js.
En este tutorial, aprenderemos cómo usar el módulo Axios y cómo realizar una solicitud en el lado del servidor usando asyncData y fetch. Estos dos métodos realizan una solicitud en el lado del servidor, pero tienen algunas diferencias que también trataremos. Finalmente, aprenderemos cómo realizar la autenticación y páginas/rutas seguras usando el módulo de autenticación y el middleware de autenticación.
Este artículo requiere conocimientos básicos de Nuxtjs y Vuejs, ya que construiremos sobre eso. Para aquellos que no tienen experiencia con Vuejs, les recomiendo comenzar con su documentación oficial y la página oficial de Nuxt antes de continuar con este artículo.
¿Qué es el módulo Nuxt.js Axios?
Según la Documentación oficial,
“Es una integración segura y fácil de Axios con Nuxt.js”.
Estas son algunas de sus características:
- Establezca automáticamente la URL base para el lado del cliente y el lado del servidor.
- Encabezados de solicitud de proxy en SSR (útil para la autenticación).
- Obtener solicitudes de estilo.
- Integrado con Nuxt.js Progressbar al realizar solicitudes.
Para usar el módulo axios en su aplicación, primero deberá instalarlo usando npm
o yarn
.
HILO
yarn add @nuxtjs/axios
MNP
npm install @nuxtjs/axios
Agréguelo a su archivo nuxt.config.js
:
modules: [ '@nuxtjs/axios', ], axios: { // extra config eg // BaseURL: 'https://link-to-API' }
La matriz de modules
acepta una lista de módulos Nuxt.js como dotenv, auth y, en este caso, Axios. Lo que hemos hecho es informar a nuestra aplicación que usaríamos el módulo Axios, al que hacemos referencia usando @nuxtjs/axios
. A esto le sigue la propiedad axios
, que es un objeto de configuraciones como la baseURL tanto para el lado del cliente como para el lado del servidor.
Ahora, puede acceder a Axios desde cualquier lugar de su aplicación llamando a this.$axios.method
o this.$axios.$method
. Donde el método puede ser get
, post
o delete
.
Realización de su primera solicitud con Axios
Para este tutorial, armé una aplicación simple en Github. El repositorio contiene dos carpetas, inicio y finalización, la carpeta de inicio contiene todo lo que necesita para ingresar directamente al tutorial. La carpeta final contiene una versión completa de lo que estaríamos construyendo.
Después de clonar el repositorio y abrir la carpeta de start
, necesitaríamos instalar todos nuestros paquetes en el archivo package.json
, así que abra su terminal y ejecute el siguiente comando:
npm install
Una vez hecho esto, podemos iniciar nuestra aplicación usando el comando npm run dev
. Esto es lo que debería ver cuando vaya a localhost:3000
.
Lo siguiente que tenemos que hacer es crear un archivo .env
en la carpeta raíz de nuestra aplicación y agregarle la URL de nuestra API. Para este tutorial, usaremos una API de muestra creada para recopilar informes de los usuarios.
API_URL=https://ireporter-endpoint.herokuapp.com/api/v2/
De esta manera, no tenemos que codificar nuestra API en nuestra aplicación, lo cual es útil para trabajar con dos API (desarrollo y producción).
El siguiente paso sería abrir nuestro archivo nuxt.config.js
y agregar la variable ambiental a nuestra configuración de axios que agregamos anteriormente.
/* ** Axios module configuration */ axios: { // See https://github.com/nuxt-community/axios-module#options baseURL: process.env.API_URL, },
Aquí, le decimos a Nuxt.js que use esta baseURL
para nuestras solicitudes del lado del cliente y del lado del servidor siempre que usemos este módulo de Axios.
Ahora, para obtener una lista de informes, abramos el archivo index.vue
y agreguemos el siguiente método a la sección del script.
async getIncidents() { let res = await this.$store.dispatch("getIncidents"); this.incidents = res.data.data.incidents; }
Lo que hemos hecho es crear una función asíncrona a la que llamamos getIncidents()
y podemos saber lo que hace a partir del nombre: obtiene una lista de incidentes usando el método de acción de la tienda Vuex this.$store.dispatch
. Asignamos la respuesta de esta acción a nuestra propiedad de incidentes para que podamos hacer uso de ella en el componente.
Queremos llamar al método getIncidents()
siempre que se monte el componente. Podemos hacerlo usando el gancho mounted
.
mounted() { this.getIncidents() }
mounted()
es un gancho de ciclo de vida que se llama cuando se monta el componente. Eso hará que la llamada a la API suceda cuando se monte el componente. Ahora, ingresemos a nuestro archivo index.js
en nuestra tienda y creemos esta acción desde donde realizaremos nuestra solicitud de Axios.
export const actions = { async getIncidents() { let res = await this.$axios.get('/incidents') return res; } }
Aquí, creamos la acción llamada getIncidents
que es una función asíncrona, luego esperamos una respuesta del servidor y devolvemos esta respuesta. La respuesta de esta acción se devuelve a nuestro método getIncidents()
en nuestro archivo index.vue
.
Si actualizamos nuestra aplicación, ahora deberíamos poder ver una larga lista de incidentes representados en la página.
Hicimos nuestra primera solicitud con Axios, pero no nos detendremos allí, vamos a probar asyncData
y fetch
para ver las diferencias entre ellos y el uso de Axios.
datos asincrónicos
AsyncData obtiene datos del lado del servidor y se llama antes de cargar el componente de la página. No tiene acceso a this
porque se llama antes de que se creen los datos del componente de su página. this
solo está disponible después de que se haya llamado al enlace created
, por lo que Nuxt.js fusiona automáticamente los datos devueltos con los datos del componente.
Usar asyncData
es bueno para SEO porque obtiene el contenido de su sitio en el lado del servidor y también ayuda a cargar contenido más rápido. Tenga en cuenta que el método asyncData
solo se puede usar en la carpeta de páginas de su aplicación, ya que no funcionaría en la carpeta de componentes. Esto se debe a que se llama al gancho asyncData
antes de que se cree su componente.
asyncData
a nuestro archivo index.vue
y observemos qué tan rápido se cargan los datos de nuestros incidentes . Agregue el siguiente código después de la propiedad de nuestros componentes y permítanos deshacernos de nuestro gancho montado.
async asyncData({ $axios }) { let { data } = await $axios.get("/incidents"); return { incidents: data.data.incidents }; }, // mounted() { // this.getIncidents(); // },
Aquí, el método asyncData
acepta una propiedad del contexto $axios
. Usamos esta propiedad para obtener la lista de incidentes y luego se devuelve el valor. Este valor se inyecta automáticamente en nuestro componente. Ahora, puede notar qué tan rápido carga su contenido si actualiza la página y en ningún momento hay ningún incidente para renderizar.
Ha podido recuperar
El método Fetch también se utiliza para realizar solicitudes en el lado del servidor. Se llama después del enlace creado en el ciclo de vida, lo que significa que tiene acceso a los datos del componente. A diferencia del método asyncData
, el método fetch se puede usar en todos los archivos .vue y se puede usar con la tienda Vuex. Esto significa que si tiene lo siguiente en su función de datos.
data() { return { incidents: [], id: 5, gender: 'male' }; }
Puede modificar fácilmente la identificación o el género llamando a this.id
o this.gender
.
Uso de Axios como complemento
Durante el proceso de desarrollo con Axios, es posible que necesite una configuración adicional, como la creación de instancias e interceptores para su solicitud, de modo que su aplicación pueda funcionar según lo previsto y, afortunadamente, podemos hacerlo ampliando nuestro Axios en un complemento.
Para extender axios
, debe crear un complemento (por ejemplo , axios.js ) en su carpeta de plugins
.
export default function ({ $axios, store, redirect }) { $axios.onError(error => { if (error.response && error.response.status === 500) { redirect('/login') } }) $axios.interceptors.response.use( response => { if (response.status === 200) { if (response.request.responseURL && response.request.responseURL.includes('login')) { store.dispatch("setUser", response); } } return response } ) }
Este es un ejemplo de un complemento que escribí para una aplicación Nuxt. Aquí, su función toma un objeto de contexto de $axios
, store
y redirect
que usaríamos para configurar el complemento. Lo primero que hacemos es escuchar un error con un estado de 500
usando $axios.onError
y redirigir al usuario a la página de inicio de sesión.
También tenemos un interceptor que intercepta cada respuesta de solicitud que hacemos en nuestra aplicación y comprueba si el estado de la respuesta que recibimos es 200
. Si eso es cierto, procedemos y verificamos que haya una response.request.responseURL
y si incluye inicio de sesión. Si se comprueba que esto es cierto, enviamos esta respuesta utilizando el método de envío de nuestra tienda donde luego mutó en nuestro estado.
Agregue este complemento a su archivo nuxt.config.js
:
plugins: [ '~/plugins/axios' ]
Después de hacer esto, su complemento Axios interceptaría cualquier solicitud que realice y verificaría si ha definido un caso especial para ello.
Introducción al módulo de autenticación
El módulo de autenticación se usa para realizar la autenticación de su aplicación Nuxt y se puede acceder desde cualquier lugar de su aplicación usando $this.auth
. También está disponible en fetch
, asyncData
, middleware
y NuxtInitServer
desde el objeto de contexto como $auth
.
El context
proporciona objetos/parámetros adicionales de Nuxt a los componentes de Vue y está disponible en áreas especiales del ciclo de vida de nuxt como las mencionadas anteriormente.
Para usar el módulo de autenticación en su aplicación, deberá instalarlo usando yarn
o npm
.
HILO
yarn add @nuxtjs/auth
MNP
npm install @nuxtjs/auth
Agréguelo a su archivo nuxt.config.js
.
modules: [ '@nuxtjs/auth' ], auth: { // Options }
La propiedad auth acepta una lista de propiedades como strategies
y redirect
. Aquí, strategies
aceptan su método de autenticación preferido, que puede ser:
-
local
Para flujo basado en nombre de usuario/correo electrónico y contraseña. -
facebook
Por utilizar cuentas de Facebook como medio de autenticación. -
Github
Para autenticar usuarios con cuentas de Github. -
Google
Para la autenticación de usuarios con cuentas de Google. - Autor0
- Pasaporte Laravel
La propiedad de redirección acepta un objeto de enlaces para:
-
login
Los usuarios serán redirigidos a este enlace si se requiere iniciar sesión. -
logout
Los usuarios serían redirigidos aquí si después de cerrar la sesión la ruta actual está protegida. -
home
Los usuarios serían redirigidos aquí después de iniciar sesión.
Ahora, agreguemos lo siguiente a nuestro archivo nuxt.config.js
.
/* ** Auth module configuration */ auth: { redirect: { login: '/login', logout: '/', home: '/my-reports' }, strategies: { local: { endpoints: { login: { url: "/user/login", method: "post", propertyName: "data.token", }, logout: false, user: false, }, tokenType: '', tokenName: 'x-auth', autoFetchUser: false }, }, }
Tenga en cuenta que el método de auth
funciona mejor cuando se proporciona un punto final de user
en la opción anterior.
Dentro del objeto de configuración de auth
, tenemos una opción de redirect
en la que configuramos nuestra ruta de inicio de sesión a /login
, la ruta de cierre de sesión a /
y la ruta de inicio a /my-reports
que se comportarían como se esperaba. También tenemos una propiedad tokenType
que representa el tipo de autorización en el encabezado de nuestra solicitud de Axios. Está configurado como Bearer
de forma predeterminada y se puede cambiar para que funcione con su API.
Para nuestra API, no hay un tipo de token y es por eso que lo dejaremos como una cadena vacía. El tokenName
representa el nombre de autorización (o la propiedad del encabezado a la que desea adjuntar su token) dentro de su encabezado en su solicitud de Axios.
De forma predeterminada, está configurado como Authorization
, pero para nuestra API, el nombre de Autorización es x-auth
. La propiedad autoFetchUser
se usa para habilitar el objeto de búsqueda del user
usando la propiedad de punto final del usuario después de iniciar sesión. Es true
de forma predeterminada, pero nuestra API no tiene un punto final de user
, por lo que lo configuramos como false
.
Para este tutorial, estaríamos usando la estrategia local. En nuestras estrategias, tenemos la opción local con puntos finales para inicio de sesión, usuario y cierre de sesión, pero en nuestro caso, solo usaríamos la opción *login*
porque nuestra API de demostración no tiene un punto final *logout*
de sesión* y nuestro objeto de usuario está siendo devuelto cuando *login*
es exitoso.
Nota: El módulo de auth
no tiene una opción de registro de punto final, lo que significa que vamos a registrar de la manera tradicional y redirigir al usuario a la página de inicio de sesión donde realizaremos la autenticación usando this.$auth.loginWith
. Este es el método utilizado para autenticar a sus usuarios. Acepta una 'estrategia' (por ejemplo, local
) como primer argumento y luego un objeto con el que realizar esta autenticación. Echa un vistazo al siguiente ejemplo.
let data { email: '[email protected]', password: '123456' } this.$auth.loginWith('local', { data })
Uso del módulo de autenticación
Ahora que hemos configurado nuestro módulo de autenticación, podemos proceder a nuestra página de registro. Si visita la página /register
, debería ver un formulario de registro.
Hagamos que este formulario sea funcional agregando el siguiente código:
methods: { async registerUser() { this.loading = true; let data = this.register; try { await this.$axios.post("/user/create", data); this.$router.push("/login"); this.loading = false; this.$notify({ group: "success", title: "Success!", text: "Account created successfully" }); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } }
Aquí, tenemos una función asíncrona llamada registerUser
que está vinculada a un evento de clic en nuestra plantilla y realiza una solicitud de Axios envuelta en un bloque try/catch a un punto final /user/create
. Esto redirige a la página de inicio de /login
y notifica al usuario de un registro exitoso. También tenemos un bloque catch que alerta al usuario de cualquier error si la solicitud no tiene éxito.
Si el registro es exitoso, será redirigido a la página de inicio de sesión.
Aquí, vamos a hacer uso del método de autenticación de autenticación this.$auth.loginWith('local', loginData)
después de lo cual usaremos this.$auth.setUser(userObj)
para configurar el usuario en nuestra instancia de auth
.
Para que la página de inicio de sesión funcione, agreguemos el siguiente código a nuestro archivo login.vue
.
methods: { async logIn() { let data = this.login; this.loading = true; try { let res = await this.$auth.loginWith("local", { data }); this.loading = false; let user = res.data.data.user; this.$auth.setUser(user); this.$notify({ group: "success", title: "Success!", text: "Welcome!" }); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } }
Creamos una función asíncrona llamada logIn
usando el método de autenticación this.$auth.loginWith('local, loginData)
. Si este intento de inicio de sesión es exitoso, asignamos los datos del usuario a nuestra instancia de autenticación usando this.$auth.setUser(userInfo)
y redirigimos al usuario a la página /my-report
.
Ahora puede obtener datos de usuario usando this.$auth.user
o con Vuex usando this.$store.state.auth.user
pero eso no es todo. La instancia de auth
contiene algunas otras propiedades que puede ver si inicia sesión o verifica su estado usando sus herramientas de desarrollo de Vue.
Si registra this.$store.state.auth
en la consola, verá esto:
{ "auth": { "user": { "id": "d7a5efdf-0c29-48aa-9255-be818301d602", "email": "[email protected]", "lastName": "Xo", "firstName": "Tm", "othernames": null, "isAdmin": false, "phoneNumber": null, "username": null }, "loggedIn": true, "strategy": "local", "busy": false } }
La instancia de auth
contiene una propiedad de loggedIn
de sesión que es útil para cambiar entre enlaces autenticados en la sección de navegación/encabezado de su aplicación. También contiene un método de estrategia que indica el tipo de estrategia que ejecuta la instancia (por ejemplo, local).
Ahora, haremos uso de esta propiedad de loggedIn
de sesión para organizar nuestros enlaces de nav
. Actualice su componente navBar
a lo siguiente:
<template> <header class="header"> <div class="logo"> <nuxt-link to="/"> <Logo /> </nuxt-link> </div> <nav class="nav"> <div class="nav__user" v-if="auth.loggedIn"> <p>{{ auth.user.email }}</p> <button class="nav__link nav__link--long"> <nuxt-link to="/report-incident">Report incident</nuxt-link> </button> <button class="nav__link nav__link--long"> <nuxt-link to="/my-reports">My Reports</nuxt-link> </button> <button class="nav__link" @click.prevent="logOut">Log out</button> </div> <button class="nav__link" v-if="!auth.loggedIn"> <nuxt-link to="/login">Login</nuxt-link> </button> <button class="nav__link" v-if="!auth.loggedIn"> <nuxt-link to="/register">Register</nuxt-link> </button> </nav> </header> </template> <script> import { mapState } from "vuex"; import Logo from "@/components/Logo"; export default { name: "nav-bar", data() { return {}; }, computed: { ...mapState(["auth"]) }, methods: { logOut() { this.$store.dispatch("logOut"); this.$router.push("/login"); } }, components: { Logo } }; </script> <style></style>
En nuestra sección de plantillas, tenemos varios enlaces a diferentes partes de la aplicación en la que ahora estamos usando auth.loggedIn
para mostrar los enlaces apropiados según el estado de autenticación. Tenemos un botón de cierre de sesión que tiene un evento de click
con una función logOut()
adjunta. También mostramos el correo electrónico del usuario obtenido de la propiedad de autenticación a la que se accede desde nuestra tienda Vuex mediante el método mapState
que asigna nuestra autenticación de estado a la propiedad calculada del componente de navegación. También tenemos un método de logout
de sesión que llama a nuestra acción logOut
y redirige al usuario a la página de inicio de login
.
Ahora, avancemos y actualicemos nuestra tienda para tener una acción de logOut
de sesión.
export const actions = { // .... logOut() { this.$auth.logout(); } }
La acción de cierre de sesión llama al método de cierre de logout
de autenticación que borra los datos del usuario, elimina los tokens de logOut
y establece el localStorage
de loggedIn
en false
.
Las rutas como /my-reports
y report-incident
no deberían ser visibles para los invitados, pero en este punto de nuestra aplicación, ese no es el caso. Nuxt no tiene un protector de navegación que pueda proteger sus rutas, pero tiene el middleware de autenticación. Le da la libertad de crear su propio middleware para que pueda configurarlo para que funcione de la manera que desee.
Se puede configurar de dos maneras:
- por ruta.
- Globalmente para toda la aplicación en su archivo
nuxt.config.js
.
router: { middleware: ['auth'] }
Este middleware de auth
funciona con su instancia de auth
, por lo que no necesita crear un archivo auth.js
en su carpeta de middleware.
Agreguemos ahora este middleware a nuestros archivos my-reports.vue
y report-incident.vue
. Agregue las siguientes líneas de código a la sección de script de cada archivo.
middleware: 'auth'
Ahora, nuestra aplicación verificaría si el usuario que intenta acceder a estas rutas tiene un valor auth.loggedIn
de true
. Los redirigirá a la página de inicio de sesión utilizando nuestra opción de redirección en nuestro archivo de configuración de autenticación . Si no ha iniciado sesión e intenta visitar /my-report
o report-incident
, será redirigido a /login
.
Si vas a /report-incidents
, esto es lo que deberías ver.
Esta página es para agregar incidentes, pero en este momento el formulario no envía incidentes a nuestro servidor porque no estamos haciendo la llamada al servidor cuando el usuario intenta enviar el formulario. Para resolver esto, agregaremos un método reportIncident
que se llamará cuando el usuario haga clic en Reportar . Tendremos esto en la sección de script del componente. Este método enviará los datos del formulario al servidor. Actualice su archivo report-incident.vue
con lo siguiente:
<template> <section class="report"> <h1 class="report__heading">Report an Incident</h1> <form class="report__form"> <div class="input__container"> <label for="title" class="input__label">Title</label> <input type="text" name="title" v-model="incident.title" class="input__field" required /> </div> <div class="input__container"> <label for="location" class="input__label">Location</label> <input type="text" name="location" v-model="incident.location" required class="input__field" /> </div> <div class="input__container"> <label for="comment" class="input__label">Comment</label> <textarea name="comment" v-model="incident.comment" class="input__area" cols="30" rows="10" required ></textarea> </div> <input type="submit" value="Report" class="input__button" @click.prevent="reportIncident" /> <p class="loading__indicator" v-if="loading">Please wait....</p> </form> </section> </template> <script> export default { name: "report-incident", middleware: "auth", data() { return { loading: false, incident: { type: "red-flag", title: "", location: "", comment: "" } }; }, methods: { async reportIncident() { let data = this.incident; let formData = new FormData(); formData.append("title", data.title); formData.append("type", data.type); formData.append("location", data.location); formData.append("comment", data.comment); this.loading = true; try { let res = await this.$store.dispatch("reportIncident", formData); this.$notify({ group: "success", title: "Success", text: "Incident reported successfully!" }); this.loading = false; this.$router.push("/my-reports"); } catch (error) { this.loading = false; this.$notify({ group: "error", title: "Error!", text: error.response ? error.response.data.error : "Sorry an error occured, check your internet" }); } } } }; </script> <style> </style>
Aquí, tenemos un formulario con campos de entrada para título, ubicación y comentario con enlace de datos bidireccional usando v-model
. También tenemos un botón de submit
con un evento de clic. En la sección de secuencias de comandos, tenemos un método reportIncident
que recopila toda la información proporcionada en el formulario y se envía a nuestro servidor mediante FormData porque la API está diseñada para aceptar también imágenes y videos.
Este formData
se adjunta a una acción de Vuex utilizando el método de envío, si la solicitud es exitosa, se le redirige a /my-reports
con una notificación que le informa que esta solicitud fue exitosa; de lo contrario, se le notificará un error con el mensaje de error .
En este momento, aún no tenemos la acción reportIncident
en nuestra tienda, por lo que en la consola de su navegador, verá un error si intenta hacer clic en enviar en esta página.
Para solucionar esto, agregue la acción reportIncident a su archivo index.js
.
export const actions = { // ... async reportIncident({}, data) { let res = await this.$axios.post('/incident/create', data) return res; } }
Aquí, tenemos una función reportIncident
que toma un objeto de contexto vacío y los datos que enviamos desde nuestro formulario. Luego, estos datos se adjuntan a una solicitud post
que crea un incidente y regresa a nuestro archivo report-incident.vue
.
En este punto, debería poder agregar un informe utilizando el formulario, luego de lo cual sería redirigido a la página /my-reports
.
Esta página debería mostrar una lista de incidentes creados por el usuario, pero en este momento solo muestra lo que vemos arriba, avancemos para solucionarlo.
Vamos a utilizar el método de fetch
que aprendimos para obtener esta lista. Actualice su archivo my-reports.vue
con lo siguiente:
<script> import incidentCard from "@/components/incidentCard.vue"; export default { middleware: "auth", name: "my-reports", data() { return { incidents: [] }; }, components: { incidentCard }, async fetch() { let { data } = await this.$axios.get("/user/incidents"); this.incidents = data.data; } }; </script>
Aquí, usamos el método de fetch
para obtener incidentes específicos del usuario y asignamos la respuesta a nuestra matriz de incidentes.
Si actualiza su página después de agregar un incidente, debería ver algo como esto.
En este punto, notaríamos una diferencia en cómo el método fetch
y asyncData
cargan nuestros datos.
Conclusión
Hasta ahora, hemos aprendido sobre el módulo Axios y todas sus funciones. También hemos aprendido más sobre asyncData y cómo podemos unirlos a pesar de sus diferencias. También aprendimos cómo realizar la autenticación en nuestra aplicación usando el módulo de autenticación y cómo usar el middleware de autenticación para proteger nuestras rutas. Aquí hay algunos recursos útiles que hablan más sobre todo lo que hemos cubierto.
- Introducción a las metaetiquetas en Nuxjs.
- Usando el módulo dotenv en Nuxt.
- Usando Fetch en su aplicación Nuxt.
- Primeros pasos con asyncData.
Recursos
- "Módulo de autenticación", NuxtJS.org
- “Módulo Axios: Introducción,” NuxtJS.org
-
FormData
, documentos web de MDN - "API: el método
asyncData
", NuxtJS.org - "La instancia de Vue: Diagrama del ciclo de vida", VueJS.org
- "Comprender cómo funciona
fetch
en Nuxt 2.12", NuxtJS.org