Transformer une app Vue.js ou Nuxt en application mobile avec Capacitor

Par Nathan Guigui, Fondateur de GUIGUI Tech · Faits vérifiés sur les sources officielles citées en fin d'article

Oui, une application Vue.js ou Nuxt peut devenir une vraie application iOS et Android sans être réécrite : Capacitor embarque le build web dans un projet natif et donne accès aux fonctions du téléphone via des plugins. Pour Vue 3 avec Vite, on installe Capacitor, on pointe son webDir vers dist et on génère les projets iOS et Android. Pour Nuxt, l'app doit en plus être générée en statique (nuxt generate, idéalement avec ssr: false), car aucun serveur Node ne tourne dans le téléphone.

Quels sont les prérequis pour utiliser Capacitor avec Vue ou Nuxt ?

Les prérequis de Capacitor 8, version stable à la date d'octobre 2026, sont Node.js 22 ou plus, un Mac avec Xcode 26.0 ou plus pour iOS, et Android Studio 2025.2.1 ou plus pour Android. Selon le guide de mise à jour vers Capacitor 8, les projets ciblent au minimum iOS 15.0 et Android API 24.

Élément (Capacitor 8, octobre 2026)Exigence
Node.js22 ou plus
Xcode (iOS)26.0 ou plus, donc un Mac
Android Studio2025.2.1 (Otter) ou plus
Cible iOS minimaleiOS 15.0
AndroidminSdkVersion 24, targetSdkVersion 36
Dépendances iOSSwift Package Manager par défaut

Côté code, il faut un projet Vue 3 qui produit un build statique, ce qui est le cas par défaut avec Vite. Ionic, l'éditeur de Capacitor, annonce par ailleurs Capacitor 9 pour fin novembre 2026 dans The Road to Capacitor 9, et rappelle que le dépôt central de CocoaPods passe en lecture seule le 2 décembre 2026 : restez sur Swift Package Manager.

Comment ajouter Capacitor à un projet Vue 3 + Vite ?

Pour ajouter Capacitor à un projet Vue 3 + Vite, on installe @capacitor/core et @capacitor/cli, on lance npx cap init avec dist comme dossier web, on ajoute les plateformes, puis on enchaîne build Vite et npx cap sync. Les commandes suivent le guide d'installation officiel :

npm install @capacitor/core
npm install -D @capacitor/cli
npx cap init "Mon App" fr.exemple.monapp --web-dir dist

npm install @capacitor/ios @capacitor/android
npx cap add ios
npx cap add android

npm run build
npx cap sync
npx cap run ios

L'identifiant (fr.exemple.monapp) devient le bundle ID iOS et l'application ID Android : il ne change plus après publication. npx cap init crée un capacitor.config.ts :

import type { CapacitorConfig } from '@capacitor/cli'

const config: CapacitorConfig = {
  appId: 'fr.exemple.monapp',
  appName: 'Mon App',
  webDir: 'dist',
}

export default config

dist est la valeur par défaut de l'option build.outDir de Vite ; si vous l'avez modifiée, reportez-la dans webDir. Les dossiers ios/ et android/ sont de vrais projets natifs, à versionner dans Git.

npx cap sync copie le build dans les projets natifs et met à jour les dépendances des plugins : il faut le relancer après chaque build web et chaque ajout de plugin.

À retenir

Ajoutez un script "build:mobile": "vite build && cap sync" dans votre package.json. Oublier le sync est la cause la plus fréquente du « mes changements n'apparaissent pas sur le téléphone ».

Comment configurer Nuxt pour Capacitor ?

Pour utiliser Capacitor avec Nuxt, il faut produire un build entièrement statique avec nuxt generate (ou npx nuxi generate) et indiquer .output/public comme webDir. Capacitor n'embarque que des fichiers : il n'y a pas de serveur Nitro dans le téléphone.

La documentation de déploiement de Nuxt décrit deux options statiques : le pré-rendu de chaque route (ssr: true, comportement par défaut de nuxt generate) ou le rendu client uniquement (ssr: false), qui produit .output/public/index.html et des bundles JavaScript, comme une app Vue classique. Pour une app mobile, ssr: false est le plus simple : le pré-rendu sert surtout au référencement, et le mode SPA évite d'exécuter du code dans un contexte serveur où les API de Capacitor n'existent pas.

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
})

Dans capacitor.config.ts, mettez webDir: '.output/public'. Si le même projet sert aussi le site en SSR, activez ssr: false uniquement pour le build mobile, via une variable d'environnement lue dans nuxt.config.ts.

Les routes serveur ne suivent pas. Selon la page sur les modes de rendu, avec nuxt generate aucun serveur n'est inclus dans le dossier de sortie, donc aucun endpoint serveur n'est utilisable. Tout ce qui vit dans server/api/ doit être déployé ailleurs et appelé par URL absolue. Sans serveur, les valeurs de runtimeConfig.public (comme l'URL de l'API) doivent être fixées au moment du nuxt generate.

Faut-il utiliser le mode history ou le mode hash avec Vue Router ?

Le mode history de Vue Router (createWebHistory) fonctionne en général dans une app Capacitor et reste le choix par défaut. L'app est servie depuis une origine locale (capacitor://localhost sur iOS, https://localhost sur Android, selon les valeurs par défaut de la configuration) et démarre toujours sur index.html. Le mode hash (createWebHashHistory), qui selon la documentation de Vue Router ne demande aucune configuration serveur, reste une solution de repli.

Garder le mode history permet aussi d'utiliser les mêmes chemins pour les deep links : Universal Links sur iOS (fichier apple-app-site-association), App Links sur Android (fichier assetlinks.json). Une fois la configuration décrite dans la documentation Capacitor sur les deep links en place, il suffit côté Vue d'écouter l'événement appUrlOpen :

// src/main.ts, après app.use(router)
import { App as CapApp } from '@capacitor/app'

CapApp.addListener('appUrlOpen', (event) => {
  const url = new URL(event.url)
  router.push(url.pathname + url.search)
})

Sous Nuxt, ce code se place dans un plugin client (plugins/deep-links.client.ts) avec useRouter().

Comment utiliser les plugins natifs de Capacitor depuis Vue ?

Les plugins Capacitor s'installent avec npm, s'importent en TypeScript et s'appellent comme des fonctions asynchrones : le plus propre est de les encapsuler dans des composables Vue. Après chaque installation, lancez npx cap sync.

BesoinPluginPoint d'attention
Photo, galerie@capacitor/cameraTextes de permission dans Info.plist
Notifications push@capacitor/push-notificationsCapability Push sur iOS, google-services.json sur Android
Stockage clé-valeur@capacitor/preferencesNi base de données, ni chiffrement
Liens, bouton retour@capacitor/appBouton retour Android à gérer
Clavier@capacitor/keyboardRedimensionnement sur iOS

Depuis la version 8.1.0 du plugin Camera, la documentation recommande takePhoto et chooseFromGallery, qui remplacent getPhoto et pickImages, dépréciés :

// src/composables/usePhoto.ts
import { ref } from 'vue'
import { Camera, CameraDirection } from '@capacitor/camera'

export function usePhoto() {
  const photoUrl = ref<string | null>(null)

  async function takePhoto() {
    const result = await Camera.takePhoto({
      quality: 90,
      cameraDirection: CameraDirection.Rear,
    })
    photoUrl.value = result.webPath ?? null
  }

  return { photoUrl, takePhoto }
}

Sur Android, écouter l'événement backButton du plugin App désactive le comportement par défaut : à vous de revenir en arrière ou de quitter l'app.

// src/composables/useAndroidBack.ts
import { onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { App as CapApp } from '@capacitor/app'
import type { PluginListenerHandle } from '@capacitor/core'

export function useAndroidBack() {
  const router = useRouter()
  let handle: PluginListenerHandle | undefined

  onMounted(async () => {
    handle = await CapApp.addListener('backButton', ({ canGoBack }) => {
      if (canGoBack) router.back()
      else CapApp.exitApp()
    })
  })

  onUnmounted(() => handle?.remove())
}

Le plugin Preferences remplace localStorage, que le système peut vider, pour les petites données persistantes ; il ne chiffre rien, donc pas de secrets dedans. Pour les notifications push, l'ordre compte : requestPermissions(), puis register(), puis l'événement registration pour récupérer le jeton à envoyer à votre backend. Enfin, testez Capacitor.isNativePlatform() (de @capacitor/core) avant d'appeler un plugin sans équivalent web, pour que le même code tourne sur le site.

Comment développer avec le live reload sur un téléphone ?

Le live reload fait charger par l'app le serveur de développement de votre ordinateur au lieu des fichiers embarqués : chaque modification apparaît sur le téléphone sans rebuild. Le serveur doit écouter sur le réseau local et le téléphone être sur le même Wi-Fi.

npx vite --host
npx cap run android --live-reload --host 192.168.1.20 --port 5173

L'option --host de Vite écoute sur toutes les adresses ; remplacez l'IP par celle de votre ordinateur. Les options de npx cap run sont décrites dans la documentation de la CLI. Avec Nuxt, lancez npx nuxi dev --host et utilisez le port 3000. La documentation du live reload décrit aussi une variante avec server.url dans la configuration, en prévenant de ne pas la committer : une app publiée ainsi chargerait votre ordinateur.

Quels sont les pièges courants d'une app Vue avec Capacitor ?

Les pièges les plus fréquents sont les URL d'API relatives et le CORS, les cookies d'authentification, les zones de l'écran, le clavier, les icônes et les textes de permission iOS. Ils se découvrent souvent tard, sur appareil réel.

URL d'API et CORS. Toutes les URL d'API doivent être absolues. Le serveur voit des requêtes venant de capacitor://localhost ou https://localhost : ajoutez ces origines à sa configuration CORS, ou activez CapacitorHttp, désactivé par défaut, qui fait passer fetch et XMLHttpRequest par les bibliothèques HTTP natives.

Cookies et authentification. Une session par cookie peut casser, car le domaine de l'API n'est plus celui de la page. La documentation CapacitorCookies rappelle que, depuis iOS 14, les cookies tiers ne sont pas utilisables par défaut, et propose de déclarer vos domaines dans WKAppBoundDomains. Un jeton envoyé dans un en-tête est souvent plus simple à fiabiliser.

Zones sûres. Ajoutez viewport-fit=cover à la meta viewport et utilisez env(safe-area-inset-top) et ses variantes. Sur Android, le plugin System Bars, intégré à Capacitor 8, injecte aussi des variables --safe-area-inset-* pour les anciennes WebView.

Clavier. Sur iOS, le plugin Keyboard choisit comment l'app se redimensionne (native, body ou none). Le mode native modifie les unités vh : testez les formulaires en bas d'écran.

Icônes et écran de lancement. npx capacitor-assets generate produit toutes les tailles à partir d'icônes d'au moins 1024 × 1024 px et d'écrans d'au moins 2732 × 2732 px, selon la documentation.

Textes de permission iOS. Chaque accès à la caméra, aux photos ou à la localisation demande un texte dans Info.plist. Selon Apple, sans ce texte l'accès échoue et peut faire planter l'app :

<key>NSCameraUsageDescription</key>
<string>Prendre en photo vos justificatifs pour les joindre à votre dossier.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choisir une photo existante à joindre à votre dossier.</string>

La règle 5.1.1(ii) des App Review Guidelines demande que ces textes décrivent clairement et complètement l'usage des données : évitez « pour l'app ».

Comment publier une app Vue sur l'App Store et Google Play ?

Pour publier une app Vue construite avec Capacitor, on signe les projets natifs dans Xcode et Android Studio, puis on les soumet via App Store Connect et la Google Play Console. À la date d'octobre 2026, Apple exige Xcode 26 et le SDK iOS 26 depuis le 28 avril 2026 (Apple Developer), et Google Play une cible Android 16 (API 36) depuis le 31 août 2026 (Android Developers) ; Capacitor 8 cible déjà l'API 36.

Le principal risque n'est pas technique. Si l'app ne fait que reproduire le site, Apple peut la refuser au titre de la règle 4.2 « Minimum Functionality », qui demande d'aller au-delà d'un site web reconditionné. Nous détaillons ce refus dans notre article sur le refus Apple 4.2 Minimum Functionality. Avant la première soumission, vérifiez au minimum :

  • une navigation mobile (barre d'onglets, bouton retour cohérent), sans menu ni pied de page web ;
  • quelques fonctions natives réellement utiles : notifications, caméra, connexion biométrique, données consultables hors connexion ;
  • un écran clair en l'absence de réseau ;
  • la suppression de compte depuis l'app si l'app permet d'en créer un (règle 5.1.1(v)) ;
  • un compte de démonstration pour l'équipe de revue d'Apple.

Capacitor ou React Native pour une équipe Vue ?

Pour une équipe Vue qui a déjà une application web fonctionnelle, Capacitor est en général le choix le plus direct : il réutilise le code, les compétences et souvent les écrans. React Native impose d'apprendre React et de réécrire l'interface avec des composants natifs. Ce coût se justifie surtout quand l'app mobile a des besoins que la WebView couvre mal : animations très exigeantes, listes très longues, usage intensif du natif, ou une interface mobile très différente du site. Le bon choix dépend de la maturité de votre app web et de ce que l'app mobile doit faire de plus.

Se faire accompagner pour transformer votre app Vue ou Nuxt

GUIGUI Tech propose la Transformation site → app mobile (Capacitor) à partir de 8 500€ HT, en 3 à 6 semaines : votre app Vue, Nuxt (en mode SPA/SSG), React ou Next.js transformée en app iOS et Android, avec icônes, écran de lancement, configuration et soumission sur l'App Store et Google Play. Si votre app existe déjà sous Cordova ou Ionic, voyez la Migration Cordova / Ionic vers Capacitor, à partir de 9 500€ HT. Si Apple a déjà refusé votre app, l'offre App refusée par Apple : on la débloque commence par un diagnostic à 500€ HT, réalisé en 2 jours ouvrés.

Questions fréquentes

Peut-on transformer une application Vue.js en application mobile ?
Oui. Capacitor embarque le build d'une application Vue.js dans une vraie application iOS et Android, publiable sur l'App Store et Google Play. Le code Vue est conservé, et les fonctions du téléphone (caméra, notifications, stockage) sont accessibles via des plugins appelés en JavaScript.
Capacitor fonctionne-t-il avec Nuxt ?
Oui, si Nuxt produit un build statique. Il faut générer l'app avec nuxt generate, idéalement avec ssr: false, et indiquer .output/public comme webDir de Capacitor. Les routes serveur de Nuxt ne sont pas incluses dans ce build et doivent être hébergées ailleurs.
Quel webDir utiliser pour Capacitor avec Vue et Vite ?
Pour un projet Vue 3 construit avec Vite, le webDir de Capacitor est dist, le dossier de sortie par défaut de Vite. Pour Nuxt en génération statique, c'est .output/public. Ce dossier doit contenir le fichier index.html final.
Faut-il passer Vue Router en mode hash pour Capacitor ?
En général non. Le mode history de Vue Router (createWebHistory) fonctionne dans une app Capacitor, et l'exemple Vue de la documentation Capacitor sur les deep links utilise router.push avec un chemin classique. Le mode hash reste une solution de repli.
Quelles versions de Node et Xcode faut-il pour Capacitor en octobre 2026 ?
À la date d'octobre 2026, Capacitor 8, version stable, demande Node.js 22 ou plus, Xcode 26.0 ou plus et Android Studio 2025.2.1 ou plus, avec une cible minimale iOS 15.0 et Android API 24. Ionic annonce Capacitor 9 pour fin novembre 2026.
Une app Vue emballée avec Capacitor peut-elle être refusée par Apple ?
Oui, si elle se contente de reproduire le site web : Apple peut alors la refuser au titre de la règle 4.2 « Minimum Functionality ». Capacitor n'est pas visé en tant que tel ; l'app doit apporter des fonctions et une ergonomie propres au mobile.

Besoin d'aide sur ce sujet ?

Transformation Site → App Mobile (Capacitor)

À partir de 8 500€ HT3 à 6 semaines

Votre site React, Next.js ou Vue.js transformé en vraie application iOS et Android, installable depuis les stores. Une expertise Capacitor éprouvée en production.

En savoir plus →

Autres articles

Mon app Lovable devient lente ou instable : quand faut-il en sortir ?

App Lovable lente, bugs à chaque modification, doutes sur la sécurité : les vraies causes, ce qui se corrige sans quitter Lovable et quand reprendre le code.

Lire la suite

App Lovable refusée par Apple : les 5 raisons les plus fréquentes (et comment les corriger)

App Lovable refusée par l'App Store ? Les 5 motifs de refus Apple les plus fréquents (4.2, 2.1, 5.1.1(v), 4.8, 3.1.1), comment les corriger et resoumettre.

Lire la suite

Parlez-nous de votre projet

Notre siège

  • France
    1 RUE DE STOCKHOLM
    75008, PARIS