Préparation d'entretien 100% Gratuit angularforall.com

Entretien Vue Senior : performance et patterns

Vue-Js Senior Quiz-Vuejs-Senior Nuxt Ssr-Vue Teleport Suspense Custom-Directives Vue-Plugins Vapor-Mode Questions-Entretien-Vuejs-Senior Qcm-Vuejs-Avance Patterns-Vue Performance-Vue
Sénior 🔀 Mixte 20 questions ⏱ 15 min
📝

Entretien Vue Senior : performance et patterns

20 questions Vue.js avancées : SSR avec Nuxt, Teleport, Suspense, custom directives, plugins, optimisation, Vapor mode et patterns avancés pour Senior.

20 questions ⏱ ~15 min Niveau Sénior

Partager

Banque de révision : les 30 questions corrigées

Voici l'intégralité des 30 questions de « Entretien Vue Senior : performance et patterns », chacune avec sa bonne réponse et son explication. Le quiz interactif ci-dessus en tire une sélection aléatoire à chaque tentative — utilisez cette liste complète pour réviser.

  • Le compilateur analyse le template, identifie les parties statiques et les hisse hors de la fonction de rendu pour éviter de les recréer à chaque mise à jour (bonne réponse)
  • Le compilateur exécute le JavaScript
  • Le compilateur ne fait que transformer le HTML en JSX
  • Il n'y a pas de compilateur, tout est interprété au runtime
Explication : Le compilateur Vue 3 transforme les templates en fonctions de rendu optimisées. Le Static Hoisting extrait les nœuds statiques (qui ne dépendent d'aucune donnée réactive) hors de la fonction render. Ces nœuds sont créés une seule fois et réutilisés, réduisant le travail du Virtual DOM.
Pour profiter au maximum du Static Hoisting, évitez d'utiliser des directives inutiles sur du contenu statique. Un <h1>Titre Fixe</h1> pur sera hissé automatiquement.

  • Des marqueurs générés à la compilation qui indiquent exactement quel type de donnée dynamique un élément contient, pour un diffing ciblé (bonne réponse)
  • Des drapeaux de fonctionnalités
  • Des flags pour activer/désactiver des composants
  • Des indicateurs de performance
Explication : Les Patch Flags sont des nombres générés lors de la compilation. Ils indiquent si un élément contient du texte dynamique (1 = TEXT), une classe dynamique (2 = CLASS), etc. Lors du diffing, Vue ne vérifie que les parties marquées, ignorant le reste.
C'est ce qui rend Vue 3 extrêmement performant. Contrairement à React qui compare tout l'arbre, Vue sait exactement quelles parties sont dynamiques.

  • Il utilise une microtask queue (Promise.then) pour regrouper les mises à jour et éviter les rendus redondants dans un même cycle (bonne réponse)
  • Il met à jour le DOM immédiatement à chaque changement
  • Il utilise setTimeout pour chaque mise à jour
  • Il n'y a pas d'ordonnanceur, les mises à jour sont instantanées
Explication : Quand des données réactives changent, Vue ne met pas à jour le DOM immédiatement. Il bufferise les changements et les vide à la fin du cycle actuel (nextTick). Cela évite de rendre plusieurs fois si plusieurs données changent dans la même "tick".
Pour attendre que le DOM soit à jour après un changement : await nextTick().

  • Quand on a besoin de logique de rendu dynamique complexe et programmatique que les templates ne peuvent pas exprimer facilement (bonne réponse)
  • Les fonctions de rendu sont toujours plus rapides que les templates
  • Uniquement pour les composants sans état
  • Les templates sont dépréciés
Explication : Les fonctions de rendu (et JSX) offrent toute la puissance de JavaScript pour générer le Virtual DOM. Utiles pour : composants génériques (bibliothèques UI), rendu conditionnel complexe, manipulation dynamique de slots, ou quand on vient de React.
99% des cas sont couverts par les templates. N'utilisez les fonctions de rendu que quand les templates deviennent un obstacle.

  • Une API qui permet de créer des moteurs de rendu pour d'autres cibles que le DOM (canvas, terminal, natif mobile) (bonne réponse)
  • Un outil pour personnaliser le CSS
  • Un plugin pour le serveur
  • Une API pour créer des composants
Explication : La Custom Renderer API (createRenderer()) permet d'utiliser le système de réactivité et de composants de Vue pour cibler autre chose que le DOM. Exemples : Vue Canvas (rendu sur canvas), Vue-blessed (terminal), Weex/Uni-app (natif mobile).
Cette API est ce qui permet à des frameworks comme NativeScript-Vue ou Uni-app d'utiliser la syntaxe Vue pour des applications mobiles natives.

  • Avec :to="variableRef" où la variable contient un sélecteur CSS ou une référence d'élément DOM (bonne réponse)
  • Le Teleport ne supporte pas le ciblage dynamique
  • Avec v-bind:teleport
  • Uniquement avec un ID fixe
Explication : La prop to peut être dynamique : :to="teleportTarget". teleportTarget peut être un sélecteur ("#modal-container") ou une référence DOM (ref()). Idéal pour les systèmes de plugins où la cible n'est pas connue à l'avance.
Le contenu téléporté doit déjà exister dans le DOM avant que le Teleport ne soit monté. Pour des cibles dynamiques, créez l'élément cible dans onMounted.

  • Setup Store : logique complexe avec composables, meilleur TypeScript ; Options Store : similaire à Vuex, plus familier pour les migrations (bonne réponse)
  • Options Store est plus rapide
  • Setup Store est déprécié
  • Il n'y a pas de différence
Explication : Le Setup Store (fonction) offre une flexibilité totale : utilisation de composables, watchers, logique complexe. Inférence TypeScript parfaite. L'Options Store (objet state/getters/actions) est plus familier aux utilisateurs Vuex et plus structuré.
Pour les nouveaux projets, privilégiez le Setup Store. Pour migrer depuis Vuex, l'Options Store facilite la transition.

  • Retourner un objet avec une méthode install(app, options) qui utilise app.provide(), app.component() et app.config.globalProperties (bonne réponse)
  • Exporter un composant Vue
  • Utiliser un fichier de configuration uniquement
  • Les plugins n'existent plus dans Vue 3
Explication : Un plugin est un objet avec une méthode install(app, options). On peut y : enregistrer des composants globaux (app.component()), fournir des données (app.provide()), ajouter des propriétés globales (app.config.globalProperties), ou des directives (app.directive()).
Pour les propriétés globales, préfixez-les avec $ pour éviter les conflits : app.config.globalProperties.$http = axios.

  • Avec defineSlots() (bonne réponse)
  • Les slots ne peuvent pas être typés
  • Avec PropTypes
  • Avec des interfaces JSDoc
Explication : defineSlots<{ default: (props: { item: Item }) => any; header: () => any }>() (Vue 3.3+) permet de typer les slots, leurs props, et leur présence (optionnel/requis). Le parent reçoit l'auto-complétion et la validation.
Pour rendre un slot optionnel, ajoutez ? : header?: () => any. Pour typer les props exposées au slot : default(props: { item: Item }).

  • Le client "reprend" le HTML rendu côté serveur en attachant les réactions et les événements sans re-rendre tout le DOM (bonne réponse)
  • Le client re-rend toute la page
  • Le serveur envoie du JavaScript pur
  • L'hydratation n'est pas nécessaire
Explication : L'hydratation est le processus où Vue côté client prend le HTML statique généré par le SSR et y attache la réactivité, les événements et l'état. Vue 3.2+ supporte l'hydratation paresseuse (lazy hydration) : seules les parties visibles/interactives sont hydratées.
Des erreurs d'hydratation surviennent si le HTML serveur diffère du rendu client. Utilisez <ClientOnly> pour le contenu spécifique au navigateur.

  • Avec build.rollupOptions.output.manualChunks pour regrouper certaines dépendances dans des chunks nommés (bonne réponse)
  • Le code splitting est automatique et non configurable
  • Avec un fichier de configuration webpack
  • En divisant manuellement les fichiers
Explication : Vite (basé sur Rollup) permet de contrôler le splitting : manualChunks(id) { if (id.includes("node_modules/vue")) return "vue"; if (id.includes("node_modules/three")) return "three"; }. Cela crée des chunks nommés, améliorant le caching navigateur.
Regroupez les grosses dépendances peu mises à jour (three.js, chart.js) dans leur propre chunk pour maximiser le cache.

  • L'interpolation {{ }} échappe automatiquement le HTML ; mais v-html désactive cette protection, nécessitant une validation côté serveur (bonne réponse)
  • Vue.js ne protège pas contre XSS
  • Uniquement si on utilise CSP
  • Avec des tokens CSRF
Explication : L'interpolation {{ }} échappe automatiquement les caractères dangereux (<&lt;). v-html désactive cette protection. Il ne faut JAMAIS utiliser v-html avec du contenu utilisateur non assaini.
Si vous devez utiliser v-html avec du contenu utilisateur, passez-le d'abord par DOMPurify : import DOMPurify from "dompurify";.

  • Utiliser Vue DevTools Timeline, le hook onRenderTracked/onRenderTriggered, et le compilateur avec __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ (bonne réponse)
  • Avec console.log
  • En désactivant la réactivité
  • Le profilage n'est pas possible
Explication : Vue DevTools (onglet Timeline) montre chaque rendu et sa cause. onRenderTracked()/onRenderTriggered() (dev only) indiquent quelles dépendances déclenchent le rendu. En production, __VUE_PROD_DEVTOOLS__ active les DevTools.
Le flag __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ (Vue 3.4+) aide à déboguer les erreurs d'hydratation en production.

  • Avec @originjs/vite-plugin-federation pour exposer et consommer des composants Vue entre applications séparées (bonne réponse)
  • Les micro-frontends ne sont pas compatibles avec Vue
  • Avec des iframes
  • En fusionnant tous les projets en un seul
Explication : Module Federation (Webpack 5) et son équivalent Vite (@originjs/vite-plugin-federation) permettent de partager des composants Vue au runtime entre applications distinctes. Chaque micro-frontend se build indépendamment mais partage ses dépendances.
Partagez vue, vue-router et pinia via le shared dans la config Module Federation pour éviter les doublons.

  • Avec defineCustomElement() qui transforme un composant Vue en Custom Element utilisable hors de Vue (bonne réponse)
  • Les Web Components ne sont pas supportés
  • Avec un plugin tiers uniquement
  • En réécrivant le composant en vanilla JS
Explication : defineCustomElement() (API officielle Vue 3.2+) convertit un composant Vue en un Custom Element standard. On peut l'utiliser dans n'importe quelle page HTML, avec React, Angular, etc. Les props sont mappées en attributs HTML.
Limitation : les Custom Elements ne supportent pas les slots nommés complexes ni le provide/inject. Testez bien votre composant avant de l'exporter.

  • Nettoyer dans onUnmounted : intervals, event listeners, watchers (watchEffect avec retour), et références circulaires (bonne réponse)
  • La mémoire est gérée automatiquement
  • En utilisant des WeakRefs partout
  • En redémarrant l'application régulièrement
Explication : Sources de fuites : intervalles/timers non nettoyés, event listeners sur window/document non retirés, watchers créés avec watchEffect sans onScopeDispose, références circulaires dans les composants gardés par KeepAlive.
watchEffect() retourne une fonction de stop. Stockez-la et appelez-la dans onUnmounted(). Ou utilisez watchEffect() à l'intérieur de <script setup> qui nettoie automatiquement.

  • Un mécanisme pour grouper des effets réactifs (watch, computed) et les nettoyer ensemble, utile dans les composables (bonne réponse)
  • Une directive pour limiter la portée du CSS
  • Un composant spécial
  • Un type de slot
Explication : effectScope() crée un scope qui peut contenir des watchers, computed, et autres effets. Quand le scope est détruit (scope.stop()), tous les effets sont nettoyés automatiquement. Essentiel pour les composables qui créent des watchers.
Dans vos composables, utilisez effectScope() si vous créez dynamiquement des watchers après le setup initial. Sinon, <script setup> gère le scope automatiquement.

  • Avec flushPromises() et waitFor() pour attendre la résolution, et vérifier l'état du DOM après le chargement (bonne réponse)
  • Suspense ne peut pas être testé
  • Avec des tests E2E uniquement
  • En désactivant Suspense pour les tests
Explication : Pour tester un composant dans Suspense : monter le composant, utiliser flushPromises() (ou vi.runAllTimers() en Vitest) pour résoudre les promesses asynchrones, puis vérifier que le fallback a disparu et que le contenu est affiché.
Dans Vitest, await vi.dynamicImportSettled() attend que tous les imports dynamiques soient résolus.

  • Chaîner plusieurs beforeEach avec des vérifications de rôles, permissions, et des redirections conditionnelles basées sur le state Pinia (bonne réponse)
  • Avec une seule vérification simple
  • Les permissions ne sont pas gérées par le routeur
  • Avec des v-if dans les templates uniquement
Explication : Un système avancé : router.beforeEach(async (to, from) => { const auth = useAuthStore(); if (to.meta.requiresAuth && !auth.isLoggedIn) return "/login"; if (to.meta.permissions && !auth.hasPermissions(to.meta.permissions)) return "/403" }). On peut chaîner plusieurs guards pour des vérifications progressives.
Stockez les permissions dans Pinia (chargées à l'authentification). Utilisez to.matched pour vérifier les meta de toutes les routes imbriquées.

  • Envelopper dans , utiliser des clés de route avec une animation CSS personnalisée ou FLIP avec GSAP/Framer Motion (bonne réponse)
  • Les transitions de route ne sont pas possibles
  • Avec des animations CSS uniquement sur le body
  • En rechargeant la page à chaque navigation
Explication : Animation de route : <RouterView v-slot="{ Component, route }"><Transition :name="route.meta.transition || 'fade'"><component :is="Component" :key="route.path" /></Transition></RouterView>. La clé basée sur route.path force la transition.
Pour des animations fluides entre listes et détails, utilisez l'animation FLIP (First, Last, Invert, Play) avec la bibliothèque auto-animate ou GSAP Flip.

  • Activer la compression Brotli/Gzip sur le serveur, analyser le bundle avec rollup-plugin-visualizer, et configurer le lazy loading des routes (bonne réponse)
  • Le build de production est déjà optimisé par défaut
  • Réduire la qualité des images
  • Utiliser un CDN
Explication : Optimisations clés : 1) Lazy loading des routes (component: () => import()), 2) Analyse du bundle avec rollup-plugin-visualizer pour repérer les dépendances lourdes, 3) Compression Brotli/Gzip côté serveur/CDN, 4) Purge CSS (PurgeCSS) si vous utilisez Tailwind.
Activez build.reportCompressedSize: false dans vite.config.js en CI pour accélérer le build.

  • Créer une bibliothèque de composants avec Vite Library Mode, exposer les composants, les composables et les types TypeScript (bonne réponse)
  • Copier-coller les composants entre projets
  • Utiliser uniquement des composants natifs HTML
  • Un Design System n'est pas adapté à Vue
Explication : Avec Vite Library Mode, on peut builder une bibliothèque de composants Vue. On expose les composants (avec defineCustomElement pour l'interopérabilité), les composables, les tokens de design (CSS custom properties), et les types TypeScript.
Structurez votre lib avec : src/components/ (composants), src/composables/ (logique), src/styles/ (tokens CSS). Exportez tout depuis src/index.ts.

  • Intégrer XState via un composable useMachine() qui retourne l'état courant et la fonction send() (bonne réponse)
  • Les state machines ne sont pas compatibles avec Vue
  • Avec des if/else complexes
  • Avec Redux uniquement
Explication : XState s'intègre parfaitement avec Vue via un composable : const { state, send } = useMachine(machine). La machine définit tous les états possibles et les transitions, éliminant les bugs d'états impossibles.
Utilisez XState pour les flux complexes (formulaires multi-étapes, processus de paiement, lecteur audio). Le Visualizer XState aide à concevoir et déboguer.

  • Un ensemble de macros/transformations compilateur : definePropsRefs, defineRender, JSX en setup, booleanMode pour v-model (bonne réponse)
  • Un framework concurrent
  • Un outil de test
  • Un plugin de navigation
Explication : Vue Macros est une bibliothèque qui étend le compilateur Vue avec des fonctionnalités avancées non (encore) intégrées : definePropsRefs() (props réactives), defineRender() (render function dans setup), booleanMode pour v-model, etc.
definePropsRefs() transforme les props en refs, permettant de les destructure sans perdre la réactivité.

  • Vue 3 excelle en rendu réactif (Patch Flags), Svelte en taille de bundle (compilation), React en écosystème et patterns de rendu serveur (bonne réponse)
  • Vue est toujours le plus rapide dans tous les cas
  • React est obsolète
  • Les trois frameworks ont des performances identiques
Explication : Vue 3 : excellent équilibre performance/DX grâce aux Patch Flags et au Static Hoisting. Svelte : le plus petit bundle (compile away) et réactivité fine. React : écosystème immense, RSC modernes, mais Virtual DOM complet plus coûteux en CPU.
Le meilleur framework dépend de votre contexte. Vue brille pour les applications interactives avec un excellent DX. Les benchmarks JS Framework montrent que les trois sont suffisamment rapides.

  • Utiliser une bibliothèque comme mitt, ou un composable basé sur un Map d'événements avec on/emit (bonne réponse)
  • Vue 3 a un Event Bus intégré comme Vue 2
  • Les Event Bus sont anti-pattern, jamais utilisés
  • Avec window.postMessage
Explication : Vue 3 a supprimé le $on/$emit global de Vue 2. On utilise mitt (minuscule, 200 octets) ou on crée son propre composable : const listeners = new Map(); export function useBus() { return { on, emit } }.
Préférez provide/inject ou Pinia pour la communication entre composants. L'Event Bus n'est utile que pour des cas très spécifiques de communication non hiérarchique.

  • Utiliser des bibliothèques headless accessibles (Radix Vue), tester avec eslint-plugin-vuejs-accessibility, et auditer avec Lighthouse/axe-core (bonne réponse)
  • L'accessibilité est automatique
  • Ajouter des attributs alt aux images uniquement
  • Ce n'est pas le rôle du développeur frontend
Explication : Approche complète : 1) Composants headless accessibles (Radix Vue, Headless UI) gèrent ARIA, focus, clavier. 2) Linter eslint-plugin-vuejs-accessibility détecte les problèmes. 3) Tests E2E avec axe-core/pa11y. 4) Audit Lighthouse régulier.
Les composants "headless" sont essentiels : ils gèrent toute la logique d'accessibilité sans imposer de style. Vous gardez le contrôle du design.

  • Utiliser @vue/apollo-composable ou Villus (léger) ; tirer parti du cache Apollo et des fragments pour une UI réactive (bonne réponse)
  • Avec des requêtes fetch dans onMounted
  • GraphQL n'est pas compatible avec Vue
  • Uniquement avec REST
Explication : @vue/apollo-composable (Apollo) ou Villus (plus léger) fournissent des composables réactifs : useQuery(), useMutation(). Le cache Apollo normalise les données et met à jour l'UI automatiquement.
Pour les applications simples, Villus est plus léger et plus facile à configurer. Pour des besoins avancés (cache normalisé, pagination), préférez Apollo.

  • Intégrer Sentry/Bugsnag via un plugin Vue pour capturer les erreurs, et utiliser les métriques Web Vitals avec le composable usePerformanceObserver (bonne réponse)
  • Lire les logs serveur suffit
  • Le monitoring n'est pas nécessaire
  • Avec des alertes email
Explication : Sentry (plugin Vue) capture les erreurs avec le stack trace complet et le contexte Vue (props, state). Pour les Web Vitals (LCP, CLS, INP), on peut créer un composable usePerformanceObserver() et envoyer les métriques à un service d'analytics.
Créez un wrapper autour de app.config.errorHandler pour enrichir les erreurs avec le state Pinia et les infos de route avant de les envoyer à Sentry.

  • Un mode de compilation expérimental sans Virtual DOM, compilant directement les templates en manipulations DOM ciblées, pour des performances proches de Svelte (bonne réponse)
  • Un nouveau framework
  • Un outil de build
  • Un mode sombre pour l'IDE
Explication : Vapor Mode (en développement) est un nouveau mode de compilation qui élimine le Virtual DOM. Les templates sont compilés en fonctions de mise à jour DOM directes et ciblées (fine-grained reactivity). Objectif : performances proches de SolidJS/Svelte, tout en gardant l'API Vue existante.
Vapor Mode sera optionnel (par composant). Vous pourrez migrer progressivement sans réécrire toute l'application.