Saltar al contenido principal
Tutorial

Creando apps móviles con SvelteKit y Capacitor

Aprende a crear una app móvil con SvelteKit, Capacitor y mejora la Capgo navegación nativa, transiciones y mejores prácticas de diseño en iOS.

Creando apps móviles con SvelteKit y Capacitor

En este tutorial, empezaremos con una nueva SvelteKit app y pasaremos al desarrollo móvil nativo usando Capacitor. También puedes añadir Capgo Native Navigation and Transitions para una sensación nativa, y usar tailwind-capacitor para las safe areas.

Capacitor te permite convertir fácilmente tu aplicación web de SvelteKit en una app móvil nativa sin necesidad de modificaciones importantes ni de aprender una nueva tecnología como React Native.

Sigue esta guía paso a paso para transformar tu app de SvelteKit en una app móvil usando Capacitor, con Capgo Native Navigation, transiciones y guía de diseño para iOS opcionales.

Acerca de Capacitor

¡CapacitorJS lo cambia todo! Se integra sin esfuerzo en cualquier proyecto web, envolviendo tu aplicación en una webview nativa y generando proyectos de Xcode y Android Studio. Sus plugins permiten acceder a funciones nativas como la cámara mediante un bridge de JavaScript.

Con Capacitor puedes crear una app móvil nativa increíble sin configuraciones complicadas ni curvas de aprendizaje pronunciadas. Su ligero API y su funcionalidad optimizada facilitan la integración. ¡Te sorprenderá lo fácil que es lograr una app nativa funcional con Capacitor!

Preparando tu app de SvelteKit

Para crear una nueva app de SvelteKit, ejecuta el siguiente comando:

npm create svelte@latest my-app
cd my-app
npm install
npm run build

Tras ejecutar el comando build deberías ver una nueva dist carpeta en la raíz de tu proyecto.

Esta carpeta la usará Capacitor más adelante, pero por ahora debemos configurarla correctamente.

Añadiendo Capacitor a tu app de SvelteKit

Para empaquetar cualquier web app en un contenedor móvil nativo, debemos seguir unos pasos iniciales. Después, es tan simple como ejecutar un solo sync comando.

Primero, instala el Capacitor CLI como una dependencia de desarrollo y configúrala en tu proyecto. Durante la instalación, puedes pulsar “enter” para aceptar los valores por defecto de nombre y bundle ID.

A continuación, instala el paquete core y los paquetes necesarios para las plataformas iOS y Android.

Por último, añade las plataformas y Capacitor creará carpetas para cada plataforma en la raíz de tu proyecto:

# Install the Capacitor CLI locally
npm install -D @capacitor/cli

# Initialize Capacitor in your SvelteKit project
npx cap init

# Install the required packages
npm install @capacitor/core @capacitor/ios @capacitor/android

# Add the native platforms
npx cap add ios
npx cap add android

En este punto, deberías ver nuevas ios y Android carpetas en tu proyecto de SvelteKit.

¡Son proyectos nativos reales!

Para acceder al proyecto de Android más tarde, necesitas instalar Android Studio. Para iOS, necesitas un Mac y debes instalar Xcode.

Además, deberías encontrar un capacitor.config.ts en tu proyecto, que contiene algunos ajustes básicos de Capacitor usados durante la sincronización. Lo único a lo que debes prestar atención es a webDir, que debe apuntar al resultado de tu comando de build. Actualmente, es incorrecto.

Para solucionar esto, abre el capacitor.config.ts y actualiza el webDir:

import { CapacitorConfig } from '@capacitor/cli'

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'build',
}

export default config

Ahora que hemos actualizado la configuración de Capacitor, vamos a convertir nuestro proyecto de SvelteKit en una aplicación estática descargando el paquete del adaptador estático adecuado:

npm i -D @sveltejs/adapter-static

Una vez instalado el paquete, tendremos que modificar el svelte.config.js archivo, pasando del auto-adaptador al estático:

import adapter from '@sveltejs/adapter-static'
import { vitePreprocess } from '@sveltejs/kit/vite'

/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
  preprocess: vitePreprocess(),

  kit: {
    // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
    // If your environment is not supported or you settled on a specific environment, switch out the adapter.
    // See https://kit.svelte.dev/docs/adapters for more information about adapters.
    adapter: adapter({
      // default options are shown. On some platforms
      // these options are set automatically — see below
      pages: 'build',
      assets: 'build',
      fallback: null,
      precompress: false,
      strict: true
    })
  }
}

export default config

Con el svelte.config.js actualizado, tendremos que añadir una prerender opción creando un +layout.js archivo para src/routes y solo añade el siguiente export a +layout.js:

export const prerender = true

Tras añadir y actualizar la +layout.js página, tendremos que añadir nuestras plataformas móviles y recompilar el proyecto para crear la build carpeta

Puedes hacerlo ejecutando los siguientes comandos:

npm run build
npx cap sync

El primer comando npm run build compilará tu proyecto SvelteKit y copiará la build estática, mientras que el segundo comando npx cap sync sincronizará todos los code web en los lugares correctos de las plataformas nativas para que se muestren en una app.

Además, el comando sync podría actualizar las plataformas nativas e instalar plugins, así que al instalar un nuevo plugins de Capacitor, es momento de ejecutar npx cap sync de nuevo.

¡Sin darte cuenta, ya has completado el proceso! ¡Vamos a ver la app en un dispositivo!

Build y deploy de apps nativas

Para desarrollar apps de iOS, necesitas tener Xcode instalado, y para apps de Android, necesitas tener Android Studio instalado. Además, si planeas distribuir tu app en la tienda de apps, debes inscribirte en el Apple Developer Program para iOS y en la Google Play Console para Android.

Si eres nuevo en el desarrollo móvil nativo, puedes usar el Capacitor CLI para abrir ambos proyectos nativos fácilmente:

npx cap open ios
npx cap open android

Una vez configurados tus proyectos nativos, desplegar tu app en un dispositivo conectado es fácil. En Android Studio, solo debes esperar a que todo esté listo y podrás desplegar tu app sin cambiar ningún ajuste. Aquí tienes un ejemplo:

android-studio-run

En Xcode, debes configurar tu cuenta de firma para desplegar la app en un dispositivo real en lugar de solo en el simulador. Si no lo has hecho antes, Xcode te guía en el proceso (pero recuerda que debes estar inscrito en el Developer Program). Después, solo tienes que darle al play para ejecutar la app en tu dispositivo conectado, que puedes seleccionar arriba. Aquí tienes un ejemplo:

xcode-run

¡Felicidades! Has desplegado con éxito tu web app de SvelteKit en un dispositivo móvil. Aquí tienes un ejemplo:

sveltekit-mobile-app

Pero espera, también hay una forma más rápida de hacer esto durante el desarrollo…

Live Reload con Capacitor

A estas alturas, probablemente estés acostumbrado al hot reload de todos los frameworks modernos, y la buena noticia es que puedes tener la misma funcionalidad en un dispositivo móvil ¡con el mínimo esfuerzo!

Habilita el acceso a tu aplicación alojada localmente con live reload on your network haciendo que la app Capacitor cargue el contenido desde la URL específica.

El primer paso es averiguar tu IP local. Si usas Mac, puedes encontrarla ejecutando este comando en la terminal:

ipconfig getifaddr en0

En Windows, ejecuta:

ipconfig

Luego busca la dirección IPv4.

Podemos indicar a Capacitor que cargue la app directamente desde el servidor añadiendo otra entrada a nuestro capacitor.config.ts archivo:

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

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'my-app',
  webDir: 'dist',
  bundledWebRuntime: false,
  server: {
    url: 'http://192.168.x.xx:3000',
    cleartext: true
  }
};

export default config;

Asegúrate de usar la IP y el puerto correctos, como se muestra en el ejemplo anterior.

Ahora podemos aplicar estos cambios copiándolos a nuestro proyecto nativo:

npx cap copy

El copy el comando es similar a sync, pero solo podrá copiará los cambios realizados en la carpeta web y la configuración, sin actualizar el proyecto nativo.

Ahora puedes desplegar tu app una vez más mediante Android Studio o Xcode. Después de eso, si cambias algo en tu app de Svelte, la app se recargará automáticamente ¡y mostrará los cambios!

Ten en cuenta que si instalas nuevos plugins como la cámara, seguirás necesitando un rebuild de tu proyecto nativo. Esto se debe a que se modifican archivos nativos y no se puede hacer sobre la marcha.

Nota que debes usar la IP y el puerto correctos en tu configuración. El bloque code de arriba muestra el puerto por defecto de SvelteKit para fines demostrativos.

Uso de Capacitor Plugins

Veamos cómo funciona un plugin Capacitor en acción, como hemos mencionado antes. Para ello, podemos instalar un plugin sencillo ejecutando:

npm i @capacitor/share

No hay nada especial en el plugin Shareno tiene nada de especial, ¡pero abre el diálogo nativo de compartir! Para esto, ahora solo necesitamos importar el paquete y llamar a la share() función desde nuestra app, así que cambiemos src/routes/index.svelte a esto:

<script>
  import { Share } from '@capacitor/share';

  async function share() {
    await Share.share({
      title: 'Open Youtube',
      text: 'Check new video on youtube',
      url: 'https://www.youtube.com',
      dialogTitle: 'Share with friends'
    });
  }
</script>

<h1>Welcome to SvelteKit and Capacitor!</h1>
<button on:click={share}>Share now!</button>

Como mencionamos antes, al instalar nuevos plugins, debemos hacer un sync y luego volver a desplegar la app en nuestro dispositivo. Para ello, ejecuta el siguiente comando:

npx cap sync

¡Tras pulsar el botón, podrás ver el magnífico diálogo nativo de compartir en acción!

Después, puedes hacer que la app se sienta más nativa en iOS y Android con la navegación y las transiciones de Capgo, y solucionar problemas comunes de layout en iOS que causan desbordamiento horizontal o áreas seguras recortadas.

UI con sensación nativa, navegación y transiciones nativas de Capgo

He trabajado durante años con Ionic para crear aplicaciones multiplataforma, pero integrarlo con SvelteKit es complejo y rara vez vale la pena si ya usas Tailwind CSS.

Para lograr una sensación nativa en una app de SvelteKit + Capacitor, usa plugins de Capgo en lugar de UI kits solo web como Konsta UI:

  • @capgo/capacitor-native-navigation — navbar nativa, Liquid Glass tab bar en iOS y un estilo de tab bar con desenfoque en Android. El router de SvelteKit gestiona el estado de las rutas; el plugin controla el chrome nativo.
  • @capgo/capacitor-transitions — transiciones de página estilo Ionic y swipe-back desde el borde en iOS en la capa WebView, sin adoptar Ionic UI.

Instala ambos:

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

Configura la navegación nativa con CSS inset mode para que el contenido web respete las barras nativas:

import { NativeNavigation } from '@capgo/capacitor-native-navigation';

await NativeNavigation.configure({
  contentInsetMode: 'css',
  animationDuration: 360,
  glass: {
    effect: 'liquidGlass',
  },
});

Renderiza una tab bar Liquid Glass (iOS usa renderizado del sistema; Android usa un fondo WebView con desenfoque):

await NativeNavigation.setTabbar({
  selectedId: 'home',
  labelVisibilityMode: 'labeled',
  icons: true,
  colors: { dynamic: true },
  tabs: [
    { id: 'home', title: 'Home', icon: { svg: '...' } },
    { id: 'settings', title: 'Settings', icon: { svg: '...' } },
  ],
});

await NativeNavigation.addListener('tabSelect', ({ id }) => {
  goto(`/${id}`);
});

Añade transiciones de página nativas en tu app shell:

<script>
  import { goto } from '$app/navigation';
  import { routerOutlet, page, setDirection } from '@capgo/capacitor-transitions/svelte';
  import '@capgo/capacitor-transitions';

  function openSettings() {
    setDirection('forward');
    goto('/settings');
  }
</script>

<cap-router-outlet use:routerOutlet>
  <cap-page use:page>
    <cap-content slot="content">
      <slot />
    </cap-content>
  </cap-page>
</cap-router-outlet>

Envuelve las páginas enrutadas en cap-router-outlet, cap-page, y cap-content, y llama a setDirection('forward') o setDirection('back') antes de navegar. No dupliques headers o footers web si la navegación nativa ya gestiona esas áreas.

Consulta las guías completas: Uso de @capgo/capacitor-native-navigation y Uso de @capgo/capacitor-transitions.

Safe areas con Tailwind

Para las safe areas del dispositivo en Tailwind CSS, usa @capgo/tailwind-capacitor (publicado como tailwind-capacitor en npm). Proporciona safe-areas utilidades y otros plugins de Tailwind compatibles con Capacitor:

bun add -D tailwind-capacitor

En src/app.css:

@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";

Usa utilidades como pt-safe, pb-safe, y px-safe en lugar de añadir env(safe-area-inset-*) a mano. El proyecto se desarrolla activamente; si falta algo para tu setup de SvelteKit, abre un PR en GitHub.

Cómo solucionar problemas de layout en iOS (viewport, safe area y overflow horizontal)

Si el contenido se ve recortado, desplazado o con scroll horizontal en iOS, añadir más overflow-x: hidden o ajustar solo la etiqueta viewport no suele solucionarlo. Revisa estas comprobaciones en orden.

Asegúrate de que la meta tag viewport esté bien aplicada

En src/app.html, configura la etiqueta meta viewport en <head>:

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />

Gestiona el safe area de iOS desde un único wrapper raíz

Crea un único app shell y aplica el padding de safe area ahí, no en múltiples componentes anidados:

html,
body,
body {
  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);
}

Envuelve todo el contenido de la página dentro de .app-shell. El padding de safe-area duplicado en headers, modales y wrappers de layout suele hacer que la UI parezca recortada o demasiado grande.

Con @capgo/tailwind-capacitor, puedes aplicar el mismo padding usando utilidades como pt-safe pb-safe px-safe en ese único shell.

Configura Capacitor iOS contentInset a never primero

En capacitor.config.ts, prefiere desactivar el inset nativo y dejar que CSS (o la navegación nativa) contentInsetMode: 'css') se encargue del safe area:

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

Combinar el content inset automático de Capacitor con CSS env(safe-area-inset-*) es una causa común de espaciado doble.

Encuentra el elemento que realmente desborda

El culpable habitual es un elemento que usa 100vw, Tailwind w-screen, un ancho fijo en píxeles, o un min-width.

En Safari Web Inspector, ejecuta:

[...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,
  }));

Con Tailwind, reemplaza w-screen con w-full siempre que sea posible. Muchos problemas de desbordamiento horizontal vienen de 100vw / w-screen, padding de safe-area duplicado o un contenedor de ancho fijo, no del propio meta tag del viewport.

Conclusión

Capacitor es una opción excelente para crear aplicaciones nativas a partir de un proyecto web existente, ya que ofrece una forma sencilla de compartir code y mantener una UI consistente.

Y con la incorporación de Capgo, es aún más fácil añadir live updates a tu app, asegurando que tus usuarios siempre tengan acceso a las últimas funciones y correcciones de errores.

Si quieres aprender cómo añadir Capgo a tu app de SvelteKit, echa un vistazo al siguiente artículo:

Descubre cómo Capgo puede ayudarte a crear mejores apps más rápido: crea una cuenta gratis hoy.

Continúa desde Building Mobile Apps with SvelteKit and Capacitor

Si estás usando Creando apps móviles con SvelteKit y Capacitor para planificar la automatización de CI/CD, conéctalo con CI/CD de Capgo para el flujo de trabajo del producto en Capgo CI/CD, Native Builds de Capgo para el flujo de trabajo del producto en Capgo Native Builds, Integraciones de Capgo para el flujo de trabajo del producto en Capgo Integraciones, Integración CI/CD para los detalles de implementación de CI/CD Integration, y Integración con GitHub Actions para los detalles de implementación de GitHub Actions Integration.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.