Aller directement au contenu principal
Guide de tutorat

Build a Nuxt Mobile App from Scratch with Capacitor 8

Step-by-step guide to creating a new Nuxt 4 project and turning it into native iOS and Android mobile apps using Capacitor 8. Perfect for starting fresh with mobile-first Vue development.

Crédits de l'article

Martin Donadieu

Auteur

Valeria

Réviseur

Jordan

Éditeur

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

Introduction

Vous souhaitez créer une application mobile avec Nuxt à partir de zéro ? Ce guide vous accompagne dans la création d'un nouveau projet Nuxt 4 configuré pour la mobilité dès le départ, puis dans l'emballage de celui-ci sous forme d'applications natives iOS et Android à l'aide de Capacitor 8.

À la fin de ce tutoriel, vous disposerez d'une application mobile fonctionnelle exécutée sur des simulateurs que vous pourrez continuer à développer et publier ultérieurement sur l'App Store et Google Play.

Temps requis : ~30 minutes

Ce que vous construirez :

  • Un nouveau projet Nuxt 4 avec la structure de répertoire la plus récente
  • La configuration de la génération statique pour la mobilité
  • Capacitor 8 avec les plugins essentiels
  • Applications iOS et Android natifs
  • Configuration de développement avec rechargement en direct

Avez-vous déjà un application Nuxt ? Consultez Convertir votre application Nuxt en mobile au lieu de cela.

Prérequis

Assurez-vous d'avoir ces éléments installés :

  • Node.js 18+ (vérifiez avec node --version)
  • Bun gestionnaire de packages (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éez un nouveau projet Nuxt 4

Commencez par créer un projet Nuxt 4 frais :

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

Structure de répertoire de Nuxt 4

Nuxt 4 utilise une nouvelle structure de répertoire avec l'application code 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 fournit une meilleure séparation entre l'application et le serveur code.

Étape 2 : Configurez 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 : Ajoutez les scripts mobiles

Mettez à jour votre package.json avec des 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 avec vos fichiers statiques.

Étape 4 : Installez Capacitor 8

Installez les packages de noyau de Capacitor :

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

Installez les plugins essentiels dont la plupart des applications mobiles ont besoin :

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

Ce que font ces plugins :

  • @capacitor/app — Événements de cycle de vie de l'application (avant-plan/arrière-plan, liens profonds)
  • @capacitor/keyboard — Contrôler le comportement de la touche clavier
  • @capacitor/écran d'accueil — Contrôle de l'écran d'accueil natif
  • @capacitor/barre de statut — Personnaliser la barre de statut de l'appareil
  • @capacitor/préférences — Stockage de valeurs clés (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

Remplacez :

  • "My Mobile App" par le nom affiché de votre application
  • com.example.mymobileapp par l'ID de votre application (notation de domaine inversé)

Cela crée capacitor.config.tsMettez à 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 : Ajoutez les plateformes natives

Installez les packages de plateforme :

bun add @capacitor/ios @capacitor/android

Générez les projets natifs :

bunx cap add ios
bunx cap add android

Cela crée ios et android des

répertoires contenant les projets natifs.

Étape 7 : Construire et Exécuter

bun run mobile

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

bun run mobile:ios

Ouvrez dans l'émulateur iOS :

bun run mobile:android

Dans Xcode (iOS) :

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

Dans Android Studio :

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

Étape 8 : Configurer la rechargement en direct

Pour un développement plus rapide, activez le rechargement en direct afin que les modifications apparaissent instantanément sur votre appareil.

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

# Windows
ipconfig
  1. Créez une configuration de développement locale 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. Démarrer le serveur de développement et copiez la configuration vers natif :
bun run dev &
NODE_ENV=development bunx cap copy
  1. Reconstruire dans Xcode/Android Studio

Maintenant, les modifications apportées à votre Nuxt code se refléteront automatiquement sur le dispositif.

Étape 9 : Créez votre première écran mobile

Créer app/app.vue:

<template>
  <NuxtPage />
</template>

Étape 10 : Ajoutez Tailwind CSS 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>

Pour que la mise en forme fonctionne, ajoutez Tailwind CSS à votre projet :

Créer

bun add tailwindcss @tailwindcss/vite

Étape 11 : Ajoutez le plugin de partage 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éons la fonctionnalité du bouton de partage : 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;
}

Créer

Étape 12 : Mettre à jour

bun add @capacitor/share

Étape 12 : Créer app/pages/index.vue pour utiliser le plugin de partage :

<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>

Sync et rebuild :

bun run mobile

Structure du projet

Votre projet devrait 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

Étape suivante

Paramètres essentiels

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

Ajoutez plus de fonctionnalités

  • Caméra : bun add @capacitor/camera
  • Localisation géographique : bun add @capacitor/geolocation
  • Notifications push : bun add @capacitor/push-notifications ou @capgo/capacitor-firebase-messaging @__CAPGO_KEEP_0__/__CAPGO_KEEP_1__-firebase-messaging
  • pour Firebase Cloud Messaging sur iOS et Android bun add @capacitor/filesystem

Système de fichiers :

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

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

Pour les zones de sécurité Tailwind, ajoutez @capgo/tailwind-capacitor:

bun add -D tailwind-capacitor

Voir Utilisation de @capgo/capacitor-native-navigation, Utilisation de @capgo/capacitor-transitions, et le repo tailwind-capacitor pour la configuration spécifique à Nuxt.

Fixer les problèmes de disposition de l'interface iOS (Vueport, Zone de sécurité, et Débordement horizontal)

Si le contenu semble coupé, décalé ou scrollable horizontalement sur iOS, ajouter plus overflow-x: hidden ou ajuster seul le tag de vueport ne résout généralement pas le problème. Effectuez ces vérifications dans l'ordre.

Assurez-vous que le tag de métadonnées de vueport est appliqué correctement

In nuxt.config.ts, définissez la vueport par app.head:

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

Gérer la zone de sécurité iOS à partir d'un seul enveloppe racine

Créez une coquille d'application unique et appliquez-y la mise en forme de la zone de sécurité — et non 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 à l'intérieur de .app-shellLe doublonnement de la mise en forme de la zone de sécurité dans les en-têtes, les modaux et les enveloppes de disposition de l'interface souvent donne l'impression que l'interface est coupée ou trop grande.

Avec @capgo/tailwind-capacitor, vous pouvez exprimer la même marge avec des utilitaires comme pt-safe pb-safe px-safe sur cette seule coquille.

Fixez Capacitor iOS contentInset à never context : Page/zone : Page de produit avec mise à jour en temps réel. Rôle : Étiquette de navigation ou élément UI court. Clé de message `live_update_dynamic_label_to` (Étiquette dynamique de mise à jour en temps réel).

premier capacitor.config.tsDans contentInsetMode: 'css', préférez l'insérer natif désactivé et laissez CSS (ou la navigation native)

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

Mixing Capacitor’s automatic content inset with CSS env(safe-area-inset-*) Mélanger les marges automatiques de contenu de __CAPGO_KEEP_0__ avec CSS

est une cause courante de double espaceage.

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

L'exécution de Safari Web Inspector, exécutez :

[...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 avec w-full lorsque possible. De nombreux problèmes de débordement horizontal proviennent de 100vw / w-screen, une duplication de la marge de sécurité de l'aire sûre, ou d'un conteneur à largeur fixe — et non de la balise meta de la vue portative elle-même.

Les Mises à Jour en Ligne

Configurez Capgo pour envoyer des mises à jour sans résubmission de l'application sur le magasin :

bunx @capgo/cli init

Résolution de problèmes

La construction échoue avec « Cannot find module » Démarrez bun install et essayez à nouveau.

iOS : « Aucune identité de signature trouvée » Ouvrez Xcode, allez dans Signing &amp; Capabilités, et sélectionnez votre équipe de développement.

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

Les modifications ne s'affichent pas sur le dispositif Assurez-vous d'avoir exécuté bun run mobile après avoir apporté des modifications. Pour la rechargement en direct, vérifiez que l'adresse IP est correcte et que le serveur de développement est en cours d'exécution.

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

Ressources

Prêt à livrer votre application ? Découvrez comment Capgo peut vous aider à livrer des mises à jour plus rapidement — inscrivez-vous pour un compte gratuit aujourd'hui.

Continuez de Build a Nuxt Mobile App from Scratch avec Capacitor 8

Si vous utilisez Build a Nuxt Mobile App from Scratch avec Capacitor 8 pour planifier l'automatisation CI/CD, connectez-l’avec Capgo CI/CD pour le flux de travail du produit dans Capgo CI/CD, Capgo Native Builds pour le flux de travail du produit dans Capgo Native Builds, Capgo Integrations for the product workflow in Capgo Integrations, Intégration CI/CD pour les détails d'implémentation dans l'Intégration CI/CD, et GitHub Intégration d'actions pour les détails d'implémentation dans GitHub Intégration d'actions.

Mises à jour instantanées pour les applications Capacitor

Lorsqu'un bug de la couche web est en ligne, expédiez la correction par le biais de Capgo au lieu d'attendre des jours pour l'approbation de la boutique d'applications. Les utilisateurs reçoivent la mise à jour en arrière-plan tandis que les modifications natives restent dans la voie de revue normale.

Support humain de Martin

Démarrer maintenant

Dernières actualités de notre Blog

Capgo vous donne les meilleures informations dont vous avez besoin pour créer une application mobile véritablement professionnelle.