z3tz3r0 5108b20954
feat(rules): add vue and nuxt rule sets (#2250)
* feat(rules): add vue and nuxt rule sets

Add rules/vue/ and rules/nuxt/, each with the standard 5-file layout (coding-style, hooks, patterns, security, testing) that extends common/, following the Adding a New Language convention in rules/README.md.

Vue rules reference the frontend-patterns and vite-patterns skills. Nuxt rules reference the nuxt4-patterns and vite-patterns skills. Content is concise (1.5 to 4 KB per file) since rules load as always-on context.

* fix(rules): address PR review on vue and nuxt rule sets

- nuxt/coding-style: generalize the srcDir-override note (drop project-specific 'this repo' phrasing so it is correct for any Nuxt project).

- vue/hooks: add **/*.ts and **/*.tsx to paths so the lint/typecheck guidance loads when editing composables and stores.

- nuxt/hooks: add **/*.vue to paths (covers pages/layouts/components) and wrap nuxi typecheck in a timeout, mirroring web/hooks.md.

- nuxt/security: tighten the /security-review auto-trigger scope to external fetch, credential handling, and sensitive mutations, with examples.

- nuxt/testing: correct 'Vitest-only' to note built-in Playwright E2E, and drop the @nuxt/test-utils version pin.

- README: register vue and nuxt in the structure tree and install examples.

Skipped: 'X specific' -> 'X-specific' hyphenation (all existing rule sets use the unhyphenated form, changing only vue/nuxt would be inconsistent); repeating the 80%/TDD mandate in nuxt/testing (already inherited from common/testing.md).
2026-06-15 14:01:38 -04:00

2.6 KiB

paths
paths
**/nuxt.config.*
**/app.config.*
**/app.vue
**/server/**/*.ts
**/pages/**
**/middleware/**

Nuxt Patterns

This file extends common/patterns.md with Nuxt specific content.

Data-fetch selection

Load-bearing. Pick by render timing, not habit.

  • useFetch(url) = SSR-safe, URL-first initial/first-paint data. The default. Forwards the server result through the payload so there is no hydration double-fetch.
  • useAsyncData(key, fn) = SSR-safe, custom async logic (SDK / GraphQL / combined calls). The explicit key shares the result across components.
  • $fetch = client interactions only (form submit, button click, POST/PUT/DELETE). NOT SSR-safe, double-fetches if used for first paint.
  • Rule: useFetch / useAsyncData for anything rendered on first paint, $fetch only for event-driven mutations.

Shared state

  • useState('key', () => init) for SSR-safe shared state. Values must be JSON-serializable.
  • NEVER export const x = ref() at module scope. One shared instance leaks across concurrent SSR requests and causes a memory leak.
  • With @pinia/nuxt: Pinia for domain state, useState for small cross-component primitives.
  • Async server-side init goes in callOnce(async () => {...}), not as a side effect inside useAsyncData.

Nitro server routes

  • server/api/*.{get,post}.ts auto-register by path + method. Handler is defineEventHandler((event) => ...).
  • Errors via throw createError({ status, statusText }). Prefer the Web-API status / statusText over deprecated statusCode / statusMessage.
  • server/middleware/ must NOT return a response. Only mutate event.context or set headers.

Route middleware

  • app/middleware/*.ts with defineNuxtRouteMiddleware((to, from) => ...).
  • Use the to / from args. Do NOT call useRoute() inside middleware.
  • .global suffix runs on every route. Return navigateTo() to redirect, abortNavigation() to stop.

Hydration-safe rendering

  • Route off status (idle | pending | success | error) for lazy fetches.
  • useAsyncData payload uses devalue (Date/Map/Set/refs survive). A server/api response is JSON.stringify-only, so define toJSON() for non-JSON types.
  • Shrink payload with pick / transform. This reduces serialized size, it does not skip the fetch.

Reference