Skip to content

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)
sh
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

vue
<template>
  <h1>Home page</h1>
</template>

/pages/about.vue

vue
<template>
  <h1>About page</h1>
</template>

app.vue (se puede eliminar si no lo necesita)

vue
<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

sh
| components/
--| AppHeader.vue
--| AppFooter.vue

app.vue

vue
<template>
  <div>
    <AppHeader />
    <NuxtPage />
    <AppFooter />
  </div>
</template>

Subdirectorios también son compatibles

sh
| components/
--| AppHeader.vue
--| AppFooter.vue
--| ui/
----| Button.vue
--| card/
----| CardHeader.vue
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

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

vue
<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

vue
<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

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.

sh
| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue

components/AppHeader.vue

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

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

vue
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

ts
export interface Post {
  title: string;
  body: string;
  id: number;
  userId: number;
}

components\card\CardMain.vue

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

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

sh
-| server/
---| api/
-----| hello.ts      # /api/hello
---| routes/
-----| bonjour.ts    # /bonjour
---| middleware/
-----| log.ts        # log all requests

server\api\posts.get.ts

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

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

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

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>