From harness-claude
Structures Nuxt apps with file-based routing in pages/, named layouts in layouts/, and definePageMeta for per-page config like middleware, transitions, and keepAlive. Use for route structures, nested routes, and catch-all pages.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Structure applications with file-based routing, named layouts, and per-page configuration via definePageMeta
Covers Nuxt 4 fundamentals for project setup, nuxt.config.ts configuration, file-based routing, middleware, SEO with useHead/useSeoMeta, error handling via error.vue/NuxtErrorBoundary, and directory structure.
Structures Next.js 13+ applications using App Router file-system conventions for layouts, nested routes, route groups, dynamic segments, loading, error, and not-found states.
Provides Nuxt 5 core setup with project structure, routing, SEO, error handling, Vite 8, and Nitro v3 configuration. Use for creating apps, routing setup, or config migration.
Share bugs, ideas, or general feedback.
Structure applications with file-based routing, named layouts, and per-page configuration via definePageMeta
Pages — file-based routing:
.vue files in pages/ — the path maps directly to the URL route:pages/
index.vue → /
about.vue → /about
users/
index.vue → /users
[id].vue → /users/:id
[...slug].vue → /* (catch-all)
<NuxtPage /> in app.vue (or within a layout) to render the active page:<!-- app.vue -->
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
useRoute:const route = useRoute();
const id = route.params.id; // typed if using typed routes
Layouts:
layouts/. The default.vue layout is applied automatically. Named layouts require explicit opt-in:<!-- layouts/default.vue -->
<template>
<div>
<AppHeader />
<slot />
<AppFooter />
</div>
</template>
<!-- layouts/dashboard.vue -->
<template>
<div class="dashboard-grid">
<DashboardSidebar />
<main><slot /></main>
</div>
</template>
definePageMeta:// pages/admin/users.vue
<script setup lang="ts">
definePageMeta({
layout: 'dashboard'
})
</script>
definePageMeta({ layout: false });
setPageLayout:const { setPageLayout } = useLayout();
setPageLayout('minimal');
definePageMeta — per-page configuration:
definePageMeta for all page-level config — it is a compiler macro and must be called at the top level of <script setup>:definePageMeta({
layout: 'dashboard',
middleware: ['auth', 'role-admin'],
keepalive: true,
pageTransition: { name: 'slide-left', mode: 'out-in' },
title: 'User Management', // custom meta field
});
Page transitions:
nuxt.config.ts or per-page:// nuxt.config.ts
export default defineNuxtConfig({
app: {
pageTransition: { name: 'page', mode: 'out-in' },
},
});
/* assets/transitions.css */
.page-enter-active,
.page-leave-active {
transition: opacity 0.3s;
}
.page-enter-from,
.page-leave-to {
opacity: 0;
}
Nested routes:
Create a parent page component alongside a subdirectory of the same name to implement nested routing. The parent must include <NuxtPage /> to render the child:
pages/
parent.vue → /parent (contains <NuxtPage />)
parent/
child.vue → /parent/child
Optional catch-all:
[[...slug]].vue matches both / (optional slug) and /a/b/c. Useful for CMS-driven routing.
Typed routes:
Enable experimental.typedPages in nuxt.config.ts to get full TypeScript inference for route params and query strings:
export default defineNuxtConfig({
experimental: { typedPages: true },
});
NuxtPage key — force remount on param change:
By default, navigating between /users/1 and /users/2 reuses the page component. Force a remount with a :key binding:
<NuxtPage :page-key="route => route.fullPath" />
Layout transitions vs. page transitions:
pageTransition — animates the <NuxtPage /> slot contentlayoutTransition — animates the outer <NuxtLayout /> when switching layoutsBoth accept Vue transition options or a boolean.
Custom page meta:
Extend definePageMeta with custom fields by augmenting the PageMeta interface:
// types/nuxt.d.ts
declare module '#app' {
interface PageMeta {
title?: string;
requiresRole?: string;
}
}
Then read it in middleware: to.meta.requiresRole.
https://nuxt.com/docs/guide/directory-structure/pages