Vue/Nuxt Code Conventions
Apply these whenever creating or modifying .vue files or Nuxt composables/plugins in this repo.
Vue SFC Structure
- ALWAYS place
<template>first in the SFC, before<script>and<style>. - ALWAYS use
<script setup lang="ts">. - PREFER grouping by logical concern, not by type (data/methods/computed).
Props & State
- ALWAYS use TypeScript type-based
defineProps(), never runtimePropType. - ALWAYS use type-based
defineEmits(), never runtime array syntax. - ALWAYS destructure props directly from
defineProps()for reactivity + inline defaults. Do not usewithDefaultsor assign to apropsvariable. If the script uses no props, calldefineProps()without destructuring. - ALWAYS use same-name shorthand
:propNameinstead of:propName="propName". - NEVER mutate props or their nested properties; emit changes to the parent.
- ALWAYS keep computed properties pure — no mutations, no async, no logging.
- USE
defineModel()for two-way binding instead of manual prop+emit pairs. - PREFER
ref()overreactive()for state. - PREFER VueUse composables over custom browser/DOM/state implementations (e.g.
useEventListenerover manualaddEventListener+ cleanup).@vueuse/nuxtis installed and auto-imports.
Template Directives
- ALWAYS use
v-for="item of items", neverv-for="item in items".
Composables
- PREFER
toValue()to accept refs, getters, or plain values as input in shared composables. - PREFER grouping composable code by concern/feature, not by Vue API type.
- PREFER extracting calculations to pure helper functions; the composable only handles reactivity.
- PREFER plain utility functions over composables unless reactivity or lifecycle hooks are needed. Expose state; let components handle presentation.
Source: lttr/jedlik-nejedlik — distributed by TomeVault.