@jarrodmedrano/claude-skills 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/new-fullstack.md +83 -0
- package/.claude/skills/solito/SKILL.md +604 -0
- package/.claude/skills/solito/references/common-pitfalls.md +659 -0
- package/.claude/skills/solito/references/monorepo-setup.md +619 -0
- package/.claude/skills/solito/references/navigation-patterns.md +606 -0
- package/.claude/skills/solito/references/platform-specific.md +651 -0
- package/README.md +1 -0
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ When this skill is invoked:
|
|
|
13
13
|
- T3 Stack (Next.js + tRPC + Prisma + Tailwind)
|
|
14
14
|
- MERN (MongoDB + Express + React + Node)
|
|
15
15
|
- Monorepo (React frontend + Express backend + shared types)
|
|
16
|
+
- Solito (Expo + Next.js + shared navigation - Universal app for web + mobile)
|
|
16
17
|
|
|
17
18
|
2. Extract the project name from args, or ask if not provided
|
|
18
19
|
|
|
@@ -46,6 +47,86 @@ When this skill is invoked:
|
|
|
46
47
|
```
|
|
47
48
|
- Set up npm workspaces or pnpm workspace
|
|
48
49
|
|
|
50
|
+
**Solito (Universal App)**:
|
|
51
|
+
- Ask follow-up questions:
|
|
52
|
+
* Package manager? (pnpm recommended, yarn, npm)
|
|
53
|
+
* Include NativeWind? (Tailwind for React Native)
|
|
54
|
+
* Include authentication? (Clerk, Supabase, custom, skip)
|
|
55
|
+
* Include API layer? (tRPC, REST, skip)
|
|
56
|
+
* Include UI library? (Tamagui, React Native Paper, custom, skip)
|
|
57
|
+
|
|
58
|
+
- Use Solito starter template:
|
|
59
|
+
```bash
|
|
60
|
+
npx create-solito-app@latest {project-name}
|
|
61
|
+
```
|
|
62
|
+
Or create manually if custom setup needed
|
|
63
|
+
|
|
64
|
+
- Create monorepo structure:
|
|
65
|
+
```
|
|
66
|
+
{project-name}/
|
|
67
|
+
apps/
|
|
68
|
+
expo/ # React Native mobile app
|
|
69
|
+
app/ # Expo Router file-system routes
|
|
70
|
+
package.json
|
|
71
|
+
app.json
|
|
72
|
+
next/ # Next.js web app
|
|
73
|
+
app/ # Next.js App Router
|
|
74
|
+
public/
|
|
75
|
+
package.json
|
|
76
|
+
next.config.js
|
|
77
|
+
packages/
|
|
78
|
+
app/ # Shared UI and navigation
|
|
79
|
+
features/ # Feature screens
|
|
80
|
+
components/ # Reusable components
|
|
81
|
+
lib/ # Utilities
|
|
82
|
+
provider/ # Navigation provider
|
|
83
|
+
package.json
|
|
84
|
+
api/ # Shared API client (if selected)
|
|
85
|
+
package.json
|
|
86
|
+
package.json # Root workspace config
|
|
87
|
+
pnpm-workspace.yaml # or yarn/npm workspace
|
|
88
|
+
turbo.json # Turborepo config
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Configure based on selections:
|
|
92
|
+
* **NativeWind**: Set up Tailwind config, Metro config, Babel plugin
|
|
93
|
+
* **Clerk**: Install @clerk/clerk-expo and @clerk/nextjs, configure providers
|
|
94
|
+
* **Supabase**: Install @supabase/supabase-js, set up client
|
|
95
|
+
* **tRPC**: Configure tRPC client, create example router
|
|
96
|
+
* **Tamagui**: Install and configure Tamagui for universal styling
|
|
97
|
+
|
|
98
|
+
- Add example screens:
|
|
99
|
+
* Home screen (apps/expo/app/index.tsx and apps/next/app/page.tsx)
|
|
100
|
+
* Profile screen with navigation
|
|
101
|
+
* Demonstrate shared navigation with solito/link
|
|
102
|
+
|
|
103
|
+
- Configure Metro bundler to watch monorepo
|
|
104
|
+
- Set up TypeScript path aliases
|
|
105
|
+
- Create .env.example for both platforms (NEXT_PUBLIC_ and EXPO_PUBLIC_)
|
|
106
|
+
|
|
107
|
+
- Add development scripts to root package.json:
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"scripts": {
|
|
111
|
+
"dev": "turbo run dev",
|
|
112
|
+
"dev:next": "pnpm --filter next-app dev",
|
|
113
|
+
"dev:expo": "pnpm --filter expo-app start",
|
|
114
|
+
"build": "turbo run build",
|
|
115
|
+
"lint": "turbo run lint",
|
|
116
|
+
"typecheck": "turbo run typecheck"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- Create README with:
|
|
122
|
+
* Project structure explanation
|
|
123
|
+
* Setup instructions (pnpm install)
|
|
124
|
+
* How to run web app (cd apps/next && pnpm dev)
|
|
125
|
+
* How to run mobile app (cd apps/expo && pnpm start)
|
|
126
|
+
* Shared code location (packages/app)
|
|
127
|
+
* Platform-specific code guidelines
|
|
128
|
+
* Deployment instructions (Vercel for web, EAS for mobile)
|
|
129
|
+
|
|
49
130
|
4. Set up database and ORM:
|
|
50
131
|
- Create database schema/models
|
|
51
132
|
- Set up migration scripts
|
|
@@ -73,3 +154,5 @@ When this skill is invoked:
|
|
|
73
154
|
**Example usage**:
|
|
74
155
|
- `/new-fullstack my-saas-app`
|
|
75
156
|
- `/new-fullstack` (will prompt for name)
|
|
157
|
+
|
|
158
|
+
**Note**: For Solito projects, automatically invoke the `solito` skill after project creation to provide specialized guidance for cross-platform development, navigation patterns, and best practices.
|
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: solito
|
|
3
|
+
description: This skill should be used when working on Solito projects (Expo + Next.js with shared navigation). It provides specialized knowledge for cross-platform navigation, monorepo structure, shared component patterns, platform-specific code handling, and common pitfalls. Use this skill when building universal apps, implementing navigation, creating shared UI components, or debugging cross-platform issues.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Solito Cross-Platform Development Skill
|
|
7
|
+
|
|
8
|
+
A specialized skill for building universal applications using Solito, combining Expo (React Native) and Next.js with shared navigation and component libraries.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Invoke this skill when:
|
|
13
|
+
- Building universal apps (web + mobile) with shared code
|
|
14
|
+
- Implementing cross-platform navigation
|
|
15
|
+
- Creating shared UI components that work on web and native
|
|
16
|
+
- Setting up monorepo structure for Solito projects
|
|
17
|
+
- Handling platform-specific code (web-only or native-only features)
|
|
18
|
+
- Implementing authentication across platforms
|
|
19
|
+
- Debugging navigation or routing issues
|
|
20
|
+
- Optimizing bundle sizes for web and native
|
|
21
|
+
|
|
22
|
+
## What is Solito?
|
|
23
|
+
|
|
24
|
+
Solito enables developers to share navigation code between React Native (Expo) and Next.js. Instead of maintaining separate routing logic for web and mobile, Solito provides a unified navigation layer that respects platform-specific patterns while sharing as much code as possible.
|
|
25
|
+
|
|
26
|
+
**Key Benefits:**
|
|
27
|
+
- Single source of truth for navigation
|
|
28
|
+
- File-system routing for native apps (via Expo Router)
|
|
29
|
+
- Shared UI components with platform-specific optimizations
|
|
30
|
+
- Unified API for links and navigation
|
|
31
|
+
- Type-safe routing with TypeScript
|
|
32
|
+
|
|
33
|
+
## Before You Start: Essential Solito Tips
|
|
34
|
+
|
|
35
|
+
### Project Structure First
|
|
36
|
+
|
|
37
|
+
**Solito projects use monorepo architecture.** Always structure your project correctly from the start:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
my-app/
|
|
41
|
+
apps/
|
|
42
|
+
expo/ # React Native mobile app
|
|
43
|
+
next/ # Next.js web app
|
|
44
|
+
packages/
|
|
45
|
+
app/ # Shared UI components & navigation
|
|
46
|
+
api/ # Shared API client (optional)
|
|
47
|
+
package.json # Workspace configuration
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**See `references/monorepo-setup.md` for detailed workspace configuration.**
|
|
51
|
+
|
|
52
|
+
### Use Solito Starter Template
|
|
53
|
+
|
|
54
|
+
The official Solito starter saves hours of configuration:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx create-solito-app@latest my-app
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Choose your preferred package manager (pnpm recommended for monorepos).
|
|
61
|
+
|
|
62
|
+
### Navigation is Different
|
|
63
|
+
|
|
64
|
+
**Don't use Next.js Link or React Navigation Link directly.** Use Solito's unified components:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { Link } from 'solito/link'
|
|
68
|
+
|
|
69
|
+
// ✅ CORRECT: Works on both web and native
|
|
70
|
+
<Link href="/profile">
|
|
71
|
+
<Text>View Profile</Text>
|
|
72
|
+
</Link>
|
|
73
|
+
|
|
74
|
+
// ❌ WRONG: Next.js-only
|
|
75
|
+
import Link from 'next/link'
|
|
76
|
+
|
|
77
|
+
// ❌ WRONG: React Navigation-only
|
|
78
|
+
import { Link } from '@react-navigation/native'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**See `references/navigation-patterns.md` for detailed routing patterns.**
|
|
82
|
+
|
|
83
|
+
## Core Development Principles
|
|
84
|
+
|
|
85
|
+
### 1. Shared by Default, Platform-Specific When Needed
|
|
86
|
+
|
|
87
|
+
**80% of your code should live in `packages/app`.** Only create platform-specific code when absolutely necessary.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// packages/app/features/home/screen.tsx
|
|
91
|
+
// ✅ GOOD: Shared screen component
|
|
92
|
+
export function HomeScreen() {
|
|
93
|
+
return (
|
|
94
|
+
<View>
|
|
95
|
+
<Text>Welcome!</Text>
|
|
96
|
+
<Link href="/profile">
|
|
97
|
+
<Text>Go to Profile</Text>
|
|
98
|
+
</Link>
|
|
99
|
+
</View>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Platform-specific code should be minimal:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// packages/app/components/map.tsx
|
|
108
|
+
import { Platform } from 'react-native'
|
|
109
|
+
|
|
110
|
+
export function Map() {
|
|
111
|
+
// ✅ GOOD: Platform detection for necessary differences
|
|
112
|
+
if (Platform.OS === 'web') {
|
|
113
|
+
return <WebMapComponent />
|
|
114
|
+
}
|
|
115
|
+
return <NativeMapComponent />
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### 2. Think in Features, Not Platforms
|
|
120
|
+
|
|
121
|
+
**Organize by feature domain, not by platform:**
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
packages/app/
|
|
125
|
+
features/
|
|
126
|
+
home/
|
|
127
|
+
screen.tsx # Home screen
|
|
128
|
+
components/ # Home-specific components
|
|
129
|
+
profile/
|
|
130
|
+
screen.tsx # Profile screen
|
|
131
|
+
components/
|
|
132
|
+
auth/
|
|
133
|
+
login-screen.tsx
|
|
134
|
+
register-screen.tsx
|
|
135
|
+
components/ # Shared UI components
|
|
136
|
+
provider/ # Navigation provider
|
|
137
|
+
navigation/ # Navigation configuration
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Not organized by platform:**
|
|
141
|
+
```
|
|
142
|
+
❌ BAD:
|
|
143
|
+
packages/app/
|
|
144
|
+
web/
|
|
145
|
+
screens/
|
|
146
|
+
native/
|
|
147
|
+
screens/
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 3. Navigation is Central
|
|
151
|
+
|
|
152
|
+
**Design your navigation structure early.** Solito uses file-system routing on native and Next.js App Router on web.
|
|
153
|
+
|
|
154
|
+
**Navigation mapping:**
|
|
155
|
+
```tsx
|
|
156
|
+
// apps/next/app/profile/page.tsx (web route)
|
|
157
|
+
import { ProfileScreen } from 'app/features/profile/screen'
|
|
158
|
+
|
|
159
|
+
export default ProfileScreen
|
|
160
|
+
|
|
161
|
+
// apps/expo/app/profile.tsx (native route)
|
|
162
|
+
import { ProfileScreen } from 'app/features/profile/screen'
|
|
163
|
+
|
|
164
|
+
export default ProfileScreen
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Both platforms render the same `ProfileScreen` component from `packages/app`.
|
|
168
|
+
|
|
169
|
+
**See `references/navigation-patterns.md` for routing patterns, params, and navigation hooks.**
|
|
170
|
+
|
|
171
|
+
## Development Workflow
|
|
172
|
+
|
|
173
|
+
### Local Development
|
|
174
|
+
|
|
175
|
+
**Run both platforms simultaneously:**
|
|
176
|
+
|
|
177
|
+
Terminal 1 - Web:
|
|
178
|
+
```bash
|
|
179
|
+
cd apps/next
|
|
180
|
+
pnpm dev
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Terminal 2 - Mobile:
|
|
184
|
+
```bash
|
|
185
|
+
cd apps/expo
|
|
186
|
+
pnpm start
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Press `i` for iOS simulator, `a` for Android emulator, or scan QR code for physical device.
|
|
190
|
+
|
|
191
|
+
### Making Changes
|
|
192
|
+
|
|
193
|
+
1. **Create shared component** in `packages/app/components/`
|
|
194
|
+
2. **Create screen** in `packages/app/features/[feature]/screen.tsx`
|
|
195
|
+
3. **Add routes** in both `apps/next/app/` and `apps/expo/app/`
|
|
196
|
+
4. **Test on both platforms** to verify cross-platform behavior
|
|
197
|
+
|
|
198
|
+
### Common Commands
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Install dependencies (from root)
|
|
202
|
+
pnpm install
|
|
203
|
+
|
|
204
|
+
# Run web dev server
|
|
205
|
+
cd apps/next && pnpm dev
|
|
206
|
+
|
|
207
|
+
# Run Expo dev server
|
|
208
|
+
cd apps/expo && pnpm start
|
|
209
|
+
|
|
210
|
+
# Type checking
|
|
211
|
+
pnpm typecheck
|
|
212
|
+
|
|
213
|
+
# Lint all packages
|
|
214
|
+
pnpm lint
|
|
215
|
+
|
|
216
|
+
# Build for production
|
|
217
|
+
pnpm build
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Styling with NativeWind
|
|
221
|
+
|
|
222
|
+
NativeWind brings Tailwind CSS to React Native, enabling shared styling across platforms.
|
|
223
|
+
|
|
224
|
+
```tsx
|
|
225
|
+
import { View, Text } from 'react-native'
|
|
226
|
+
|
|
227
|
+
// ✅ GOOD: Tailwind classes work on both platforms
|
|
228
|
+
export function Card() {
|
|
229
|
+
return (
|
|
230
|
+
<View className="bg-white rounded-lg p-4 shadow-md">
|
|
231
|
+
<Text className="text-xl font-bold">Title</Text>
|
|
232
|
+
<Text className="text-gray-600">Description</Text>
|
|
233
|
+
</View>
|
|
234
|
+
)
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Platform-specific styles when needed:**
|
|
239
|
+
```tsx
|
|
240
|
+
<View className="p-4 web:p-6 native:p-2">
|
|
241
|
+
{/* Different padding on web vs native */}
|
|
242
|
+
</View>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Design Tokens
|
|
246
|
+
|
|
247
|
+
**Use shared design tokens in `packages/app/design/tokens.ts`:**
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
export const colors = {
|
|
251
|
+
primary: '#3B82F6',
|
|
252
|
+
secondary: '#10B981',
|
|
253
|
+
background: '#FFFFFF',
|
|
254
|
+
text: '#1F2937',
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const spacing = {
|
|
258
|
+
xs: 4,
|
|
259
|
+
sm: 8,
|
|
260
|
+
md: 16,
|
|
261
|
+
lg: 24,
|
|
262
|
+
xl: 32,
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Authentication Patterns
|
|
267
|
+
|
|
268
|
+
**Share auth logic across platforms:**
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
// packages/app/lib/auth.ts
|
|
272
|
+
import { createContext, useContext } from 'react'
|
|
273
|
+
|
|
274
|
+
interface AuthContextType {
|
|
275
|
+
user: User | null
|
|
276
|
+
signIn: (email: string, password: string) => Promise<void>
|
|
277
|
+
signOut: () => Promise<void>
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export const AuthContext = createContext<AuthContextType>(null!)
|
|
281
|
+
|
|
282
|
+
export function useAuth() {
|
|
283
|
+
return useContext(AuthContext)
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Use in components:**
|
|
288
|
+
```tsx
|
|
289
|
+
import { useAuth } from 'app/lib/auth'
|
|
290
|
+
|
|
291
|
+
export function ProfileScreen() {
|
|
292
|
+
const { user, signOut } = useAuth()
|
|
293
|
+
|
|
294
|
+
return (
|
|
295
|
+
<View>
|
|
296
|
+
<Text>Welcome, {user?.name}</Text>
|
|
297
|
+
<Button onPress={signOut}>Sign Out</Button>
|
|
298
|
+
</View>
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**Popular auth solutions:**
|
|
304
|
+
- **Clerk** - Excellent Solito integration, works on both platforms
|
|
305
|
+
- **Supabase** - Self-hosted option with good RN support
|
|
306
|
+
- **Custom JWT** - Full control, requires more setup
|
|
307
|
+
|
|
308
|
+
## API Integration
|
|
309
|
+
|
|
310
|
+
**Share API client in `packages/api/`:**
|
|
311
|
+
|
|
312
|
+
```tsx
|
|
313
|
+
// packages/api/client.ts
|
|
314
|
+
const API_URL = process.env.NEXT_PUBLIC_API_URL
|
|
315
|
+
|
|
316
|
+
export async function fetchUser(id: string) {
|
|
317
|
+
const response = await fetch(`${API_URL}/users/${id}`)
|
|
318
|
+
return response.json()
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Use with tRPC for type-safety:**
|
|
323
|
+
```tsx
|
|
324
|
+
// packages/api/trpc.ts
|
|
325
|
+
import { initTRPC } from '@trpc/server'
|
|
326
|
+
|
|
327
|
+
const t = initTRPC.create()
|
|
328
|
+
|
|
329
|
+
export const appRouter = t.router({
|
|
330
|
+
getUser: t.procedure
|
|
331
|
+
.input(z.string())
|
|
332
|
+
.query(async ({ input }) => {
|
|
333
|
+
return db.user.findUnique({ where: { id: input } })
|
|
334
|
+
}),
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
export type AppRouter = typeof appRouter
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**tRPC works seamlessly across web and native with full type-safety.**
|
|
341
|
+
|
|
342
|
+
## State Management
|
|
343
|
+
|
|
344
|
+
**Recommended: Zustand** (lightweight, works great with Solito)
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
// packages/app/store/user.ts
|
|
348
|
+
import { create } from 'zustand'
|
|
349
|
+
|
|
350
|
+
interface UserState {
|
|
351
|
+
user: User | null
|
|
352
|
+
setUser: (user: User | null) => void
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export const useUserStore = create<UserState>((set) => ({
|
|
356
|
+
user: null,
|
|
357
|
+
setUser: (user) => set({ user }),
|
|
358
|
+
}))
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Use in components:**
|
|
362
|
+
```tsx
|
|
363
|
+
import { useUserStore } from 'app/store/user'
|
|
364
|
+
|
|
365
|
+
export function ProfileScreen() {
|
|
366
|
+
const user = useUserStore((state) => state.user)
|
|
367
|
+
|
|
368
|
+
return <Text>Welcome, {user?.name}</Text>
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**Other options:**
|
|
373
|
+
- **Jotai** - Atomic state management
|
|
374
|
+
- **Redux Toolkit** - For complex state needs
|
|
375
|
+
- **React Context** - For simple global state
|
|
376
|
+
|
|
377
|
+
## Platform-Specific Code
|
|
378
|
+
|
|
379
|
+
**Use platform detection sparingly:**
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
import { Platform } from 'react-native'
|
|
383
|
+
|
|
384
|
+
export function VideoPlayer() {
|
|
385
|
+
if (Platform.OS === 'web') {
|
|
386
|
+
return <video src={url} controls />
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Use native video component
|
|
390
|
+
return <Video source={{ uri: url }} />
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Better: Use platform-specific files:**
|
|
395
|
+
|
|
396
|
+
```
|
|
397
|
+
packages/app/components/
|
|
398
|
+
video-player.tsx # Shared interface
|
|
399
|
+
video-player.web.tsx # Web implementation
|
|
400
|
+
video-player.native.tsx # Native implementation
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
// video-player.tsx
|
|
405
|
+
export { VideoPlayer } from './video-player.native'
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Metro bundler and Next.js will automatically resolve the correct file.
|
|
409
|
+
|
|
410
|
+
**See `references/platform-specific.md` for detailed patterns.**
|
|
411
|
+
|
|
412
|
+
## Common Pitfalls to Avoid
|
|
413
|
+
|
|
414
|
+
**Critical mistakes and their solutions are documented in `references/common-pitfalls.md`. Key pitfalls include:**
|
|
415
|
+
|
|
416
|
+
1. Using Next.js Link or React Navigation Link directly
|
|
417
|
+
2. Hardcoding absolute URLs (use relative paths)
|
|
418
|
+
3. Not handling navigation params correctly
|
|
419
|
+
4. Importing from wrong packages (next/link vs solito/link)
|
|
420
|
+
5. Forgetting to configure navigation provider
|
|
421
|
+
6. Not testing on both platforms regularly
|
|
422
|
+
7. Overusing platform-specific code
|
|
423
|
+
|
|
424
|
+
Review `references/common-pitfalls.md` before implementing navigation or shared components.
|
|
425
|
+
|
|
426
|
+
## Performance Optimization
|
|
427
|
+
|
|
428
|
+
### Bundle Size
|
|
429
|
+
|
|
430
|
+
**Keep packages/app lean:**
|
|
431
|
+
- Avoid large dependencies in shared code
|
|
432
|
+
- Use dynamic imports for heavy features
|
|
433
|
+
- Split platform-specific dependencies
|
|
434
|
+
|
|
435
|
+
```tsx
|
|
436
|
+
// ✅ GOOD: Dynamic import for heavy feature
|
|
437
|
+
const HeavyChart = dynamic(() => import('./heavy-chart'))
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Navigation Performance
|
|
441
|
+
|
|
442
|
+
**Preload screens for better UX:**
|
|
443
|
+
```tsx
|
|
444
|
+
import { useRouter } from 'solito/router'
|
|
445
|
+
|
|
446
|
+
export function HomeScreen() {
|
|
447
|
+
const router = useRouter()
|
|
448
|
+
|
|
449
|
+
// Preload profile screen on hover/focus
|
|
450
|
+
const handlePreload = () => {
|
|
451
|
+
router.push('/profile', undefined, { shallow: true })
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
<Link href="/profile" onHoverIn={handlePreload}>
|
|
456
|
+
<Text>Profile</Text>
|
|
457
|
+
</Link>
|
|
458
|
+
)
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Image Optimization
|
|
463
|
+
|
|
464
|
+
**Use Next.js Image on web, optimized Image on native:**
|
|
465
|
+
|
|
466
|
+
```tsx
|
|
467
|
+
// packages/app/components/optimized-image.tsx
|
|
468
|
+
import { Platform } from 'react-native'
|
|
469
|
+
import NextImage from 'next/image'
|
|
470
|
+
import { Image as RNImage } from 'react-native'
|
|
471
|
+
|
|
472
|
+
export function OptimizedImage({ src, width, height, alt }) {
|
|
473
|
+
if (Platform.OS === 'web') {
|
|
474
|
+
return <NextImage src={src} width={width} height={height} alt={alt} />
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return <RNImage source={{ uri: src }} style={{ width, height }} />
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Testing Strategy
|
|
482
|
+
|
|
483
|
+
### Unit Tests
|
|
484
|
+
|
|
485
|
+
**Test shared logic in packages/app:**
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
// packages/app/lib/__tests__/format.test.ts
|
|
489
|
+
import { formatCurrency } from '../format'
|
|
490
|
+
|
|
491
|
+
describe('formatCurrency', () => {
|
|
492
|
+
it('formats USD correctly', () => {
|
|
493
|
+
expect(formatCurrency(1234.56, 'USD')).toBe('$1,234.56')
|
|
494
|
+
})
|
|
495
|
+
})
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Component Tests
|
|
499
|
+
|
|
500
|
+
**Use React Native Testing Library:**
|
|
501
|
+
|
|
502
|
+
```tsx
|
|
503
|
+
import { render, screen } from '@testing-library/react-native'
|
|
504
|
+
import { HomeScreen } from '../screen'
|
|
505
|
+
|
|
506
|
+
test('renders welcome message', () => {
|
|
507
|
+
render(<HomeScreen />)
|
|
508
|
+
expect(screen.getByText('Welcome!')).toBeTruthy()
|
|
509
|
+
})
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### E2E Tests
|
|
513
|
+
|
|
514
|
+
**Playwright for web, Detox for native:**
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
// apps/next/e2e/home.spec.ts
|
|
518
|
+
import { test, expect } from '@playwright/test'
|
|
519
|
+
|
|
520
|
+
test('navigates to profile', async ({ page }) => {
|
|
521
|
+
await page.goto('/')
|
|
522
|
+
await page.click('text=Profile')
|
|
523
|
+
await expect(page).toHaveURL('/profile')
|
|
524
|
+
})
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
## Deployment
|
|
528
|
+
|
|
529
|
+
### Web (Next.js)
|
|
530
|
+
|
|
531
|
+
**Deploy to Vercel (recommended):**
|
|
532
|
+
|
|
533
|
+
```bash
|
|
534
|
+
cd apps/next
|
|
535
|
+
vercel deploy
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
Configure environment variables in Vercel dashboard.
|
|
539
|
+
|
|
540
|
+
### Mobile (Expo)
|
|
541
|
+
|
|
542
|
+
**Build with EAS:**
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
cd apps/expo
|
|
546
|
+
|
|
547
|
+
# Install EAS CLI
|
|
548
|
+
npm install -g eas-cli
|
|
549
|
+
|
|
550
|
+
# Configure project
|
|
551
|
+
eas build:configure
|
|
552
|
+
|
|
553
|
+
# Build for iOS
|
|
554
|
+
eas build --platform ios
|
|
555
|
+
|
|
556
|
+
# Build for Android
|
|
557
|
+
eas build --platform android
|
|
558
|
+
|
|
559
|
+
# Submit to stores
|
|
560
|
+
eas submit
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
**Over-the-air updates:**
|
|
564
|
+
```bash
|
|
565
|
+
eas update --branch production
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## References
|
|
569
|
+
|
|
570
|
+
This skill includes detailed reference documentation:
|
|
571
|
+
|
|
572
|
+
- `references/navigation-patterns.md` - Link usage, router hooks, params, navigation state
|
|
573
|
+
- `references/monorepo-setup.md` - Workspace configuration, package structure, dependencies
|
|
574
|
+
- `references/platform-specific.md` - Platform detection, conditional rendering, file extensions
|
|
575
|
+
- `references/common-pitfalls.md` - Import issues, navigation bugs, platform quirks
|
|
576
|
+
|
|
577
|
+
Load these references as needed to inform implementation decisions.
|
|
578
|
+
|
|
579
|
+
## Additional Resources
|
|
580
|
+
|
|
581
|
+
**Solito Documentation:**
|
|
582
|
+
- Official Docs: https://solito.dev/
|
|
583
|
+
- Solito Starter: https://github.com/nandorojo/solito
|
|
584
|
+
- Example Apps: https://github.com/nandorojo/solito/tree/master/example-monorepos
|
|
585
|
+
|
|
586
|
+
**Related Technologies:**
|
|
587
|
+
- Expo Router: https://docs.expo.dev/router/introduction/
|
|
588
|
+
- Next.js App Router: https://nextjs.org/docs/app
|
|
589
|
+
- NativeWind: https://www.nativewind.dev/
|
|
590
|
+
- React Navigation: https://reactnavigation.org/
|
|
591
|
+
|
|
592
|
+
**State Management:**
|
|
593
|
+
- Zustand: https://github.com/pmndrs/zustand
|
|
594
|
+
- Jotai: https://jotai.org/
|
|
595
|
+
- Redux Toolkit: https://redux-toolkit.js.org/
|
|
596
|
+
|
|
597
|
+
**Authentication:**
|
|
598
|
+
- Clerk: https://clerk.com/
|
|
599
|
+
- Supabase: https://supabase.com/
|
|
600
|
+
- NextAuth.js: https://next-auth.js.org/
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
**Remember:** Share code by default, create platform-specific code only when necessary. Design your navigation structure early, test on both platforms regularly, and keep `packages/app` as the single source of truth for your application logic.
|