everything-claude-code/rules/vue/coding-style.md
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
**/*.vue

Vue Coding Style

This file extends common/coding-style.md with Vue specific content.

SFC Structure

  • Always <script setup lang="ts"> with the Composition API. No Options API in new code.
  • Block order inside a .vue file: <script setup>, then <template>, then <style scoped>. One component per file.
  • Naming: component files PascalCase (AuctionCard.vue), composables camelCase prefixed useXxx (useAuctionTimer).
  • Format with Prettier plus ESLint flat config using eslint-plugin-vue (vue/vue3-recommended). Type-check with vue-tsc.

Reactivity Discipline

  • ref is the primary state API. Mutate via .value in script, auto-unwrapped only at template top level.
  • Nested ref inside arrays, Map, or Set still needs .value to read.
  • Reach for reactive only for grouped object state. Never reassign a whole reactive object.
  • Never destructure a reactive object or a Pinia store without toRefs / storeToRefs. Plain destructure silently drops reactivity.

Computed and Watchers

  • computed getters must be pure: no side effects, no async, no DOM access.
  • 3.4+ computed only triggers when the returned value changes. Return the prior object unchanged when equal to skip downstream updates.
  • watch is lazy. Pass a getter for a reactive property (watch(() => x.value, ...)), not the bare reactive object.
  • watchEffect is eager and stops tracking dependencies after its first await.

Lifecycle and DOM

  • Register lifecycle hooks synchronously inside setup (onMounted, onUnmounted).
  • Clean up timers, listeners, and subscriptions in onUnmounted.
  • Read or measure the DOM only after await nextTick().

Macros and Templates

  • Macros: defineProps / defineEmits (tuple form change: [id: number]), defineModel (3.4+) for v-model, withDefaults or 3.5+ reactive-props-destructure for defaults, defineExpose for the public ref API.
  • Put a :key on every v-for, a stable unique primitive. Never the array index, never an object.
  • Never put v-if and v-for on the same element. Wrap with <template v-for> plus an inner v-if, or precompute a filtered list.
<script setup lang="ts">
const props = defineProps<{ id: number }>()
const emit = defineEmits<{ change: [id: number] }>()
const open = defineModel<boolean>('open', { default: false })
</script>

Reference