Loading...
Loading...
Guide for integrating modern web frameworks with Capacitor. Covers Next.js static export, React, Vue, Angular, Svelte, and others. Use this skill when converting framework apps to mobile apps with Capacitor.
npx skill4agent add cap-go/capgo-skills framework-to-capacitor| Framework | Static Export | SSR Support | Recommended Approach |
|---|---|---|---|
| Next.js | ✅ Yes | ❌ No | Static export (output: 'export') |
| React | ✅ Yes | N/A | Create React App or Vite |
| Vue | ✅ Yes | ❌ No | Vite or Vue CLI |
| Angular | ✅ Yes | ❌ No | Angular CLI |
| Svelte | ✅ Yes | ❌ No | SvelteKit with adapter-static |
| Remix | ✅ Yes | ❌ No | SPA mode |
| Solid | ✅ Yes | ❌ No | Vite |
| Qwik | ✅ Yes | ❌ No | Static site mode |
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
images: {
unoptimized: true, // Required for static export
},
trailingSlash: true, // Helps with routing on mobile
};
module.exports = nextConfig;// next.config.js
module.exports = {
output: 'export',
images: {
unoptimized: true,
},
trailingSlash: true,
};bun run buildout/bun add @capacitor/core @capacitor/cli
bunx cap initoutimport type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'out', // Next.js static export directory
server: {
androidScheme: 'https',
},
};
export default config;bun add @capacitor/ios @capacitor/android
bunx cap add ios
bunx cap add android# Build Next.js
bun run build
# Sync with native projects
bunx cap syncbunx cap open ios
# Build and run in Xcodebunx cap open android
# Build and run in Android Studio// next.config.js
const nextConfig = {
output: 'export',
basePath: '',
assetPrefix: '',
};trailingSlash: true// Instead of next/image
<img src="/images/photo.jpg" alt="Photo" />// components/CapacitorImage.tsx
import { Capacitor } from '@capacitor/core';
export const CapacitorImage = ({ src, alt, ...props }) => {
const isNative = Capacitor.isNativePlatform();
const imageSrc = isNative ? src : src;
return <img src={imageSrc} alt={alt} {...props} />;
};@capacitor/preferencesimport { Preferences } from '@capacitor/preferences';
// Save data
await Preferences.set({
key: 'user',
value: JSON.stringify(userData),
});
// Load data
const { value } = await Preferences.get({ key: 'user' });
const userData = JSON.parse(value || '{}');// In your React components
import { useEffect } from 'react';
import { useRouter } from 'next/router';
export default function ProtectedPage() {
const router = useRouter();
useEffect(() => {
const checkAuth = async () => {
const { value } = await Preferences.get({ key: 'token' });
if (!value) {
router.push('/login');
}
};
checkAuth();
}, []);
return <div>Protected content</div>;
}{
"name": "my-capacitor-app",
"scripts": {
"dev": "next dev",
"build": "next build",
"build:mobile": "next build && cap sync",
"ios": "cap open ios",
"android": "cap open android"
},
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@capacitor/core": "^6.0.0",
"@capacitor/ios": "^6.0.0",
"@capacitor/android": "^6.0.0",
"@capacitor/camera": "^6.0.0"
},
"devDependencies": {
"@capacitor/cli": "^6.0.0",
"typescript": "^5.0.0"
}
}bun create vite my-app --template react-ts
cd my-app
bun installbun add @capacitor/core @capacitor/cli
bunx cap initimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
outDir: 'dist', // Capacitor webDir
},
});import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist',
};
export default config;bun add @capacitor/ios @capacitor/android
bunx cap add ios
bunx cap add android
bun run build
bunx cap syncbunx create-react-app my-app --template typescript
cd my-appbun add @capacitor/core @capacitor/cli
bunx cap initconst config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'build', // CRA outputs to build/
};bun run build
bunx cap syncimport { HashRouter as Router, Routes, Route } from 'react-router-dom';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Router>
);
}bun create vite my-app --template vue-ts
cd my-app
bun installbun add @capacitor/core @capacitor/cli
bunx cap initimport { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
outDir: 'dist',
},
});const config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist',
};bun add @capacitor/ios @capacitor/android
bunx cap add ios
bunx cap add android
bun run build
bunx cap sync// router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router';
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
],
});
export default router;bunx @angular/cli new my-app
cd my-appbun add @capacitor/core @capacitor/cli
bunx cap initconst config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist/my-app/browser', // Angular 17+ output
};webDir: 'dist/my-app',bun add @capacitor/ios @capacitor/android
bunx cap add ios
bunx cap add android
bun run build
bunx cap sync// app.config.ts (Angular 17+)
import { provideRouter, withHashLocation } from '@angular/router';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, withHashLocation()),
],
};// app.module.ts
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
@NgModule({
providers: [
{ provide: LocationStrategy, useClass: HashLocationStrategy }
],
})
export class AppModule {}bunx create-svelte my-app
cd my-app
bun installbun add -D @sveltejs/adapter-staticimport adapter from '@sveltejs/adapter-static';
const config = {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: 'index.html',
}),
},
};
export default config;bun add @capacitor/core @capacitor/cli
bunx cap initconst config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'build',
};bun run build
bunx cap syncbun create vite my-app --template svelte-ts
cd my-app
bun installbun add @capacitor/core @capacitor/cli
bunx cap initconst config: CapacitorConfig = {
appId: 'com.company.app',
appName: 'My App',
webDir: 'dist',
};import { Capacitor } from '@capacitor/core';
const isNative = Capacitor.isNativePlatform();
const platform = Capacitor.getPlatform(); // 'ios', 'android', or 'web'
if (isNative) {
// Use native plugins
} else {
// Use web APIs
}import { App } from '@capacitor/app';
App.addListener('appUrlOpen', (data) => {
// Handle deep link
const slug = data.url.split('.app').pop();
// Navigate to route
});bun add @capgo/capacitor-updaterimport { CapacitorUpdater } from '@capgo/capacitor-updater';
// Check for updates
const { id } = await CapacitorUpdater.download({
url: 'https://api.capgo.app/updates',
});
// Apply update
await CapacitorUpdater.set({ id });bun add @ionic/corebun add @ionic/react @ionic/react-routerbun add @ionic/vue @ionic/vue-routerbun add @ionic/angularimport { Preferences } from '@capacitor/preferences';
// Set value
await Preferences.set({ key: 'theme', value: 'dark' });
// Get value
const { value } = await Preferences.get({ key: 'theme' });
// Remove value
await Preferences.remove({ key: 'theme' });
// Clear all
await Preferences.clear();import { Camera, CameraResultType } from '@capacitor/camera';
const photo = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri,
});
const imageUrl = photo.webPath;{
"scripts": {
"dev": "vite", // or next dev, ng serve, etc.
"build": "vite build", // or next build, ng build, etc.
"build:mobile": "vite build && cap sync",
"ios": "cap run ios",
"android": "cap run android",
"sync": "cap sync"
}
}#/about/aboutwebDirwebDirbun run buildbunx cap syncHashRoutercreateWebHashHistory()HashLocationStrategyNEXT_PUBLIC_VITE_REACT_APP_environment.tsimport { CapacitorHttp } from '@capacitor/core';
const response = await CapacitorHttp.get({
url: 'https://api.example.com/data',
});ionic-designkonsta-uioutput: 'export'webDirionic-designkonsta-ui