Skip to content
Learni
Voir tous les tutoriels
Vue.js

Comment bâtir une app Vue 3 experte en 2026

Read in English

Introduction

En 2026, Vue 3 domine le frontend grâce à sa Composition API qui révolutionne la réutilisabilité et la maintenabilité du code. Contrairement à l'Options API, elle permet une logique métier extraite en composables réutilisables, un typage strict avec TypeScript et une intégration fluide avec des outils comme Pinia pour le state management et Vite pour un bundling ultra-rapide. Ce tutoriel expert vous guide pour bâtir une application TODO avancée : routing gardé, persistence locale, fetching asynchrone via JSONPlaceholder et Suspense pour les états de chargement. Vous apprendrez à scaler une SPA professionnelle, évitant les pièges des apps monolithiques. À la fin, vous aurez un projet copier-collable, prêt pour la prod, optimisé SEO et perf. Idéal pour les seniors visant l'excellence en Vue. (142 mots)

Prérequis

  • Node.js 20+ et npm 10+
  • Connaissances avancées en Vue 3 (Options API, lifecycle)
  • TypeScript intermédiaire (generics, interfaces)
  • VS Code avec extensions Volar, TypeScript Vue
  • Git pour versionning

Initialiser le projet Vite + Vue TS

terminal
npm create vue@latest todo-expert -- --template vue-ts
cd todo-expert
npm install
npm install vue-router@4 pinia @vueuse/core @tanstack/vue-query
npm install -D @types/node
npm run dev

Cette commande crée un projet Vite avec template Vue + TypeScript, installe les dépendances essentielles : Vue Router pour le routing, Pinia pour le state global persistant, VueUse pour des utils composables et TanStack Query pour le data fetching réactif. Le flag --template vue-ts active le typage strict dès le départ. Lancez npm run dev pour vérifier que l'app démarre sur http://localhost:5173.

Configurer Vite et les plugins

Vite est le bundler par défaut de Vue 3, offrant HMR instantané et builds optimisés. Nous étendons sa config pour supporter les aliases, le proxy API et les résolutions TS strictes, essentiels pour une app experte scalable.

vite.config.ts complet

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": resolve(__dirname, "src"),
    },
  },
  server: {
    proxy: {
      '/api': {
        target: 'https://jsonplaceholder.typicode.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^/api/, '/'),
      },
    },
  },
})

Cette config définit l'alias @ pour importer depuis src/, active le plugin Vue et proxy les appels /api vers JSONPlaceholder pour simuler un backend réel sans CORS. Le rewrite nettoie les paths. Redémarrez le dev server après modification pour appliquer les changements.

Initialiser Router et Pinia dans main.ts

src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
import router from './router'

const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')

Le main.ts bootstrap l'app Vue, intègre Pinia pour le state global et Vue Router pour la navigation SPA. createPinia() active la persistence par défaut via plugins. Cette entrée est le cœur de toute app Vue 3 experte.

Mettre en place le routing avancé

Vue Router 4 supporte les guards, lazy-loading et nested routes. Nous configurons deux vues : Home pour les TODOs et About, avec un guard pour protéger les routes si authentifié (simulé).

router/index.ts avec guards

src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import { useAuthStore } from '@/stores/auth'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: () => import('@/views/HomeView.vue'),
    },
    {
      path: '/about',
      name: 'about',
      component: () => import('@/views/AboutView.vue'),
      beforeEnter: (to, from) => {
        const authStore = useAuthStore()
        if (!authStore.isAuthenticated) return '/'
      },
    },
  ],
})

export default router

Ce router utilise createWebHistory pour les URLs propres, lazy-loads les vues pour optimiser le bundle initial et implémente un beforeEnter guard qui vérifie l'auth via Pinia. Les routes sont typées implicitement par TS.

Store Pinia pour auth et persistence

src/stores/auth.ts
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { useLocalStorage } from '@vueuse/core'

export const useAuthStore = defineStore('auth', () => {
  const token = useLocalStorage('auth-token', '')
  const isAuthenticated = ref(!!token.value)

  function login(newToken: string) {
    token.value = newToken
    isAuthenticated.value = true
  }

  function logout() {
    token.value = ''
    isAuthenticated.value = false
  }

  return { token, isAuthenticated, login, logout }
}, {
  persist: true,
})

Ce store utilise defineStore avec Composition API, @vueuse/core pour persistence locale via useLocalStorage. Les actions login/logout mutent le state réactif. L'option persist: true sauvegarde automatiquement en sessionStorage.

Créer des composables réutilisables

Les composables sont la force de Vue 3 : fonctions pures exportant reactive state et logic. Nous en créons un pour fetcher des TODOs avec TanStack Query, intégrant Suspense.

Composable useTodos avec Vue Query

src/composables/useTodos.ts
import { ref } from 'vue'
import { useQuery } from '@tanstack/vue-query'

interface Todo {
  id: number
  title: string
  completed: boolean
}

export function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: async (): Promise<Todo[]> => {
      const res = await fetch('/api/todos?_limit=5')
      if (!res.ok) throw new Error('Fetch failed')
      return res.json()
    },
  })
}

Ce composable encapsule useQuery de TanStack pour caching, refetching auto et états (loading/error). Typé avec interface Todo, il fetch via le proxy Vite. Réutilisable partout, il optimise les perf en évitant les re-fetch inutiles.

Composant HomeView avec Suspense

src/views/HomeView.vue
<template>
  <div>
    <h1>Mes TODOs Experts</h1>
    <Suspense>
      <template #default>
        <TodoList />
      </template>
      <template #fallback>
        <div>Chargement des tâches...</div>
      </template>
    </Suspense>
    <router-link to="/about">About (protégé)</router-link>
  </div>
</template>

<script setup lang="ts">
import TodoList from '@/components/TodoList.vue'
</script>

Ce composant utilise pour gérer les états asynchrones des enfants comme TodoList (qui utilise le composable).