Aller au contenu principal
Tutoriel

Créer une application mobile Nuxt de zéro avec Capacitor 8

Guide pas à pas pour créer un nouveau projet Nuxt 4 et le transformer en applications mobiles natives iOS et Android avec Capacitor 8. Idéal pour démarrer une développement Vue mobile-first.

Créer une application mobile Nuxt de A à Z avec Capacitor 8 Capgo illustration du blog

Introduction

Vous voulez créer une application mobile avec Nuxt en partant de zéro ? Ce guide vous montre comment créer un nouveau projet Nuxt 4 configuré pour le mobile dès le départ, puis le packager en applications natives iOS et Android avec Capacitor 8.

À la fin de ce tutoriel, vous aurez une application mobile fonctionnelle qui tourne sur les simulateurs, que vous pourrez continuer à développer et finir par publier sur l'App Store et Google Play.

Temps requis : ~30 minutes

Ce que vous allez créer :

  • Un nouveau projet Nuxt 4 avec la dernière structure de dossiers
  • Configuration de génération statique pour le mobile
  • Capacitor 8 avec les plugins essentiels
  • Des apps natives iOS et Android
  • Configuration de développement avec live reload

Vous avez déjà une app Nuxt ? Découvrez Convertir votre app Nuxt en mobile plutôt.

Prerequisites

Assurez-vous d’avoir installé :

  • Node.js 18+ (vérifiez avec node --version)
  • Bun gestionnaire de paquets (curl -fsSL https://bun.sh/install | bash)
  • Xcode (macOS uniquement, pour le développement iOS)
  • Android Studio (pour le développement Android)

Étape 1 : créer un nouveau projet Nuxt 4

Commencez par créer un nouveau projet Nuxt 4 :

bunx nuxi@latest init my-mobile-app
cd my-mobile-app
bun install

Structure du répertoire Nuxt 4

Nuxt 4 utilise une nouvelle structure de répertoires avec le code de l'app dans le app/ répertoire :

my-mobile-app/
  app/
    assets/
    components/
    composables/
    layouts/
    middleware/
    pages/
    plugins/
    utils/
    app.vue
  public/
  server/
  nuxt.config.ts
  package.json

Cette structure permet une meilleure séparation entre l'application et le serveur code.

Étape 2 : Configurer Nuxt pour la génération statique

Capacitor nécessite des fichiers HTML/JS/CSS statiques. Configurez Nuxt pour la génération statique dans nuxt.config.ts:

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  // Enable static generation
  ssr: true,
  nitro: {
    preset: 'static',
  },
});

Étape 3 : Ajouter les scripts mobiles

Mettez à jour votre package.json avec les scripts de développement mobile :

{
  "scripts": {
    "dev": "nuxt dev",
    "build": "nuxt build",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "mobile": "bun run generate && bunx cap sync",
    "mobile:ios": "bun run mobile && bunx cap open ios",
    "mobile:android": "bun run mobile && bunx cap open android"
  }
}

Testez la génération statique :

bun run generate

Vous devriez voir un .output/public répertoire contenant vos fichiers statiques.

Étape 4 : Installer Capacitor 8

Installez les packages core Capacitor :

bun add @capacitor/core
bun add -D @capacitor/cli

Installez les plugins essentiels à la plupart des apps mobiles :

bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences

Rôle de ces plugins :

  • @capacitor/app — Événements du cycle de vie (premier plan/arrière-plan, deep links)
  • @capacitor/keyboard — Contrôle du comportement du clavier
  • @capacitor/splash-screen — Contrôle du splash screen natif
  • @capacitor/status-bar — Personnaliser la barre d'état de l'appareil
  • @capacitor/preferences — Stockage clé-valeur (comme localStorage mais natif)

Étape 5 : Initialiser Capacitor

Initialisez Capacitor avec les détails de votre projet :

bunx cap init "My Mobile App" com.example.mymobileapp --web-dir .output/public

Remplacer :

  • "My Mobile App" par le nom d’affichage de votre application
  • com.example.mymobileapp par l’ID de votre application (notation de domaine inversée)

Cela crée capacitor.config.ts. Mettez-l’à jour avec la configuration du plugin :

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

const config: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  plugins: {
    SplashScreen: {
      launchShowDuration: 2000,
      launchAutoHide: true,
      androidScaleType: 'CENTER_CROP',
      splashFullScreen: true,
      splashImmersive: true,
    },
    Keyboard: {
      resize: 'body',
      resizeOnFullScreen: true,
    },
    StatusBar: {
      style: 'dark',
    },
  },
};

export default config;

Étape 6 : Ajouter les plateformes natives

Installer les packages de plateforme :

bun add @capacitor/ios @capacitor/android

Générer les projets natifs :

bunx cap add ios
bunx cap add android

Cela crée ios et android les dossiers contenant les projets natifs.

Étape 7 : build et exécution

Compilez votre projet et synchronisez-l’avec les plateformes natives :

bun run mobile

Ouvrir dans le simulateur iOS :

bun run mobile:ios

Ou dans l’émulateur Android :

bun run mobile:android

Dans Xcode (iOS) :

  1. Sélectionnez un simulateur dans le menu déroulant des appareils
  2. Cliquez sur le bouton Play ou appuyez sur Cmd + R

Dans Android Studio :

  1. Attendez que Gradle termine sa synchronisation
  2. Sélectionnez un émulateur dans le menu déroulant des appareils
  3. Cliquez sur le bouton Run ou appuyez sur Shift + F10

Étape 8 : Configurer le live reload

Pour un développement plus rapide, activez le live reload : vos changements s'affichent instantanément sur votre appareil.

  1. Trouvez votre adresse IP locale :
# macOS
ipconfig getifaddr en0

# Windows
ipconfig
  1. Créez une config de développement Capacitor. Mettez à jour capacitor.config.ts:
import type { CapacitorConfig } from '@capacitor/cli';

const devConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  server: {
    url: 'http://YOUR_IP_ADDRESS:3000',
    cleartext: true,
  },
  plugins: {
    // ... same plugin config
  },
};

const prodConfig: CapacitorConfig = {
  appId: 'com.example.mymobileapp',
  appName: 'My Mobile App',
  webDir: '.output/public',
  plugins: {
    // ... same plugin config
  },
};

const config = process.env.NODE_ENV === 'development' ? devConfig : prodConfig;

export default config;
  1. Lancez le serveur de dev et copiez la config vers le natif :
bun run dev &
NODE_ENV=development bunx cap copy
  1. Recompilez dans Xcode/Android Studio

Now edits to your Nuxt code will hot-reload on the device.

Étape 9 : Créer votre premier écran mobile

Créons un écran d'accueil optimisé pour le mobile. Mise à jour app/app.vue:

<template>
  <NuxtPage />
</template>

Créer app/pages/index.vue:

<template>
  <main
    class="min-h-screen bg-linear-to-b from-green-500 to-green-700 flex flex-col items-center justify-center p-6 text-white"
  >
    <h1 class="text-4xl font-bold mb-4">My Mobile App</h1>
    <p class="text-xl mb-8 text-center opacity-90">
      Built with Nuxt 4 + Capacitor 8
    </p>

    <div v-if="appInfo" class="bg-white/20 rounded-lg p-4 backdrop-blur-sm mb-8">
      <p class="text-sm">
        {{ appInfo.name }} v{{ appInfo.version }}
      </p>
    </div>

    <div class="space-y-4 w-full max-w-sm">
      <button
        class="w-full py-4 px-6 bg-white text-green-600 rounded-xl font-semibold text-lg shadow-lg active:scale-95 transition-transform"
        @click="handleGetStarted"
      >
        Get Started
      </button>
      <button
        class="w-full py-4 px-6 bg-white/20 text-white rounded-xl font-semibold text-lg backdrop-blur-sm active:scale-95 transition-transform"
        @click="handleShare"
      >
        Share App
      </button>
    </div>
  </main>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';

const appInfo = ref<{ name: string; version: string } | null>(null);

let backButtonListener: { remove: () => void } | null = null;

onMounted(async () => {
  // Get app info
  try {
    appInfo.value = await App.getInfo();
  } catch (e) {
    // Web fallback
    appInfo.value = { name: 'My Mobile App', version: '1.0.0' };
  }

  // Handle Android back button
  backButtonListener = await App.addListener('backButton', ({ canGoBack }) => {
    if (!canGoBack) {
      App.exitApp();
    } else {
      window.history.back();
    }
  });
});

onUnmounted(() => {
  backButtonListener?.remove();
});

function handleGetStarted() {
  // Navigate to onboarding or main app
  console.log('Get started clicked');
}

async function handleShare() {
  // We'll implement this with the Share plugin later
  console.log('Share clicked');
}
</script>

Étape 10 : Ajouter Tailwind CSS

Pour que les styles s'appliquent, ajoutez Tailwind CSS à votre projet :

bun add tailwindcss @tailwindcss/vite

Mise à jour nuxt.config.ts:

import tailwindcss from '@tailwindcss/vite';

export default defineNuxtConfig({
  compatibilityDate: '2025-01-15',
  devtools: { enabled: true },

  ssr: true,
  nitro: {
    preset: 'static',
  },

  css: ['~/assets/css/main.css'],

  vite: {
    plugins: [tailwindcss()],
  },
});

Créer app/assets/css/main.css:

@import 'tailwindcss';

:root {
  --sat: env(safe-area-inset-top);
  --sar: env(safe-area-inset-right);
  --sab: env(safe-area-inset-bottom);
  --sal: env(safe-area-inset-left);
}

body {
  padding-top: var(--sat);
  padding-right: var(--sar);
  padding-bottom: var(--sab);
  padding-left: var(--sal);
}

/* Prevent text selection on mobile */
* {
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

/* Allow text selection in inputs */
input,
textarea {
  -webkit-user-select: auto;
  user-select: auto;
}

Étape 11 : ajouter le plugin Share

Implémentons la fonctionnalité du bouton de partage :

bun add @capacitor/share

Mise à jour app/pages/index.vue pour utiliser le plugin Share :

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { App } from '@capacitor/app';
import { Share } from '@capacitor/share';

// ... existing code ...

async function handleShare() {
  try {
    await Share.share({
      title: 'Check out this app!',
      text: 'Built with Nuxt 4 and Capacitor 8',
      url: 'https://capacitorjs.com',
      dialogTitle: 'Share with friends',
    });
  } catch (e) {
    console.log('Share cancelled or failed:', e);
  }
}
</script>

Synchroniser et recompiler :

bun run mobile

Structure du projet

Votre projet devrait maintenant ressembler à ceci :

my-mobile-app/
├── android/                  # Android native project
├── ios/                      # iOS native project
├── .output/
│   └── public/              # Static build output
├── app/
│   ├── assets/
│   │   └── css/
│   │       └── main.css
│   ├── pages/
│   │   └── index.vue
│   └── app.vue
├── capacitor.config.ts       # Capacitor configuration
├── nuxt.config.ts            # Nuxt configuration
├── package.json
└── ...

Étapes suivantes

Votre application mobile Nuxt est maintenant opérationnelle. Voici la suite :

Configuration essentielle

  • Icônes de l'app : Remplacez les icônes par défaut dans ios/App/App/Assets.xcassets et android/app/src/main/res
  • Écran de démarrage : Personnalisez dans vos projets natifs ou utilisez @capacitor/splash-screen la config
  • Deep Links : Configurez les schémas d'URL de votre app

Ajoutez plus de fonctionnalités

  • Caméra : bun add @capacitor/camera
  • Géolocalisation : bun add @capacitor/geolocation
  • Notifications push : bun add @capacitor/push-notifications ou @capgo/capacitor-firebase-messaging pour Firebase Cloud Messaging sur iOS et Android
  • Système de fichiers : bun add @capacitor/filesystem

UI et transitions natives

Utilisez les plugins Capgo au lieu de Konsta UI pour un rendu mobile natif :

bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync

Pour les zones sûres Tailwind, ajoutez @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

Consultez Utilisation de @capgo/capacitor-native-navigation, Utiliser @capgo/capacitor-transitions, et le le dépôt tailwind-capacitor pour la configuration spécifique à Nuxt.

Corriger les problèmes de mise en page iOS (viewport, zone sécurisée et débordement horizontal)

Si le contenu semble coupé, décalé ou défile horizontalement sur iOS, ajouter plus de overflow-x: hidden ou le simple ajustement de la balise viewport ne règle généralement pas le problème. Effectuez ces vérifications dans l'ordre.

Assurez-vous que la balise meta viewport est correctement appliquée

Dans nuxt.config.ts, configurez le viewport via app.head:

export default defineNuxtConfig({
  app: {
    head: {
      meta: [
        {
          name: 'viewport',
          content: 'width=device-width, initial-scale=1, viewport-fit=cover',
        },
      ],
    },
  },
});

Gérez la safe area iOS depuis un seul wrapper racine

Créez un shell d'application unique et appliquez-y le padding de la safe area — pas dans plusieurs composants imbriqués :

html,
body,
#__nuxt {
  width: 100%;
  min-height: 100%;
  margin: 0;
  padding: 0;
  overflow-x: hidden;
}

* {
  box-sizing: border-box;
}

.app-shell {
  min-height: 100dvh;
  width: 100%;
  padding-top: env(safe-area-inset-top);
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
}

Enveloppez tout le contenu de la page dans .app-shell. Un padding de safe area dupliqué dans les headers, les modales et les wrappers de layout donne souvent l'impression que l'UI est rognée ou trop grande.

Avec @capgo/tailwind-capacitor, vous pouvez obtenir le même padding avec des utilitaires comme pt-safe pb-safe px-safe sur ce shell unique.

Configurez Capacitor iOS contentInset vers never d'abord

Dans capacitor.config.ts, préférez désactiver les insets natifs et laissez le CSS (ou la contentInsetMode: 'css') gèrent la safe area :

const config: CapacitorConfig = {
  appId: 'com.example.myapp',
  appName: 'my-app',
  webDir: '.output/public',
  ios: {
    contentInset: 'never',
  },
};

Combiner le content inset automatique de Capacitor avec le CSS env(safe-area-inset-*) le padding est une cause fréquente de double espacement.

Trouvez l'élément qui déborde réellement

Le coupable habituel est un élément utilisant 100vw, Tailwind w-screen, une largeur fixe en pixels, ou un grand min-width.

Dans le Web Inspector de Safari, lancez :

[...document.querySelectorAll('*')]
  .filter(el => el.scrollWidth > document.documentElement.clientWidth)
  .map(el => ({
    el,
    tag: el.tagName,
    class: el.className,
    scrollWidth: el.scrollWidth,
    clientWidth: document.documentElement.clientWidth,
  }));

Avec Tailwind, remplacez w-screen par w-full dès que possible. De nombreux problèmes de débordement horizontal proviennent de 100vw / w-screen, d'un padding safe-area dupliqué, ou d'un conteneur à largeur fixe — et non de la balise meta viewport elle-même.

Mises à jour OTA

Configuration Capgo pour envoyer des mises à jour sans repasser par le store :

bunx @capgo/cli init

Troubleshooting

Le build échoue avec « Cannot find module » Exécutez bun install et réessayez.

iOS : « No signing identity found » Ouvrez Xcode, allez dans Signing &amp; Capabilities et sélectionnez votre équipe de développement.

Android : « SDK location not found » Créer android/local.properties par sdk.dir=/path/to/android/sdk

Les changements n'apparaissent pas sur l'appareil Assurez-vous d'avoir exécuté bun run mobile après avoir effectué les modifications. Pour le live reload, vérifiez que l'adresse IP est correcte et que le serveur de dev est lancé.

.output/public est vide ou manquant Assurez-vous d'avoir configuré nitro: { preset: 'static' } dans nuxt.config.ts et lancez bun run generate.

Ressources

Prêt à déployer votre app ? Découvrez comment Capgo peut vous aider à livrer des mises à jour plus rapidement — créez un compte gratuit aujourd'hui.

Continuer avec Créer une application mobile Nuxt à partir de zéro avec Capacitor 8

Si vous utilisez Créer une application mobile Nuxt de zéro avec Capacitor 8 pour planifier l'automatisation CI/CD, et le connecter avec CI/CD Capgo pour le workflow produit dans le CI/CD de Capgo, Capgo Native Build pour le workflow produit dans les Native Builds de Capgo, Intégrations Capgo pour le workflow produit dans les intégrations de Capgo, Intégration CI/CD pour le détail d'implémentation dans l'intégration CI/CD, et Intégration GitHub Actions pour les détails d'implémentation de l'intégration GitHub Actions.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.