Vue interview questions and answers
30 Vue questions picked from Codejump's quizzes, from the basics a junior is expected to know to the details that trip up senior candidates. Each one comes with its answer and an explanation — try to answer before you open it.
Junior level Vue questions
1.Which Composition API hook replaces the Options API
mountedhook?javascriptimport { onMounted, ref } from 'vue' const el = ref(null) onMounted(() => { console.log('Component is mounted!') console.log(el.value) // DOM element is accessible here })- A.beforeMount()
- B.useMounted()
- C.onMounted()
- D.mounted()
Show answer
Answer: C. onMounted()
In the Composition API, lifecycle hooks are functions imported from Vue and called insidesetup(). Themountedoption becomesonMounted(). The complete mapping from Options API to Composition API:beforeCreate/created→ usesetup()directlybeforeMount→onBeforeMount()mounted→onMounted()beforeUpdate→onBeforeUpdate()updated→onUpdated()beforeUnmount→onBeforeUnmount()unmounted→onUnmounted()
From the quiz ref & reactive
2.How do you create and use layouts in Nuxt 3?
javascript<!-- layouts/default.vue — applied to all pages by default --> <template> <div> <AppHeader /> <main> <slot /> <!-- Page content renders here --> </main> <AppFooter /> </div> </template> <!-- layouts/admin.vue — custom layout for admin pages --> <template> <div class="admin-shell"> <AdminSidebar /> <main> <slot /> </main> </div> </template> <!-- pages/dashboard.vue — uses the admin layout --> <script setup> definePageMeta({ layout: 'admin' }) </script> <template> <div> <h1>Dashboard</h1> </div> </template> <!-- pages/login.vue — no layout --> <script setup> definePageMeta({ layout: false // Disable layout entirely }) </script>- A.Wrap every page in a <Layout> component manually
- B.Create .vue files in the layouts/ directory — use definePageMeta({ layout: 'name' }) in pages to select a layout
- C.Configure layouts in nuxt.config.ts under the layouts key
- D.Layouts are not supported in Nuxt 3 — use slot-based composition instead
Show answer
Answer: B. Create .vue files in the layouts/ directory — use definePageMeta({ layout: 'name' }) in pages to select a layout
Layouts wrap page content with shared UI (navigation, footer, sidebar). Thelayouts/default.vuelayout is applied automatically.From the quiz Nuxt Basics
3.What does the
v-oncedirective do and when should you use it?javascript<template> <!-- Static content that never changes after initial render --> <h1 v-once>Welcome to {{ appName }}</h1> <!-- appName won't update even if the ref changes --> <!-- Static translations --> <footer v-once> <p>Version {{ version }}</p> <p>{{ copyright }}</p> </footer> <!-- Large static tree --> <div v-once> <ProductShowcase :product="initialProduct" /> <!-- initialProduct changes won't affect this --> </div> </template> <!-- Vue 3.2+ alternative: v-memo for conditional memoization --> <template> <div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]"> <!-- Only re-renders if item.id or item.selected changes --> <ExpensiveItemRenderer :item="item" /> </div> </template>- A.It prevents the element from rendering until a condition is met
- B.It limits the number of times a component can re-render to once per second
- C.It renders the element/component once and skips future updates, treating it as static content
- D.It is equivalent to v-if with a boolean that starts as true
Show answer
Answer: C. It renders the element/component once and skips future updates, treating it as static content
v-oncerenders the element or component only once. On subsequent re-renders, Vue skips it entirely. Use it for truly static content.From the quiz v-memo & v-once
4.How do you access the current route's parameters in a component?
javascript// Options API export default { mounted() { console.log(this.$route.params.id) // Route param console.log(this.$route.query.search) // Query string console.log(this.$route.path) // Current path console.log(this.$route.name) // Route name } } // Composition API (recommended) import { useRoute } from 'vue-router' const route = useRoute() console.log(route.params.id) console.log(route.query.search) // Route definition for context: const routes = [ { path: '/users/:id', component: UserProfile } // ↑ This creates params.id ]- A.this.$params.id (Options API), useParams() (Composition API)
- B.this.$router.params.id (Options API), useRouter().params.id (Composition API)
- C.this.$route.params.id (Options API), useRoute().params.id (Composition API)
- D.Only through props — route params are not directly accessible in components
Show answer
Answer: C. this.$route.params.id (Options API), useRoute().params.id (Composition API)
Route parameters are accessed via the current route object. In Options API this isthis.$route, in Composition API useuseRoute().From the quiz Router Basics
5.How do you use a Pinia store in a Vue 3 component?
javascript<script setup> import { useCounterStore } from '@/stores/counter' // Get the store instance const counter = useCounterStore() // Access state directly console.log(counter.count) // Access getters console.log(counter.double) // Call actions function handleClick() { counter.increment() } // $patch for bulk updates counter.$patch({ count: 10, name: 'Updated' }) // $patch with function (for complex updates) counter.$patch((state) => { state.count++ state.name = `Count: ${state.count}` }) </script> <template> <p>Count: {{ counter.count }}</p> <p>Double: {{ counter.double }}</p> <button @click="counter.increment()">Increment</button> </template>- A.Import useCounterStore and call it anywhere in the component
- B.Inject the store using inject('counterStore')
- C.Import useCounterStore and call it inside setup() or <script setup>
- D.Access via this.$store.counter in Options API components
Show answer
Answer: C. Import useCounterStore and call it inside setup() or <script setup>
Call the store composable insidesetup()to get the reactive store instance. The same instance is shared across all components.From the quiz Pinia Basics
6.Quelle est la différence clé entre une propriété
computedet unemethoddans ce contexte ?javascript<script setup> import { ref, computed } from 'vue' const firstName = ref('Alice') const lastName = ref('Martin') // computed const fullNameComputed = computed(() => `${firstName.value} ${lastName.value}`) // method function fullNameMethod() { return `${firstName.value} ${lastName.value}` } </script> <template> <p>{{ fullNameComputed }}</p> <p>{{ fullNameMethod() }}</p> </template>- A.computed est mis en cache selon ses dépendances réactives — il ne recalcule que si firstName ou lastName change. fullNameMethod() est appelée à chaque rendu du composant
- B.Les deux sont identiques — computed est juste une syntaxe alternative aux méthodes
- C.computed ne peut pas accéder aux ref — seules les méthodes le peuvent
- D.computed s'exécute au moment de l'import du composant, avant le rendu
Show answer
Answer: A. computed est mis en cache selon ses dépendances réactives — il ne recalcule que si firstName ou lastName change. fullNameMethod() est appelée à chaque rendu du composant
Usecomputedwhen: the result depends on reactive state and is expensive to compute. Usemethodwhen: you need to trigger a side effect, or the function takes arguments.From the quiz Vue Fundamentals
7.How do you access a DOM element with a template ref in the Composition API?
javascript<template> <input ref="inputEl" type="text" /> <button @click="focusInput">Focus</button> </template> <script setup> import { ref, onMounted } from 'vue' const inputEl = ref(null) onMounted(() => { inputEl.value.focus() // Direct DOM access }) function focusInput() { inputEl.value?.focus() } </script>- A.Declare const myEl = ref(null) and use ref="myEl" in the template
- B.Declare const myEl = ref(null) and use v-ref="myEl" in the template
- C.Use this.$refs.myEl inside onMounted
- D.Use document.querySelector('#myEl') inside onMounted
Show answer
Answer: A. Declare const myEl = ref(null) and use ref="myEl" in the template
To use template refs in the Composition API, declare arefwithnullas initial value, then bind it to the element usingref="varName"in the template. The ref will be populated after the component mounts. The ref name in<script setup>must match therefattribute value in the template.From the quiz ref & reactive
8.How does
<NuxtLink>differ from a plain<a>tag?javascript<template> <!-- Internal navigation — client-side, no page reload --> <NuxtLink to="/about">About</NuxtLink> <!-- Named route --> <NuxtLink :to="{ name: 'users-id', params: { id: user.id } }"> View Profile </NuxtLink> <!-- External link — renders a plain <a> with a full-page navigation. Nuxt adds rel="noopener noreferrer" automatically; it does NOT add target="_blank" — set that yourself if you want a new tab. --> <NuxtLink to="https://nuxt.com" external target="_blank">Nuxt Website</NuxtLink> <!-- Prefetch control — disable for rarely visited pages --> <NuxtLink to="/heavy-page" :prefetch="false">Heavy Page</NuxtLink> <!-- Custom active class --> <NuxtLink to="/" active-class="nav-active" exact-active-class="nav-exact"> Home </NuxtLink> </template>- A.<NuxtLink> renders faster because it avoids the browser's default navigation
- B.<NuxtLink> automatically adds rel="noopener" to external links
- C.<NuxtLink> is Nuxt's enhanced router-link that performs client-side navigation and automatically prefetches linked pages
- D.<NuxtLink> is identical to <RouterLink> — they are interchangeable
Show answer
Answer: C. <NuxtLink> is Nuxt's enhanced router-link that performs client-side navigation and automatically prefetches linked pages
<NuxtLink>extends Vue Router's<RouterLink>with Nuxt-specific features: Key Nuxt-specific features:- Auto-prefetch: When a
<NuxtLink>is visible, Nuxt prefetches the linked page's JavaScript chunk - External detection: recognises absolute URLs, renders them as a plain
<a>with a full-page navigation, and addsrel="noopener noreferrer"(also applied whenevertarget="_blank"is set). It does not addtarget="_blank"itself. - No
importneeded: Auto-imported component
From the quiz Nuxt Basics
9.How do you lazily load a Vue component so it only loads when needed?
javascriptimport { defineAsyncComponent } from 'vue' // Basic async component const HeavyModal = defineAsyncComponent( () => import('./components/HeavyModal.vue') ) // With loading and error states const AsyncTable = defineAsyncComponent({ loader: () => import('./components/DataTable.vue'), loadingComponent: LoadingSpinner, errorComponent: ErrorDisplay, delay: 200, // Show loading component after 200ms timeout: 10000, // Show error component if not loaded in 10s onError(error, retry, fail, attempts) { if (attempts <= 3) { retry() // Retry up to 3 times on network error } else { fail() } } })- A.Use import() inside onMounted hook
- B.Use v-lazy directive from Vue core
- C.Add lazy: true to the component options
- D.Use defineAsyncComponent(() => import('./MyComponent.vue'))
Show answer
Answer: D. Use defineAsyncComponent(() => import('./MyComponent.vue'))
defineAsyncComponentcreates a component that is only loaded when it's first rendered. Vite/webpack split it into a separate chunk.From the quiz v-memo & v-once
10.What is the primary advantage of using named routes?
javascript// Route definition const routes = [ { path: '/users/:id/profile', name: 'user-profile', component: UserProfile }, { path: '/settings', name: 'settings', component: Settings } ] // ✅ Using named routes — resilient to URL changes router.push({ name: 'user-profile', params: { id: 42 } }) <router-link :to="{ name: 'user-profile', params: { id: user.id } }"> View Profile </router-link> // ❌ Hardcoded path — breaks if URL changes router.push(`/users/${id}/profile`) <router-link :to="`/users/${user.id}/profile`">View Profile</router-link>- A.Named routes are faster because Vue Router caches their matched components
- B.Named routes automatically enable route-level code splitting
- C.Named routes are required to use dynamic route parameters
- D.Named routes allow navigation without hardcoding path strings, making URL refactoring easier
Show answer
Answer: D. Named routes allow navigation without hardcoding path strings, making URL refactoring easier
Named routes decouple your navigation code from URL structure. If you change a URL, you only update the route definition — allrouter-linkandrouter.push()calls using the name remain unchanged.From the quiz Router Basics
Mid level Vue questions
11.What defines a Vue 3 composable by convention?
javascript// useCounter.js import { ref, computed } from 'vue' export function useCounter(initialValue = 0) { const count = ref(initialValue) const double = computed(() => count.value * 2) function increment() { count.value++ } function decrement() { count.value-- } function reset() { count.value = initialValue } return { count, double, increment, decrement, reset } } // Usage in any component — each component gets isolated state import { useCounter } from '@/composables/useCounter' const { count, double, increment } = useCounter(10)- A.Any function that returns an object with data, methods, and computed keys
- B.A file that must be exported from a composables/ directory
- C.A class that extends VueComposable from the Vue package
- D.A function prefixed with use that encapsulates stateful reactive logic using Composition API
Show answer
Answer: D. A function prefixed with use that encapsulates stateful reactive logic using Composition API
A composable is a function that uses Vue's Composition API to encapsulate and reuse stateful logic. By convention, composable names start withuse. Each call to a composable creates its own isolated reactive state.From the quiz watch & Composables
12.What are the three types of middleware in Nuxt and when do they run?
javascript// 1. Route middleware — runs on client during navigation // middleware/auth.ts export default defineNuxtRouteMiddleware((to, from) => { const { isAuthenticated } = useAuth() if (!isAuthenticated.value && to.meta.requiresAuth) { return navigateTo('/login', { replace: true }) } }) // Used in a page: definePageMeta({ middleware: 'auth' }) // 2. Global route middleware — runs on ALL navigations // middleware/analytics.global.ts — .global suffix makes it run everywhere export default defineNuxtRouteMiddleware((to) => { useTrackPageView(to.fullPath) }) // 3. Server middleware — runs on every HTTP request (Nitro) // server/middleware/logging.ts export default defineEventHandler((event) => { console.log(`[${new Date().toISOString()}] ${getMethod(event)} ${getRequestURL(event)}`) // No return = passes to next handler // return something = short-circuits the request })- A.Route middleware (navigation-time, client-side), Server middleware (every request, server-side), and Global route middleware (runs on every navigation)
- B.Server middleware (server-side), client middleware (client-side), and universal middleware (both sides)
- C.Page middleware (per-page), app middleware (app-wide), and plugin middleware (plugin execution)
- D.Auth middleware, analytics middleware, and redirect middleware — categorized by purpose
Show answer
Answer: A. Route middleware (navigation-time, client-side), Server middleware (every request, server-side), and Global route middleware (runs on every navigation)
Nuxt has two distinct middleware systems:From the quiz SSR & Data Fetching
13.What does
v-memodo and when should you use it?javascript<template> <!-- v-memo is particularly powerful in v-for with complex items --> <div v-for="item in largeList" :key="item.id" v-memo="[item.id, item.selected, item.value]" > <!-- This entire subtree is skipped if item.id, item.selected, and item.value are all the same as last render --> <ComplexItemRenderer :item="item" /> <div class="metadata"> <span>ID: {{ item.id }}</span> <span>Value: {{ item.value }}</span> <!-- ... 50 more bindings --> </div> </div> <!-- Without v-memo: ALL items re-render when any item changes --> <!-- With v-memo: ONLY items with changed dependency values re-render --> </template>- A.It skips re-rendering a subtree if the provided array of values hasn't changed since the last render
- B.It memoizes the component props between renders, preventing prop object creation
- C.It caches the computed value of an expression in the template
- D.It is equivalent to v-once but with a condition
Show answer
Answer: A. It skips re-rendering a subtree if the provided array of values hasn't changed since the last render
v-memotakes an array of dependency values. If they haven't changed since the last render, Vue skips the entire subtree diff — similar toReact.memofor children.From the quiz shallowRef & markRaw
14.How do you add a navigation guard specific to one route?
javascript// Route-level guard — in route definition const routes = [ { path: '/admin', component: AdminPanel, beforeEnter: [requireAdmin, logAccess], // Array of guards // or a single function: beforeEnter: (to, from) => { if (!store.isAdmin) return { name: 'forbidden' } } } ] // Component-level in-component guards (Composition API) import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router' // Prompt before leaving unsaved form onBeforeRouteLeave((to, from) => { if (hasUnsavedChanges.value) { const confirmed = window.confirm('Leave without saving?') if (!confirmed) return false // Cancel navigation } }) // React to param changes on same route (e.g., /user/1 → /user/2) onBeforeRouteUpdate(async (to, from) => { if (to.params.id !== from.params.id) { user.value = await fetchUser(to.params.id) } })- A.Use beforeEnter in the route definition; also use onBeforeRouteLeave / onBeforeRouteUpdate in the component
- B.Pass a guard function in the route options
- C.Use meta.guard in the route definition
- D.Only global guards exist; per-route guards require a plugin
Show answer
Answer: A. Use beforeEnter in the route definition; also use onBeforeRouteLeave / onBeforeRouteUpdate in the component
Routes supportbeforeEnterfor route-level guards. Components can also useonBeforeRouteLeaveandonBeforeRouteUpdatecomposables.From the quiz Guards & Nested Routes
15.How do you correctly compose stores that depend on each other using setup syntax?
javascript// stores/notifications.ts export const useNotificationStore = defineStore('notifications', () => { const items = ref([]) function add(message: string, type = 'info') { items.value.push({ id: Date.now(), message, type }) } return { items, add } }) // stores/cart.ts — depends on notifications export const useCartStore = defineStore('cart', () => { const items = ref([]) // ✅ Call useNotificationStore INSIDE the setup function // (not at module level) to avoid circular init issues const notifications = useNotificationStore() async function addItem(product) { items.value.push(product) notifications.add(`${product.name} added to cart`, 'success') } return { items, addItem } }) // Circular dependency pattern — lazy resolution // stores/a.ts calls b.ts and b.ts calls a.ts // Solution: access the circular dependency inside an action, not at setup time export const useStoreA = defineStore('a', () => { const data = ref(0) function doSomething() { const storeB = useStoreB() // ✅ Lazy — called inside action, not during setup storeB.notify(data.value) } return { data, doSomething } })- A.Import store A inside store B's setup function at module level
- B.Cross-store dependencies are only supported in Options syntax stores
- C.Use inject(StoreAKey) inside store B's setup function
- D.Call useStoreA() inside store B's setup function, and handle circular dependencies by lazy initialization
Show answer
Answer: D. Call useStoreA() inside store B's setup function, and handle circular dependencies by lazy initialization
Setup stores can call other store composables inside their setup function. For circular dependencies, one store must be accessed lazily (inside an action/getter instead of at setup time).From the quiz Store Composition
16.Comment implémenter
v-modelsur un composant personnalisé en Vue 3 ?javascript<!-- Usage --> <MyInput v-model="username" /> <!-- Equivalent to: --> <MyInput :modelValue="username" @update:modelValue="username = $event" />- A.Vue 3 utilise la prop modelValue et l'événement update:modelValue — le composant reçoit modelValue et émet update:modelValue quand la valeur change
- B.v-model sur un composant personnalisé utilise :value et @input comme pour les inputs natifs
- C.Il faut utiliser $emit('v-model', value) pour que v-model fonctionne
- D.v-model ne peut pas être utilisé sur des composants personnalisés
Show answer
Answer: A. Vue 3 utilise la prop modelValue et l'événement update:modelValue — le composant reçoit modelValue et émet update:modelValue quand la valeur change
Multiple v-model bindings (Vue 3.x):From the quiz Options API Deep-dive
17.How do you clean up side effects inside
watchEffect?javascriptimport { watchEffect, ref } from 'vue' const searchQuery = ref('') watchEffect((onCleanup) => { const controller = new AbortController() // Register cleanup before starting async work onCleanup(() => { controller.abort() // Cancel previous request when query changes }) fetch(`/api/search?q=${searchQuery.value}`, { signal: controller.signal }) .then(r => r.json()) .then(data => { /* update results */ }) .catch(err => { if (err.name !== 'AbortError') throw err }) })- A.Return a cleanup function from watchEffect's callback
- B.Use the onCleanup parameter provided to the callback
- C.Call stopEffect() before the effect re-runs
- D.Use onBeforeUpdate to clean up before re-renders
Show answer
Answer: B. Use the onCleanup parameter provided to the callback
watchEffect(andwatch) provide anonCleanupfunction as a parameter to the callback. This function registers a cleanup callback that runs before the effect re-executes or when the watcher is stopped.From the quiz watch & Composables
18.How do you access server-only vs public environment variables in Nuxt?
javascript// nuxt.config.ts export default defineNuxtConfig({ runtimeConfig: { // SERVER-ONLY — never sent to client databaseUrl: '', // Set via NUXT_DATABASE_URL env var jwtSecret: '', // Set via NUXT_JWT_SECRET stripeSecretKey: '', // Set via NUXT_STRIPE_SECRET_KEY // PUBLIC — available on both server and client public: { apiBase: '/api', // Set via NUXT_PUBLIC_API_BASE appName: 'My App', // Set via NUXT_PUBLIC_APP_NAME gtmId: '' // Set via NUXT_PUBLIC_GTM_ID } } })- A.All environment variables are accessible via process.env in both server and client code
- B.Use appConfig for all environment variables — it works in both environments
- C.Use runtimeConfig — server-only vars in the root, public vars in runtimeConfig.public; access via useRuntimeConfig() composable
- D.Client-side env vars must be prefixed with VITE_; server-side vars are exposed via nuxt.config.ts
Show answer
Answer: C. Use runtimeConfig — server-only vars in the root, public vars in runtimeConfig.public; access via useRuntimeConfig() composable
Nuxt'sruntimeConfigprovides environment-specific access control:From the quiz SSR & Data Fetching
19.What does
<KeepAlive>do and what are the associated lifecycle hooks?javascript<template> <nav> <button @click="activeTab = 'profile'">Profile</button> <button @click="activeTab = 'settings'">Settings</button> <button @click="activeTab = 'billing'">Billing</button> </nav> <!-- Components are cached, not destroyed on tab switch --> <KeepAlive :include="['ProfileTab', 'SettingsTab']" :max="5"> <component :is="activeComponent" /> </KeepAlive> </template>- A.It prevents a component from being garbage collected when it unmounts
- B.It automatically persists component state to localStorage
- C.It caches component instances so they aren't destroyed when dynamically switched, and provides onActivated/onDeactivated lifecycle hooks
- D.It makes components render faster by precompiling their templates
Show answer
Answer: C. It caches component instances so they aren't destroyed when dynamically switched, and provides onActivated/onDeactivated lifecycle hooks
<KeepAlive>wraps dynamic components to cache their state between switches instead of unmounting them.include/excludeaccept component name strings, regex, or arrays.maxlimits cache size (LRU eviction).From the quiz shallowRef & markRaw
20.What is the purpose of the
metafield in route definitions?javascriptconst routes = [ { path: '/dashboard', component: Dashboard, meta: { requiresAuth: true, title: 'Dashboard', roles: ['admin', 'manager'], transition: 'slide' } }, { path: '/profile', component: Profile, meta: { requiresAuth: true, title: 'Profile' } }, { path: '/login', component: Login, meta: { requiresGuest: true, title: 'Sign In' } } ] // Using meta in global guard router.beforeEach((to) => { if (to.meta.requiresAuth && !isAuthenticated()) { return { name: 'login', query: { redirect: to.fullPath } } } if (to.meta.requiresGuest && isAuthenticated()) { return { name: 'dashboard' } } }) // Accessing meta in component const route = useRoute() useHead({ title: route.meta.title }) // With @vueuse/head or similar- A.It stores SEO metadata for server-side rendering
- B.It is required for named routes to work correctly
- C.It provides a way to attach arbitrary custom data to routes, accessible in guards and components
- D.It is only available in the beforeEach global guard
Show answer
Answer: C. It provides a way to attach arbitrary custom data to routes, accessible in guards and components
metais a free-form object that lets you attach custom data to routes — commonly used for auth requirements, page titles, breadcrumbs, or transition names.From the quiz Guards & Nested Routes
Senior level Vue questions
21.What is
effectScopeused for in Vue 3?javascriptimport { effectScope, ref, watch, computed } from 'vue' const scope = effectScope() scope.run(() => { const count = ref(0) const double = computed(() => count.value * 2) watch(count, (val) => console.log('count:', val)) // All effects here are tracked by the scope }) // Dispose all effects at once scope.stop() // Detached scope — not bound to current component's lifecycle const pluginScope = effectScope(true) // true = detached from parent scope pluginScope.run(() => { // Safe to create reactive effects here in a plugin // Won't be accidentally stopped when a component unmounts }) // Clean up when Vue app is unmounted app.onUnmount(() => pluginScope.stop())- A.Limiting the scope of reactive effects to a specific component subtree
- B.Grouping reactive effects so they can all be stopped together with a single call
- C.Creating isolated reactive contexts for unit testing
- D.Both B and C — effectScope is useful for both plugin architecture and testing
Show answer
Answer: D. Both B and C — effectScope is useful for both plugin architecture and testing
effectScope()creates a scope that captures all reactive effects (watchers, computeds) created within it, allowing them to be disposed together with a singlescope.stop()call.From the quiz Advanced Composables
22.How do you implement internationalization in Nuxt 3 with
@nuxtjs/i18n?javascript// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxtjs/i18n'], i18n: { locales: [ { code: 'en', language: 'en-US', file: 'en.json', name: 'English' }, { code: 'fr', language: 'fr-FR', file: 'fr.json', name: 'Français' } ], defaultLocale: 'en', langDir: 'locales/', // Strategy: 'prefix' = /fr/about, 'prefix_except_default' = /about (en), /fr/about strategy: 'prefix_except_default', // Browser locale detection detectBrowserLanguage: { useCookie: true, cookieKey: 'i18n_redirected', redirectOn: 'root' } } })- A.Manually prefix all routes with locale codes and detect language via headers
- B.Configure translations in nuxt.config.ts under the translations key
- C.Use Vue I18n directly without any Nuxt-specific module
- D.Use the @nuxtjs/i18n module which auto-generates locale-prefixed routes, provides useI18n() composable, and handles SSR locale detection
Show answer
Answer: D. Use the @nuxtjs/i18n module which auto-generates locale-prefixed routes, provides useI18n() composable, and handles SSR locale detection
@nuxtjs/i18nintegrates Vue I18n with Nuxt's routing and SSR:From the quiz Nitro & Modules
23.What is "partial hydration" and how does it improve SSR performance?
javascript<!-- Nuxt 3 approach: lazy hydration --> <script setup> import { defineAsyncComponent } from 'vue' // Component hydrated only when it becomes visible const LazyChart = defineAsyncComponent({ loader: () => import('./Chart.vue'), hydrate: hydrateOnVisible() // From vue3-lazy-hydration or Nuxt }) </script> <template> <!-- Static HTML — never hydrated (pure server HTML) --> <header> <Logo /> <StaticNav /> </header> <!-- Interactive island — hydrated immediately --> <SearchBar /> <!-- Users interact with this immediately --> <!-- Lazy island — hydrated when scrolled into view --> <LazyChart :data="chartData" /> <!-- Never hydrated — no JavaScript needed --> <ArticleContent :content="htmlContent" /> </template>- A.Hydrating only the components that appear above the fold
- B.Only hydrating interactive components that need JavaScript behavior, leaving static components as plain HTML
- C.Splitting the hydration process across multiple frames using requestIdleCallback
- D.Using JSON.parse instead of eval for state hydration
Show answer
Answer: B. Only hydrating interactive components that need JavaScript behavior, leaving static components as plain HTML
Partial hydration (also called islands architecture) reduces JavaScript execution by hydrating only interactive components: In Nuxt 3, use<LazyHydrate>or#lazymodifiers:From the quiz Bundle Optimization
24.When do you need to use
router.isReady()?javascript// SSR — server entry file import { createApp } from './app' export async function render(url) { const { app, router } = createApp() router.push(url) await router.isReady() // Wait for initial navigation + all guards to complete // Now render — route is correctly resolved const html = await renderToString(app) return { html } } // Testing import { mount } from '@vue/test-utils' import { createRouter, createWebHistory } from 'vue-router' test('dashboard redirects unauthenticated users', async () => { const router = createRouter({ history: createWebHistory(), routes }) const wrapper = mount(App, { global: { plugins: [router] } }) router.push('/dashboard') await router.isReady() // Wait for navigation guards to run expect(router.currentRoute.value.name).toBe('login') })- A.In SSR to wait for the initial navigation before rendering, or in tests to ensure guards have completed before assertions
- B.Before every navigation to ensure the router is in a valid state
- C.Only when using lazy-loaded routes to ensure components are downloaded
- D.router.isReady() is deprecated — use router.currentRoute.value instead
Show answer
Answer: A. In SSR to wait for the initial navigation before rendering, or in tests to ensure guards have completed before assertions
router.isReady()returns a Promise that resolves when the router has completed its initial navigation (including all navigation guards). Critical in SSR and testing contexts.From the quiz Lazy Loading & Transitions
25.What is the recommended way to structure stores for a large application?
javascript// Domain stores — single source of truth per entity // stores/users.ts export const useUsersStore = defineStore('users', () => { const users = ref<Map<string, User>>(new Map()) function getUser(id: string) { return users.value.get(id) } function setUser(user: User) { users.value.set(user.id, user) } return { users, getUser, setUser } }) // stores/posts.ts export const usePostsStore = defineStore('posts', () => { const posts = ref<Post[]>([]) return { posts } }) // Feature composable — orchestrates multiple stores // composables/useBlogFeed.ts export function useBlogFeed() { const postsStore = usePostsStore() const usersStore = useUsersStore() const { query } = useRoute() const feedPosts = computed(() => postsStore.posts .filter(p => !query.userId || p.authorId === query.userId) .map(p => ({ ...p, author: usersStore.getUser(p.authorId) })) ) async function loadFeed() { const posts = await api.getPosts() // Extract and cache authors without duplicating state const authorIds = [...new Set(posts.map(p => p.authorId))] const authors = await api.getUsersBatch(authorIds) authors.forEach(a => usersStore.setUser(a)) postsStore.posts = posts } return { feedPosts, loadFeed } }- A.One large global store for all application state (like a single Vuex store)
- B.Two stores maximum: one for server state, one for UI state
- C.One store per component to keep state co-located with components
- D.Domain-based stores (one per entity: user, product, cart) with feature-level composition in composables
Show answer
Answer: D. Domain-based stores (one per entity: user, product, cart) with feature-level composition in composables
Domain stores manage entity state; composables orchestrate cross-store logic for specific features.From the quiz Plugins & SSR
26.Comment charger un composant de façon asynchrone et afficher un état de chargement ?
javascript<script setup> import { defineAsyncComponent } from 'vue' const HeavyChart = defineAsyncComponent(() => import('./HeavyChart.vue') ) </script> <template> <Suspense> <template #default> <HeavyChart /> </template> <template #fallback> <div>Loading chart...</div> </template> </Suspense> </template>- A.defineAsyncComponent télécharge le composant à l'avance dès le chargement de la page
- B.Il faut utiliser un try/catch dans le parent pour gérer les erreurs de chargement
- C.<Suspense> ne fonctionne qu'avec les Server Components — pas avec les imports dynamiques client
- D.defineAsyncComponent crée un composant chargé lazily via code splitting — <Suspense> affiche le #fallback pendant le chargement et bascule sur #default une fois résolu
Show answer
Answer: D. defineAsyncComponent crée un composant chargé lazily via code splitting — <Suspense> affiche le #fallback pendant le chargement et bascule sur #default une fois résolu
Suspense with async setup: Error handling:From the quiz Advanced Patterns
27.What is the correct pattern for a data-fetching composable that properly handles component unmounting and rapid re-calls?
javascriptimport { ref, watchEffect, toValue } from 'vue' export function useFetch(urlOrGetter) { const data = ref(null) const error = ref(null) const loading = ref(false) watchEffect(async (onCleanup) => { const url = toValue(urlOrGetter) if (!url) return const controller = new AbortController() // Register cleanup BEFORE the first await onCleanup(() => controller.abort()) loading.value = true error.value = null try { const response = await fetch(url, { signal: controller.signal }) if (!response.ok) throw new Error(`HTTP ${response.status}`) data.value = await response.json() } catch (err) { if (err.name !== 'AbortError') error.value = err } finally { loading.value = false } }) return { data, error, loading } }- A.Return a cancel function and rely on the consumer to call it in onUnmounted
- B.Use onUnmounted inside the composable to abort the request
- C.Use watchEffect with onCleanup to abort the request when dependencies change or the component unmounts
- D.Fetch in onMounted without cleanup — browsers automatically cancel orphaned requests
Show answer
Answer: C. Use watchEffect with onCleanup to abort the request when dependencies change or the component unmounts
CombiningwatchEffectwithonCleanupprovides automatic cancellation of ongoing requests when dependencies change or the component unmounts.From the quiz Advanced Composables
28.How does
@nuxt/imageoptimize images in Nuxt 3?javascript// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxt/image'], image: { // Providers — where images come from domains: ['images.unsplash.com', 'cdn.myapp.com'], // Default provider (local by default) provider: 'ipx', // Built-in: ipx, cloudinary, imgix, bunny, etc. // Provider-specific config cloudinary: { baseURL: 'https://res.cloudinary.com/my-account/image/upload/' }, // Responsive image sizes for srcset screens: { xs: 320, sm: 640, md: 768, lg: 1024, xl: 1280, xxl: 1536 } } })- A.It automatically converts all images to WebP at build time
- B.It compresses images in the public/ directory at build time using Sharp
- C.It provides a <NuxtImg> component that generates optimized, resized, format-converted images on-demand via a server-side image transformation API
- D.It replaces all <img> tags with lazy-loading versions automatically via DOM manipulation
Show answer
Answer: C. It provides a <NuxtImg> component that generates optimized, resized, format-converted images on-demand via a server-side image transformation API
@nuxt/imageprovides on-demand image optimization with multiple provider backends:From the quiz Nitro & Modules
29.How do you diagnose memory leaks in a Vue application?
javascript// Step 1: Chrome DevTools > Memory tab > Take snapshot (baseline) // Step 2: Navigate/mount/unmount the suspected component multiple times // Step 3: Take another snapshot // Step 4: Select "Comparison" view — see what objects were retained // Common Vue leak patterns to look for in heap: // - 'VNode' objects growing = components not unmounting // - 'Array' objects growing = event listeners accumulating // - 'Function' objects growing = closures retaining references // Programmatic leak detection: const weakRefs = [] // After component unmounts, the weakRef should be garbage collected function trackForLeaks(componentInstance) { if (typeof WeakRef !== 'undefined') { weakRefs.push(new WeakRef(componentInstance)) } } // Later: check if refs are collected async function checkForLeaks() { gc() // Force GC (requires --js-flags=--expose-gc in Chrome) const survived = weakRefs.filter(ref => ref.deref() !== undefined) console.log(`${survived.length} components still alive after unmount`) } // Common leak patterns: // 1. Event listeners on window/document not removed in onUnmounted // 2. setInterval not cleared in onUnmounted // 3. WebSocket not closed in onUnmounted // 4. Observer (IntersectionObserver, ResizeObserver) not disconnected // 5. Pinia store subscription not stopped- A.Count the number of components — too many components always indicates a leak
- B.Use Chrome DevTools Memory tab: take heap snapshots before and after navigation, compare retained objects to identify leaks
- C.Watch the number of events in the Vue DevTools — a growing count indicates leaks
- D.Memory leaks are not possible in Vue 3 due to WeakRef-based reactivity
Show answer
Answer: B. Use Chrome DevTools Memory tab: take heap snapshots before and after navigation, compare retained objects to identify leaks
Memory leak diagnosis requires comparing heap states before and after operations:From the quiz Bundle Optimization
30.What are named views in Vue Router and when do you use them?
javascript// Route with named views const routes = [ { path: '/', components: { // Note: plural default: MainContent, sidebar: Sidebar, header: Header } }, { path: '/dashboard', components: { default: DashboardMain, sidebar: DashboardSidebar, header: DashboardHeader } } ]- A.Named routes with human-readable path names instead of patterns
- B.Multiple <router-view> outlets in the same layout, each rendering a different component for the same route
- C.Dynamic component names that can be swapped at runtime
- D.Route aliases — accessing the same component via different names
Show answer
Answer: B. Multiple <router-view> outlets in the same layout, each rendering a different component for the same route
Named views allow rendering multiple components simultaneously for a single route — useful for complex layouts with independent sections.From the quiz Lazy Loading & Transitions
Practise 650+ more Vue questions
Timed quizzes with instant feedback, the questions you miss coming back until they stick, coding challenges and AI mock interviews — free to start.