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