Introduction
Vous souhaitez créer une application mobile avec Nuxt à partir de zéro ? Ce guide vous accompagne dans la création d'une nouvelle application Nuxt 4 configurée pour les appareils mobiles dès le départ, puis la mise en boîte sous forme d'applications natives iOS et Android 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 construisez :
- Une nouvelle application Nuxt 4 avec la structure de répertoire la plus récente
- Configuration de la génération statique pour les appareils mobiles
- Capacitor 8 avec les plugins essentiels
- Applications natives iOS et Android
- Configuration de développement avec rechargement en direct
Déjà une application Nuxt? Vérifiez Convertissez 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 (seulement macOS, 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 projet Nuxt 4 frais :
bunx nuxi@latest init my-mobile-app
cd my-mobile-app
bun install
Structure de répertoire 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 séparation améliorée 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 avec vos fichiers statiques.
Étape 4 : Installez Capacitor 8
Installez les packages de noyau 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ôle du comportement de la touche clavier
- @capacitor/splash-screen — Contrôle de l'écran de démarrage natif
- @capacitor/status-bar — Personnalisez la barre d'état du dispositif
- @capacitor/preferences — Stockage de valeurs clés (comme localStorage mais natif)
Étape 5 : Initialiser Capacitor
Initialisez Capacitor avec vos détails de projet :
bunx cap init "My Mobile App" com.example.mymobileapp --web-dir .output/public
Remplacez :
"My Mobile App"par le nom d'affichage de votre applicationcom.example.mymobileapppar l'ID de votre application (notation de domaine inversé)
Cela crée capacitor.config.ts. Mettez à 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
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 dossiers contenant les projets natifs.
Étape 7 : Construire et Exécuter
Construire votre projet et synchronisez-le avec les plateformes natives :
bun run mobile
Ouvrez dans l'émulateur iOS :
bun run mobile:ios
Ou émulateur Android :
bun run mobile:android
Dans Xcode (iOS) :
- Sélectionnez un émulateur dans le menu déroulant des appareils
- Cliquez sur le bouton Play ou appuyez sur
Cmd + R
Dans Android Studio :
- Attendez que Gradle termine de synchroniser
- Sélectionnez un émulateur dans le menu déroulant des appareils
- Cliquez sur le bouton Exécuter ou appuyez sur
Shift + F10
Étape 8 : Configurez la mise à jour en temps réel
Pour un développement plus rapide, activez la mise à jour en temps réel afin que les modifications apparaissent instantanément sur votre appareil.
- Trouvez votre adresse IP locale :
# macOS
ipconfig getifaddr en0
# Windows
ipconfig
- Créez un fichier de configuration 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;
- Lancez le serveur de développement et copiez la configuration vers natif :
bun run dev &
NODE_ENV=development bunx cap copy
- Rebâtissez dans Xcode/Android Studio
Maintenant, les modifications apportées à votre Nuxt code seront rechargées automatiquement sur l'appareil.
Étape 9 : Créez votre première écran mobile
Créons une page d'accueil mobile. Mettre à 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 le style fonctionne, ajoutez Tailwind CSS à votre projet :
bun add tailwindcss @tailwindcss/vite
Mettre à 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 de partage
Créons la fonctionnalité du bouton de partage :
bun add @capacitor/share
Mettre à jour pour utiliser le plugin de partage : app/pages/index.vue Synchroniser et reconstruire :
<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>
Étape 11 : Ajouter le plugin de partage
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
Vous avez maintenant une application mobile Nuxt fonctionnelle. Voici ce que vous devez faire ensuite :
Configuration essentielle
- Icônes de l'application : Remplacez les icônes par défaut dans
ios/App/App/Assets.xcassetsetandroid/app/src/main/res - Écran de démarrage : Personnalisez dans les projets natifs ou utilisez
@capacitor/splash-screenconfig - Lien profond : Configure les schémas de URL pour votre application
Ajoutez plus de fonctionnalités
- Camera :
bun add @capacitor/camera - Localisation :
bun add @capacitor/geolocation - Notifications push :
bun add @capacitor/push-notificationsou @capgo/capacitor-firebase-messaging pour Firebase Cloud Messaging sur iOS et Android - Système de fichiers :
bun add @capacitor/filesystem
Interface utilisateur native et transitions
Utilisez les plugins Capgo au lieu de Konsta UI pour un sentiment mobile natif :
- @capgo/capacitor-native-navigation — Barre de navigation Liquid Glass et navbar native
- @capgo/capacitor-transitions — Transitions de page ressemblant à celles natives
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-transitionset le repo tailwind-capacitor pour la configuration spécifique à Nuxt.
Résolution des problèmes de mise en page iOS (Vueport, zone de sécurité et débordement horizontal)
If le contenu semble coupé, décalé ou scrollable horizontalement sur iOS, ajouter plus ou ajuster la balise viewport seule ne résout généralement pas le problème. Travaillez à travers ces vérifications dans l'ordre. overflow-x: hidden Assurez-vous que la balise meta viewport est appliquée correctement
En
Configurez la vueport via nuxt.config.tsGérez l'espace sûr d'iOS à partir d'un seul wrapper racine app.head:
export default defineNuxtConfig({
app: {
head: {
meta: [
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, viewport-fit=cover',
},
],
},
},
});
Créez une coquille d'application unique et appliquez la mise en forme de l'espace sûr là-bas — et non dans plusieurs composants imbriqués :
Enveloppez tout le contenu de la page à l'intérieur
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);
}
Le doublonnement de la mise en forme de l'espace sûr dans les en-têtes, les modaux et les enveloppes de mise en page peut rendre l'interface utilisateur coupée ou trop grande. .app-shellAvec
@__CAPGO_KEEP_0__/tailwind-__CAPGO_KEEP_1__ @capgo/tailwind-capacitor__CAPGO_KEEP_0__ pt-safe pb-safe px-safe On cette seule coquille.
Configurez Capacitor iOS contentInset à never premier
En capacitor.config.ts, préférez l'insérer natif désactivé et laissez CSS (ou la navigation native) gérer la zone de sécurité : contentInsetMode: 'css'Mélanger les inscriptions automatiques de contenu de __CAPGO_KEEP_0__ avec la mise en forme CSS
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-*) Trouvez l'élément qui déborde vraiment
L'élément coupable est généralement un élément utilisant
, Tailwind 100vwSet __CAPGO_KEEP_0__ iOS to first w-screenou une largeur fixe, ou une min-width.
En Inspecteur Web Safari, 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 par w-full lorsque possible. De nombreux problèmes d'écoulement horizontal proviennent de 100vw / w-screen, de la mise en forme de la zone de sécurité dupliquée, ou d'un conteneur à largeur fixe — et non de la balise meta de la zone de vue elle-même.
Mises à jour hors ligne
Configurez Capgo pour pousser les mises à jour sans résubmission de l'application sur le magasin :
bunx @capgo/cli init
Résolution des problèmes
Les builds échouent avec « Cannot find module »
Exécutez bun install et essayez à nouveau.
iOS: « Aucune identité de signature trouvée » Ouvrez Xcode, allez dans Signing & Capabilités, et sélectionnez votre équipe de développement.
Android: « Emplacement de SDK non trouvé »
Créez android/local.properties avec sdk.dir=/path/to/android/sdk
Les modifications ne s'affichent pas sur le dispositif
Vérifiez que vous avez exécuté bun run mobile après avoir apporté des modifications. Pour le 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
Vérifiez que vous avez configuré nitro: { preset: 'static' } en nuxt.config.ts et et exécuter bun run generate.
Ressources
- Capacitor 8 Documentation
- Nuxt 4 Documentation
- Capgo - Mises à jour en temps réel
- @capgo/capacitor-navigation native
- @capgo/capacitor-transitions
- @capgo/tailwind-capacitor
Prêt à envoyer votre application ? Découvrez comment Capgo peut vous aider à livrer des mises à jour plus rapidement — s'inscrire à un compte gratuit aujourd'hui.
Continuez à partir de Créez une application mobile Nuxt à partir de zéro avec Capacitor 8
Si vous utilisez Créez une application mobile Nuxt à partir de zéro avec Capacitor 8 pour planifier l'automatisation de CI/CD, connectez-le avec Capgo CI/CD pour le flux de travail du produit dans Capgo CI/CD, Capgo Builds natifs pour le flux de travail du produit dans Capgo Builds natifs, Capgo Intégrations pour le flux de travail du produit dans Capgo Intégrations, Intégration CI/CD pour le détail d'implémentation dans Intégration CI/CD, et Actions d'intégration de GitHub pour les détails d'implémentation dans les actions d'intégration de GitHub