Nuxt 4
Nuxt es un framework gratuito y de código abierto que se basa en Vue.js y está diseñado para facilitar el desarrollo de aplicaciones web intuitivas, rápidas y de calidad profesional. Con Nuxt, puedes empezar a escribir archivos .vue desde el principio y disfrutar de funcionalidades como recarga en caliente durante el desarrollo y renderizado en el servidor (SSR) por defecto en producción, lo que mejora el rendimiento y la experiencia del usuario Introducción Nuxt 4.x.
¿Qué beneficios tiene Nuxt sobre trabajar solo con Vue?
- Renderizado en el servidor (SSR) por defecto: Nuxt puede generar páginas HTML en el servidor antes de enviarlas al navegador, lo que mejora el SEO, la velocidad de carga inicial y la accesibilidad. Con Vue puro, esto requiere mucha configuración manual SSR en Nuxt 4.x.
- Enrutamiento automático: Nuxt crea rutas automáticamente a partir de la estructura de carpetas, evitando la configuración manual de rutas que sí necesitas en Vue puro Introducción Nuxt 4.x.
- División automática de código: Nuxt divide tu código en partes más pequeñas para que la aplicación cargue más rápido.
- Auto-importación de componentes y composables: No necesitas importar manualmente los componentes o funciones reutilizables, Nuxt lo hace por ti y solo incluye lo que usas en el bundle final.
- Soporte para TypeScript sin configuración: Puedes escribir código seguro y tipado sin preocuparte por la configuración.
- Herramientas de desarrollo integradas: Usa Vite por defecto para un desarrollo más rápido y eficiente.
- Flexibilidad de despliegue: Puedes desplegar tu app en servidores tradicionales, serverless, edge o como sitio estático sin cambios en el código.
En resumen, Nuxt automatiza y simplifica muchas tareas repetitivas y complejas que tendrías que hacer manualmente con Vue puro, permitiéndote enfocarte en crear tu aplicación Introducción Nuxt 4.x.
Instalación
- Tener instalado Node.js (v.18.0.0 en adelante)
npm create nuxt@latest <project-name>Extensiones VSCode
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.
Componentes proporcionados por Nuxt
Los componentes NuxtRouteAnnouncer y NuxtWelcome son componentes proporcionados directamente por Nuxt:
NuxtRouteAnnouncer: Este componente es parte del núcleo de Nuxt (disponible desde Nuxt v3.12+). Su función es mejorar la accesibilidad anunciando los cambios de ruta a tecnologías de asistencia, como los lectores de pantalla. Puedes usarlo simplemente agregándolo en tu archivo
app.vueo en tus layouts. No necesitas instalar nada adicional, ya que viene incluido con Nuxt a partir de la versión mencionada. Más detalles y ejemplos de uso se encuentran en la documentación oficial de Nuxt 3 y 4 NuxtRouteAnnouncer - Nuxt 4.x NuxtRouteAnnouncer - Nuxt 3.x.NuxtWelcome: Este componente también es proporcionado por Nuxt y está pensado para dar la bienvenida en proyectos nuevos creados a partir del template inicial de Nuxt. Incluye enlaces útiles a la documentación y recursos de la comunidad. Se puede usar directamente en el archivo principal de la aplicación (
app.vueoapp/app.vue), y forma parte del paquetenuxt/assetsNuxtWelcome - Nuxt 4.x NuxtWelcome - Nuxt 3.x.
app/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>app/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 app/components y estarán disponibles automáticamente en su aplicación sin tener que importarlos explícitamente. más información sobre componentes
Los nombres de los archivos de componentes deben usar PascalCase o kebab-case.
PascalCase
| components/
--| AppHeader.vue
--| AppFooter.vuekebab-case
| components/
--| app-header.vue
--| app-footer.vueapp.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>Componentes con Props
app\components\title-page.vue
<script setup lang="ts">
interface Props {
title: string;
}
const { title } = defineProps<Props>();
</script>
<template>
<h1>{{ title }}</h1>
</template>app\pages\index.vue
<template>
<TitlePage title="Home" />
</template>app\pages\about.vue
<template>
<TitlePage title="About" />
</template>PascalCase vs kebab-case (recomendación de Nuxt)
Nuxt recomienda utilizar el formato PascalCase para nombrar y llamar a los componentes auto-importados. Por ejemplo, si tienes un componente en una ruta anidada como components/base/foo/Button.vue, el nombre del componente será <BaseFooButton /> y así es como deberías usarlo en tus plantillas. Esto ayuda a mantener claridad y coherencia, especialmente cuando los componentes están en subdirectorios components - Nuxt 4.x components - Nuxt 3.x.
Aunque Vue permite usar tanto PascalCase como kebab-case en los templates, la documentación de Nuxt recomienda que el nombre del archivo coincida con el nombre del componente en PascalCase y que se use ese mismo formato al importarlo o referenciarlo en el template. Esto es especialmente importante para evitar confusiones con componentes auto-importados desde rutas anidadas.
For clarity, we recommend that the component's filename matches its name. So, in the example above, you could rename
Button.vueto beBaseFooButton.vue.
...the component's name will be:<BaseFooButton />
components - Nuxt 4.x
Slots
La razón por la que en la documentación de Nuxt aparece el ejemplo de <slot /> y no <Slot /> es porque <slot /> es un componente nativo de Vue, no un componente personalizado. En Vue (y por extensión en Nuxt), los elementos nativos como <slot>, <template>, y <component> siempre se escriben en minúsculas, siguiendo la convención de HTML. Esto es diferente a los componentes personalizados, que se recomienda escribir en PascalCase, como <MyComponent /> Slot - Nuxt Content.
Por lo tanto, cuando ves <slot /> en la documentación, es porque se está refiriendo al slot nativo de Vue, no a un componente auto-importado o personalizado.
app/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
app/layouts/default.vue
<template>
<div>
<header>
<nav>
<NuxtLink to="/">Home</NuxtLink> |
<NuxtLink to="/about">About</NuxtLink>
</nav>
</header>
<slot />
<footer>
<p>© 2024 My Nuxt Application</p>
</footer>
</div>
</template>Los layouts se habilitan añadiendo el componente <NuxtLayout> en el archivo app.vue.
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</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].vueNuxtLink
La ventaja de usar <NuxtLink> en lugar de <a> es que Nuxt manejará la navegación del lado del cliente, lo que significa que no se recargará toda la página al hacer clic en un enlace, proporcionando una experiencia de usuario más fluida y rápida.
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>Parámetros opcionales
Si queremos que un parámetro de ruta sea opcional, podemos agregar doble corchetes alrededor del nombre del parámetro.
/pages/posts/[[id]].vue
Parámetros dinámicos anidados
Si queremos capturar rutas anidadas, podemos usar tres puntos suspensivos antes del nombre del parámetro.
/pages/posts/[...id].vue
useFetch
useFetch es un composable de Nuxt que se utiliza para obtener (fetch) datos de manera reactiva dentro de componentes, plugins o middleware. Su principal función es facilitar la obtención de datos desde APIs o endpoints, integrando automáticamente la respuesta en el ciclo de vida de Nuxt para evitar solicitudes duplicadas y mejorar la experiencia SSR (Server-Side Rendering).
Cuando usas useFetch, los datos obtenidos se transfieren del servidor al cliente durante la hidratación, evitando que la misma solicitud se haga dos veces (una en el servidor y otra en el cliente). Esto lo diferencia de $fetch, que no transfiere el estado y puede causar doble petición si se usa directamente en componentes. useFetch es ideal para solicitudes GET, aunque también puede usarse para otros métodos HTTP, pero la documentación recomienda $fetch para acciones como POST que se disparan por interacción del usuarioWhich to use: $fetch, useAsyncData or useFetch for GET and POST requests in Nuxt 3?.
En resumen, useFetch sirve para:
- Obtener datos de forma reactiva y eficiente en componentes.
- Evitar solicitudes duplicadas entre servidor y cliente.
- Integrar fácilmente la respuesta en el ciclo de vida de Nuxt y Vue.
Puedes encontrar más detalles y ejemplos en la documentación oficial de useFetchWhich to use: $fetch, useAsyncData or useFetch for GET and POST requests in Nuxt 3?.
useFetch vs $fetch
useFetches el composable preferido para cualquier solicitud de datos que se ejecute durante la fase de configuración (setup) de un componente o página, ya que garantiza que la lógica de renderizado universal (evitar la doble obtención de datos en SSR/CSR) se maneje correctamente.useFetch(url)es casi equivalente auseAsyncData(url, () => event.$fetch(url)).$fetches la utilidad de bajo nivel para realizar solicitudes HTTP puras. Es ideal para llamadas de API que se disparan en respuesta a interacciones del usuario o que se ejecutan exclusivamente en el lado del cliente (donde no se necesita la transferencia de datos entre servidor y cliente)
useFetch ejemplo básico
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 "#shared/types/post";
const { data: posts } = await useFetch<Post[]>(
"https://jsonplaceholder.typicode.com/posts"
);
</script>
<template>
<div>
<h1>Blog page</h1>
<ul>
<li
v-for="post in posts"
:key="post.id"
>
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
<nuxt-link :to="`/blog/${post.id}`">Read more</nuxt-link>
</li>
</ul>
<pre>
{{ posts }}
</pre>
</div>
</template>shared\types\post.ts
export default interface Post {
userId: number;
id: number;
title: string;
body: string;
}pages\posts[id].vue
<script setup lang="ts">
import type Post from "#shared/types/post";
const { id } = useRoute().params;
const { data: post, error } = await useFetch<Post>(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
</script>
<template>
<div>
<h1>Blog Post Detail</h1>
<div v-if="error">
<!-- {{ error }} -->
<!-- {{ error.message }} -->
<p>Error loading post: {{ error.statusCode }}</p>
</div>
<div v-else-if="post && post.title">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
<div v-else>
<p>Loading or post not found...</p>
</div>
</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 requestsserver\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>$fetch
Realiza solicitudes HTTP. Es una versión mejorada de la función nativa fetch con soporte para interceptores, reintentos automáticos, serialización/deserialización automática y más. más información sobre $fetch
const data = await $fetch("https://jsonplaceholder.typicode.com/posts");
console.log(data);try {
// Uso de $fetch para enviar la petición POST a la API.
// $fetch es auto-importado globalmente.
const response = await $fetch("/api/login", {
method: "POST", // Especificar el método HTTP
body: {
username: username.value,
password: password.value,
},
// $fetch automáticamente parsea el cuerpo si es un objeto y establece el Content-Type.
});
// Debe existir una propiedad 'success' en la respuesta del servidor.
if (response.success) {
console.log("Login successful, token:", response.token);
// Redireccionar o almacenar el token
// Es importante usar navigateTo para la navegación programática [18].
await navigateTo("/dashboard");
}
} catch (err) {
// Manejo de errores, por ejemplo, si el servidor devuelve 401
loginError.value = err.data?.message || "Login failed.";
console.error("Login failed:", err);
} finally {
loading.value = false;
}Ejemplo de login con NuxtUI
<script setup lang="ts">
definePageMeta({
middleware: "authenticated",
});
import type { NuxtError } from "#app";
import type { LoginSchemaType } from "#shared/zod/login.schema";
import { loginSchema } from "#shared/zod/login.schema";
import type { AuthFormField, FormSubmitEvent } from "@nuxt/ui";
const { user, loggedIn, fetch: refreshSession } = useUserSession();
const toast = useToast();
const serverError = ref<string | undefined>(undefined);
const loading = ref(false);
const fields: AuthFormField[] = [
{
name: "email",
type: "email",
label: "Correo",
placeholder: "Introduce tu correo",
required: true,
defaultValue: "test1@test.com",
},
{
name: "password",
label: "Contraseña",
type: "password",
placeholder: "Introduce tu contraseña",
required: true,
defaultValue: "123123",
},
{
name: "remember",
label: "Recuérdame",
type: "checkbox",
},
];
const providers = [
{
label: "Google",
icon: "i-simple-icons-google",
onClick: () => {
toast.add({ title: "Google", description: "Login with Google" });
},
},
{
label: "GitHub",
icon: "i-simple-icons-github",
onClick: () => {
toast.add({ title: "GitHub", description: "Login with GitHub" });
},
},
];
async function onSubmit(payload: FormSubmitEvent<LoginSchemaType>) {
try {
loading.value = true;
serverError.value = undefined;
await $fetch("/api/login", {
method: "POST",
body: {
email: payload.data.email,
password: payload.data.password,
},
});
toast.add({ title: "Success", description: "Login successful" });
await refreshSession();
await navigateTo("/admin/dashboard");
} catch (error) {
const err = error as NuxtError;
toast.add({
title: "Error",
description: err.statusMessage || "Login failed 🚩",
color: "error",
});
} finally {
loading.value = false;
}
}
</script>
<template>
<div class="flex flex-col items-center justify-center gap-4 p-4">
<pre>
user: {{ user }}
</pre>
<pre>
loggedIn {{ loggedIn }}
</pre>
<UPageCard class="w-full max-w-md">
<UAuthForm
:schema="loginSchema"
:fields="fields"
:providers="providers"
title="Login to your account"
icon="i-lucide-lock"
@submit="onSubmit"
:loading="loading"
>
<template #description>
Don't have an account?
<ULink
to="/register"
class="text-primary font-medium"
>Sign up</ULink
>.
</template>
<template #password-hint>
<ULink
to="/auth/forgot-password"
class="text-primary font-medium"
tabindex="-1"
>Forgot password?</ULink
>
</template>
<template #validation>
<UAlert
v-if="serverError"
color="error"
icon="i-lucide-info"
:title="serverError"
/>
</template>
<template #footer>
By signing in, you agree to our
<ULink
to="#"
class="text-primary font-medium"
>Terms of Service</ULink
>.
</template>
</UAuthForm>
</UPageCard>
</div>
</template>Ejemplo simple login/logout con server/api y $fetch
server\api\login.post.ts
import { z } from "zod";
const bodySchema = z.object({
email: z.email(),
password: z.string().min(6),
});
export default defineEventHandler(async (event) => {
// const { email, password } = await readBody(event); // SIN VALIDACIÓN
const { email, password } = await readValidatedBody(event, bodySchema.parse);
// Here you would typically validate the email and password,
// check them against a database, and create a session or token.
if (email === "test1@test.com" && password === "123123") {
setCookie(event, "auth_token", "un_valor_de_token_seguro", {
httpOnly: true,
path: "/",
});
return {
message: "Login successful",
};
}
throw createError({
statusCode: 401,
statusMessage: "Invalid email or password",
});
});app\pages\login.vue
<script setup lang="ts">
import type { NuxtError } from "#app";
const email = ref<string>("");
const password = ref<string>("");
const responseMessage = ref<string | undefined>("");
const onSubmit = async () => {
responseMessage.value = "";
try {
const response = await $fetch("/api/login", {
method: "POST",
body: {
email: email.value,
password: password.value,
},
});
responseMessage.value = response.message;
// Usa refreshCookie o fuerza una recarga para asegurar que la cookie esté disponible antes de proteger la ruta.
refreshCookie("auth_token");
setTimeout(async () => {
await navigateTo("/dashboard");
}, 1000);
} catch (error) {
const err = error as NuxtError;
responseMessage.value = err.statusMessage;
} finally {
}
};
</script>
<template>
<div>
<form @submit.prevent="onSubmit">
<input
type="email"
placeholder="email"
name="email"
v-model="email"
/>
<input
type="password"
placeholder="password"
name="password"
v-model="password"
/>
<button type="submit">Login</button>
</form>
<p v-if="responseMessage">{{ responseMessage }}</p>
</div>
</template>app\middleware\auth.ts
export default defineNuxtRouteMiddleware((to) => {
// Solo ejecutar en el servidor
if (import.meta.server && to.path.startsWith("/dashboard")) {
const authToken = useCookie("auth_token");
if (!authToken.value) {
console.log("entró");
return navigateTo("/login");
}
}
});server\api\logout.post.ts
// server/api/logout.post.ts
export default defineEventHandler(async (event) => {
// Si usas nuxt-auth-utils:
// await clearUserSession(event)
// Si manejas la cookie manualmente:
setCookie(event, "auth_token", "", { maxAge: 0, path: "/" });
return { success: true };
});app\pages\dashboard\index.vue
<script setup lang="ts">
definePageMeta({
middleware: "auth",
});
async function logout() {
await $fetch("/api/logout", { method: "POST" });
await navigateTo("/login");
}
</script>
<template>
<div>
<h1>Dashboard</h1>
<p>Ruta protegida</p>
<button @click="logout">Logout</button>
</div>
</template>Características principales de Nuxt DevTools
Overview: Muestra una vista rápida de tu aplicación, incluyendo la versión de Nuxt y Vue, páginas, componentes, imports, módulos, plugins y el tiempo de carga de tu app
Pages: Muestra todas tus rutas actuales con información útil como qué layout o middleware tienen, y proporciona una forma rápida de navegar entre páginas
Components: Muestra todos los componentes que estás usando en tu app y de dónde vienen. Incluye una vista de gráfico que muestra las relaciones entre componentes y sus dependencias. También puedes inspeccionar el árbol DOM de tu app
Imports: Muestra todos los auto-imports registrados en Nuxt, qué archivos los están importando y de dónde vienen, con descripciones y enlaces a documentación
Modules: Muestra todos los módulos instalados con su información (repositorio GitHub, documentación, versión). Puedes instalar o remover módulos con un solo clic
Assets: Muestra tus archivos del directorio Public con información y acciones útiles. Incluye capacidad de subir archivos con Drag & Drop
Terminals: Muestra los procesos de terminal activos
Runtime Config: Muestra toda la configuración runtime de tu proyecto con la capacidad de editarla
Payload: Muestra todos los estados y datos payloads de tu proyecto
Build Analyze: Permite analizar el build y ver el tamaño del bundle de tu proyecto, guardando reportes para comparar diferentes builds
Open Graph: Te ayuda con SEO mostrando una vista previa de tarjetas sociales para Twitter, Facebook y LinkedIn, además de proporcionar tags SEO faltantes
Plugins: Muestra todos los plugins que tu proyecto está usando con información como el tiempo de inicialización
Server Routes: Muestra todas las rutas Nitro en tu proyecto con un playground para enviar y probar tus endpoints
Storage: Muestra todo el almacenamiento Nitro en tu proyecto, permitiéndote crear, editar y eliminar archivos
Tasks: Muestra todas las tareas Nitro en tu proyecto, permitiéndote pasar payloads, ejecutarlas y ver los resultados
VS Code Server: Integración con VS Code que te permite editar y depurar tus proyectos Nuxt usando la interfaz familiar de VS Code directamente en el navegador
Command Palette: Acceso rápido a características útiles como navegación fácil, ejecutar comandos y documentación de Nuxt (se abre con
Ctrl+KoCmd+K)Split Screen: Permite usar múltiples tabs al mismo tiempo
Para abrir DevTools, simplemente presiona Shift + Alt + D (o ⇧ Shift + ⌥ Option + D en Mac) después de iniciar tu servidor de desarrollo.
