Skip to main content

nextjs-capacitor

Project-agnostic guide for setting up Next.js with Capacitor for native mobile support and Ionic React for UI components. Includes core setup, optional enhancements, and complete push notifications implementation.

소스 정보

저장소
pmarashian/cursor-agent-skills
최근 소스 활동
2026년 2월 13일 19:51
감지된 SKILL.md 언어
영어
스타
2
포크
1

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
nextjs-capacitor
description
Project-agnostic guide for setting up Next.js with Capacitor for native mobile support and Ionic React for UI components. Includes core setup, optional enhancements, and complete push notifications implementation.
# Next.js + Capacitor + Ionic React Setup ## Purpose This skill provides a comprehensive, project-agnostic guide for setting up a Next.js application with Capacitor for native mobile support and Ionic React for UI components. It covers core setup requirements, optional enhancements, and complete push notification implementation. ## When to Use Use this skill when: - Setting up a new Next.js project with Capacitor and Ionic React - Adding Capacitor to an existing Next.js application - Configuring push notifications for a Capacitor app - Troubleshooting Capacitor build or sync issues - Understanding the conditional static export pattern for Next.js + Capacitor ## Architecture Overview ### Project Structure Options You can organize your project in two ways: **Option A: Root-level `src/` directory** (Single app) ``` your-project/ ├── src/ # Next.js frontend at root │ └── app/ ├── backend/ # Optional backend (if monorepo) ├── capacitor.config.ts └── package.json ``` - Capacitor `webDir`: `"dist"` - Common for single-app projects **Option B: Separate `frontend/` directory** (Monorepo) ``` your-project/ ├── frontend/ # Next.js frontend │ └── src/ │ └── app/ ├── backend/ # Backend API ├── capacitor.config.ts └── package.json ``` - Capacitor `webDir`: `"frontend/dist"` - Better for projects with separate frontend/backend ### Key Concepts - **Conditional Static Export**: Next.js only exports statically when `CAPACITOR_BUILD=true`, allowing normal Next.js development - **Capacitor Integration**: Capacitor wraps the static Next.js build into native iOS/Android apps - **Ionic React**: Provides mobile-optimized UI components that work on web and native ## Core Setup Instructions ### Step 1: Create Next.js Project ```bash npx create-next-app@latest . --typescript --app --tailwind --eslint --src-dir ``` When prompted: - Choose **TypeScript** (recommended) - Choose **App Router** (required) - Choose **Tailwind CSS** (optional but recommended) - Choose **ESLint** (recommended) ### Step 2: Install Core Dependencies ```bash # Capacitor Core npm install @capacitor/core @capacitor/cli @capacitor/android @capacitor/ios # Ionic React npm install @ionic/react ionicons # Optional but recommended Capacitor plugins npm install @capacitor/splash-screen @capacitor/status-bar @capacitor/app ``` ### Step 3: Initialize Capacitor ```bash npx cap init ``` When prompted: - **App name**: YourAppName - **App ID**: com.yourcompany.yourapp (use reverse domain notation) - **Web dir**: `dist` (for root `src/`) or `frontend/dist` (for monorepo) This creates `capacitor.config.ts` at the root level. ### Step 4: Configure Capacitor Update `capacitor.config.ts`: ```typescript import type { CapacitorConfig } from "@capacitor/cli"; const config: CapacitorConfig = { appId: "com.yourcompany.yourapp", appName: "YourAppName", webDir: "dist", // or "frontend/dist" for monorepo plugins: { SplashScreen: { launchAutoHide: false, // Control manually for better UX }, StatusBar: { style: "DARK", overlaysWebView: false, backgroundColor: "#000000", }, }, }; export default config; ``` ### Step 5: Configure Next.js Update `next.config.js`: ```javascript /** @type {import('next').NextConfig} */ const nextConfig = { // Only use static export when building for Capacitor ...(process.env.CAPACITOR_BUILD === "true" && { output: "export", images: { unoptimized: true, // Required for static export }, trailingSlash: true, distDir: "dist", // Must match Capacitor's webDir }), transpilePackages: ["@ionic/react", "@ionic/core", "@stencil/core"], eslint: { ignoreDuringBuilds: true, }, typescript: { ignoreBuildErrors: true, }, webpack: (config, { isServer }) => { // Handle Stencil dynamic imports and Node.js polyfills if (!isServer) { config.resolve.fallback = { ...config.resolve.fallback, fs: false, crypto: false, stream: false, util: false, path: false, os: false, tls: false, net: false, dns: false, child_process: false, http: false, https: false, zlib: false, querystring: false, url: false, buffer: false, timers: false, "timers/promises": false, diagnostics_channel: false, }; } // Ignore dynamic import warnings for Stencil config.module = { ...config.module, unknownContextCritical: false, unknownContextRegExp: /^\.\/.*$/, unknownContextRequest: ".", }; return config; }, }; module.exports = nextConfig; ``` **Important**: The conditional static export allows normal Next.js development while enabling Capacitor builds when needed. ### Step 6: Update TypeScript Config Update `tsconfig.json`: ```json { "compilerOptions": { "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "strict": false, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": ["./src/*"] } }, "include": [ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "next-env.d.ts", "dist/types/**/*.ts" ], "exclude": ["node_modules"] } ``` ### Step 7: Create Root Layout Create `src/app/layout.tsx`: ```tsx import type { Metadata } from "next"; import "@ionic/react/css/core.css"; import "@ionic/react/css/normalize.css"; import "@ionic/react/css/structure.css"; import "@ionic/react/css/typography.css"; import "@ionic/react/css/padding.css"; import "@ionic/react/css/float-elements.css"; import "@ionic/react/css/text-alignment.css"; import "@ionic/react/css/text-transformation.css"; import "@ionic/react/css/flex-utils.css"; import "@ionic/react/css/display.css"; import "@ionic/react/css/ionic.bundle.css"; import "@ionic/react/css/palettes/dark.css"; import "./globals.css"; import IonicApp from "./IonicApp"; export const metadata: Metadata = { title: "YourAppName", description: "Your app description", }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <head> <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="format-detection" content="telephone=no" /> <meta name="msapplication-tap-highlight" content="no" /> <link rel="manifest" href="/manifest.json" /> <meta name="theme-color" content="#31d53d" /> </head> <body className="" style={{ overflow: "hidden" }}> <IonicApp>{children}</IonicApp> </body> </html> ); } ``` ### Step 8: Create Basic IonicApp Component Create `src/app/IonicApp.tsx`: ```tsx "use client"; import { IonApp, setupIonicReact } from "@ionic/react"; setupIonicReact(); export default function IonicApp({ children }: { children: React.ReactNode }) { return <IonApp>{children}</IonApp>; } ``` ### Step 9: Create Global Styles Create `src/app/globals.css`: ```css @tailwind base; @tailwind components; @tailwind utilities; :root { --ion-color-primary: #31d53d; --ion-color-primary-rgb: 49, 213, 61; --ion-color-primary-contrast: #ffffff; --ion-color-primary-contrast-rgb: 255, 255, 255; --ion-color-primary-shade: #2bbb36; --ion-color-primary-tint: #46d954; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } ``` ### Step 10: Update Package Scripts Update `package.json` scripts: ```json { "scripts": { "dev": "next dev -p 3001", "build": "next build", "start": "next start", "lint": "next lint", "cap:sync": "CAPACITOR_BUILD=true next build && cap sync", "cap:ios": "CAPACITOR_BUILD=true next build && cap sync ios", "cap:android": "CAPACITOR_BUILD=true next build && cap sync android", "cap:open:ios": "cap open ios", "cap:open:android": "cap open android" } } ``` ### Step 11: Add Native Platforms ```bash # iOS npx cap add ios npx cap sync # Android npx cap add android npx cap sync ``` ## Optional Enhancements ### Enhanced IonicApp Component You can enhance the basic `IonicApp.tsx` with additional features: ```tsx "use client"; import { useEffect } from "react"; import { IonApp, setupIonicReact } from "@ionic/react"; import { Capacitor } from "@capacitor/core"; import { SplashScreen } from "@capacitor/splash-screen"; import { StatusBar, Style } from "@capacitor/status-bar"; import { App, AppState } from "@capacitor/app"; setupIonicReact(); export default function IonicApp({ children }: { children: React.ReactNode }) { useEffect(() => { // Add platform class to body for CSS targeting if (Capacitor.isNativePlatform()) { document.body.classList.add('native-platform'); } else { document.body.classList.add('web-platform'); // Add debug safe area indicators for Chrome DevTools testing document.documentElement.style.setProperty('--safe-area-inset-top', '44px'); document.documentElement.style.setProperty('--safe-area-inset-bottom', '34px'); } // Configure StatusBar on native platforms if (Capacitor.isNativePlatform()) { try { StatusBar.setStyle({ style: Style.Dark }); StatusBar.setOverlaysWebView({ overlay: false }); StatusBar.setBackgroundColor({ color: "#000000" }); } catch (error) { console.warn("Failed to configure status bar:", error); } try { // Hide splash screen after app loads setTimeout(() => { SplashScreen.hide({ fadeOutDuration: 200 }); }, 100); } catch (error) { console.warn("Failed to hide splash screen:", error); } // Listen for app state changes const stateListener = App.addListener("appStateChange", (state: AppState) => { if (state.isActive) { // Handle app becoming active console.log("App became active"); } }); return () => { document.body.classList.remove('native-platform', 'web-platform'); stateListener.remove(); }; } }, []); return <IonApp>{children}</IonApp>; }
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기