Nuxt
Nuxt es un marco gratuito y de código abierto con una forma intuitiva y extensible de crear aplicaciones web y sitios web completos con seguridad de escritura, rendimiento y grado de producción con Vue.js.
Características
- Componentes de Vue.js
- Renderizado estático o dinámico: Al aprovechar el renderizado híbrido, puede obtener lo mejor de ambos mundos: el rendimiento de un sitio estático y la interactividad de uno dinámico.
- Enrutamiento y layout basado en archivos.
- Obtención de datos: Composables que se ejecutan en el servidor para obtener datos antes de que se represente la página.
- Optimización de imágenes, fuentes, y scripts con soporte integrado para módulos css, sass, postcss y más.
- SEO y metaetiquetas.
- Rutas del servidor para crear puntos finales de API y conectarse de forma segura con servicios de terceros.
- Importaciones automáticas.
- Typescript.
Instalación
- Tener instalado Node.js (v.18.0.0 en adelante)
npx nuxi@latest init <project-name>
app.vue
De forma predeterminada, Nuxt tratará este archivo como punto de entrada y mostrará su contenido para cada ruta de la aplicación.
TIP
Si está familiarizado con Vue, quizás se pregunte dónde está main.js
(el archivo que normalmente crea una aplicación Vue). Nuxt hace esto detrás de escena.
/pages
Las páginas representan vistas para cada patrón de ruta específico. Cada archivo en el directorio representa una ruta diferente que muestra su contenido.
/pages/index.vue
<template>
<h1>Home page</h1>
</template>
/pages/about.vue
<template>
<h1>About page</h1>
</template>
app.vue (se puede eliminar si no lo necesita)
<template>
<NuxtPage />
</template>
/components
La mayoría de los componentes son piezas reutilizables de la interfaz de usuario, como botones y menús. En Nuxt, puede crear estos componentes en el directorio /components
y estarán disponibles automáticamente en su aplicación sin tener que importarlos explícitamente. más información sobre componentes
| components/
--| AppHeader.vue
--| AppFooter.vue
app.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
Subdirectorios también son compatibles
| components/
--| AppHeader.vue
--| AppFooter.vue
--| ui/
----| Button.vue
--| card/
----| CardHeader.vue
<template>
<h1>Home page</h1>
<UiButton />
<CardHeader />
</template>
/layouts
Los diseños son envoltorios de páginas que contienen una interfaz de usuario común para varias páginas, como un encabezado y un pie de página. más información sobre layouts
/layouts/default.vue
<template>
<div>
<!-- ejemplo de encabezado -->
<AppHeader />
<!-- contenido de la página -->
<slot />
<!-- ejemplo de pie de página -->
<AppFooter />
</div>
</template>
SEO y metadata
Existen varias formas de agregar metadatos a nuestra aplicación. veremos dos de las más utilizadas. más información sobre SEO y metadata
useHead
<script setup lang="ts">
useHead({
title: "My App",
meta: [{ name: "description", content: "My amazing site." }],
link: [
{
rel: "preconnect",
href: "https://fonts.googleapis.com",
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Roboto&display=swap",
crossorigin: "",
},
],
});
</script>
useSeoMeta
<script setup lang="ts">
useSeoMeta({
title: "My Amazing Site",
ogTitle: "My Amazing Site",
description: "This is my amazing site, let me tell you all about it.",
ogDescription: "This is my amazing site, let me tell you all about it.",
ogImage: "https://example.com/image.png",
twitterCard: "summary_large_image",
});
</script>
TIP
El ogTitle es el título que se mostrará cuando compartas la URL de tu sitio en una plataforma de redes sociales que admita etiquetas Open Graph, como Facebook. Este título se utilizará en la vista previa de la publicación compartida, y es diferente del título de la página web en sí. Puede ser más descriptivo o adaptado a la plataforma de redes sociales en la que se comparte el enlace.
nuxt.config.ts
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
app: {
head: {
title: "Nuxt.js TypeScript project",
link: [
{
rel: "stylesheet",
href: "https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css",
integrity:
"sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN",
crossorigin: "anonymous",
},
],
},
},
});
Pages
Cómo vimos anteriormente solo basta con crear un archivo en la carpeta pages
para que se cree una ruta en nuestra aplicación. El enrutamiento de Nuxt se basa en vue-router.
| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue
NuxtLink
components/AppHeader.vue
<template>
<header>
<nav>
<ul>
<li><NuxtLink to="/about">About</NuxtLink></li>
<li><NuxtLink to="/posts/1">Post 1</NuxtLink></li>
<li><NuxtLink to="/posts/2">Post 2</NuxtLink></li>
</ul>
</nav>
</header>
</template>
Parámetros de ruta
Se utiliza para acceder a la información de la ruta actual. Por ejemplo, si queremos mostrar el id de la ruta posts/[id].vue
/pages/posts/[id].vue
<script setup lang="ts">
const route = useRoute();
// When accessing /posts/1, route.params.id will be 1
console.log(route.params.id);
</script>
useFetch
Obtenga datos de un punto final de API con un elemento componible compatible con SSR. más información sobre useFetch
pages\posts\index.vue
<script setup lang="ts">
import type { Post } from "@/interfaces/Post";
const { data: posts } = await useFetch<Post[]>(
"https://jsonplaceholder.typicode.com/posts"
);
</script>
<template>
<div>
<h1>Lista de Posts</h1>
<CardMain
v-for="{ title, body, id } of posts"
:title="title"
:body="body"
:id="id"
/>
</div>
</template>
interfaces\Post.ts
export interface Post {
title: string;
body: string;
id: number;
userId: number;
}
components\card\CardMain.vue
<script setup lang="ts">
interface Props {
title: string;
body: string;
id: number;
}
const { title, body, id } = defineProps<Props>();
</script>
<template>
<article>
<h2>{{ title }}</h2>
<p>{{ body }}</p>
<NuxtLink :to="`/posts/${id}`">
<span>Read more</span>
</NuxtLink>
</article>
</template>
pages\posts[id].vue
<script setup lang="ts">
import type { Post } from "@/interfaces/Post";
const { id } = useRoute().params;
const { data: post } = await useFetch<Post>(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
</script>
<template>
<div>
<h1>{{ post?.id }} - {{ post?.title }}</h1>
<p>{{ post?.body }}</p>
</div>
</template>
server
Nuxt escanea automáticamente los archivos dentro de estos directorios para registrar una API.
Los nombres de los archivos de manejo pueden tener el sufijo .get, .post, .put, .delete, ... para que coincida con el método HTTP de la solicitud . Por ejemplo, posts.get.ts se manejará para las solicitudes GET a /api/posts. más información sobre server
Estructura de directorios
-| server/
---| api/
-----| hello.ts # /api/hello
---| routes/
-----| bonjour.ts # /bonjour
---| middleware/
-----| log.ts # log all requests
server\api\posts.get.ts
export default defineEventHandler((event) => {
const posts = [
{
userId: 1,
id: 1,
title:
"sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
body: "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto",
},
{
userId: 1,
id: 2,
title: "qui est esse",
body: "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla",
},
{
userId: 1,
id: 3,
title: "ea molestias quasi exercitationem repellat qui ipsa sit aut",
body: "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut",
},
];
return posts;
});
pages\posts\index.vue
<script setup lang="ts">
import type { Post } from "@/interfaces/Post";
const { data: posts } = await useFetch<Post[]>("/api/posts");
</script>
<template>
<div>
<h1>Lista de Posts</h1>
<CardMain
v-for="{ title, body, id } of posts"
:title="title"
:body="body"
:id="id"
/>
</div>
</template>
server\api\posts[id].get.ts
import { Post } from "@/interfaces/Post";
export default defineEventHandler(async (event) => {
const { id } = getRouterParams(event);
const post = await $fetch<Post>(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
return post;
});
pages\posts[id].vue
<script setup lang="ts">
import type { Post } from "@/interfaces/Post";
const { id } = useRoute().params;
const { data: post } = await useFetch<Post>(`/api/posts/${id}`);
</script>
<template>
<div>
<h1>{{ post?.id }} - {{ post?.title }}</h1>
<p>{{ post?.body }}</p>
</div>
</template>