Nano Banana Pro
Agent skill for nano-banana-pro
Complete mastery of essential modern web development libraries and dependencies. Cover Next.js, React, TypeScript, Tailwind CSS, Firebase, Zustand, redux-toolkit, react-hook-form, Zod, shadcn/ui, lucide-react, Stripe, and more. Learn setup, integration patterns, advanced usage, performance optimization, troubleshooting, common pitfalls, and version management. Includes quick reference guides, in-depth tutorials, complete examples for e-commerce and SaaS, configuration files, type definitions, error handling, and production patterns. Master how libraries work together and solve real-world challenges.
Sign in to like and favorite skills
You are an expert in modern web development libraries and their integration. This skill provides complete mastery of the essential libraries powering modern full-stack applications: Next.js, React, TypeScript, Tailwind CSS, Firebase, State Management (Zustand, Redux Toolkit), Forms (react-hook-form, Zod), UI/UX (shadcn/ui, lucide-react), and Payments (Stripe). Learn setup, configuration, integration patterns, advanced usage, performance optimization, troubleshooting, version management, and common pitfalls.
Setup & Configuration:
App Router (Next.js 13+):
Performance Optimization:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: "Cannot find module" in builds Solution: Check tsconfig paths, clear .next folder, rebuild Issue: Hydration mismatch error Solution: Use dynamic imports, wrap client code, check useEffect Issue: Images not optimizing Solution: Use next/image, configure domains, check sizes Issue: Build time too long Solution: Analyze with `next/bundle-analyzer`, use dynamic imports Issue: Environment variables undefined Solution: Prefix with NEXT_PUBLIC_ for client, restart dev server
Version Management:
Hooks Deep Dive:
Component Patterns:
Performance Optimization:
Concurrent Features:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: Infinite loop in useEffect Solution: Check dependencies, add return cleanup function Issue: Stale state in callback Solution: Include state in dependencies or use useCallback Issue: Memory leak warning Solution: Add cleanup function to useEffect, unsubscribe Issue: Component rerending unnecessarily Solution: Use React.memo, useCallback, useMemo Issue: Hydration error with useId Solution: Use proper key prop, wrap in Suspense
Fundamentals:
Advanced Types:
React + TypeScript:
Common Patterns:
// Discriminated union type Action = | { type: 'ADD'; payload: Item } | { type: 'REMOVE'; payload: string }; // Generic component function List<T extends { id: string }>(props: { items: T[] }) {} // Type guard function isString(value: unknown): value is string { return typeof value === 'string'; } // Utility type usage type User = { name: string; age: number; email: string }; type UserPreview = Pick<User, 'name' | 'age'>;
Configuration:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: Type 'X' is not assignable to type 'Y' Solution: Check property names, use type assertion carefully, review interfaces Issue: Cannot find name 'X' Solution: Check imports, verify tsconfig paths, check node_modules Issue: Property 'X' doesn't exist on type 'Y' Solution: Check types, update interfaces, verify external package types Issue: Generic type 'T' is too complex Solution: Add constraints, break into simpler types, use keyof
Core Concepts:
Configuration & Customization:
// tailwind.config.ts import type { Config } from 'tailwindcss' export default { content: [ './app/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}', ], theme: { extend: { colors: { primary: '#your-color', }, spacing: { '128': '32rem', }, }, }, plugins: [], } satisfies Config
Advanced Patterns:
Performance Optimization:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: Styles not applying in production Solution: Check content paths, rebuild, check purge config Issue: Dark mode not toggling Solution: Set darkMode: 'class' in config, add class to html Issue: Custom colors not available Solution: Update tailwind.config.ts theme.extend.colors Issue: Build size too large Solution: Verify content paths, use JIT, remove unused plugins Issue: Responsive styles not working Solution: Use correct breakpoint prefix (sm:, md:), check cascade
Setup & Configuration:
// lib/firebase.ts import { initializeApp } from 'firebase/app'; import { getAuth } from 'firebase/auth'; import { getFirestore } from 'firebase/firestore'; import { getStorage } from 'firebase/storage'; const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const db = getFirestore(app); export const storage = getStorage(app);
Authentication:
Firestore Database:
Cloud Storage:
Offline Persistence:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: "Permission denied" errors Solution: Check Security Rules, verify auth state, check custom claims Issue: onSnapshot not updating Solution: Verify listener attached, check firestore rules, cleanup properly Issue: File upload failing Solution: Check storage rules, verify file path, check bucket permissions Issue: Auth state undefined on refresh Solution: Wait for onAuthStateChanged before rendering, use loading state Issue: Realtime listener consuming quota Solution: Limit listeners, use oncemore, implement cleanup
Zustand Complete:
// store/cartStore.ts import { create } from 'zustand'; import { persist } from 'zustand/middleware'; interface CartState { items: CartItem[]; addItem: (item: CartItem) => void; removeItem: (id: string) => void; getTotal: () => number; } export const useCartStore = create<CartState>()( persist( (set, get) => ({ items: [], addItem: (item) => set(state => ({ items: [...state.items, item] })), removeItem: (id) => set(state => ({ items: state.items.filter(i => i.id !== id) })), getTotal: () => { return get().items.reduce((sum, item) => sum + item.price * item.quantity, 0 ); }, }), { name: 'cart-storage' } ) );
Redux Toolkit Complete:
// store/cartSlice.ts import { createSlice, PayloadAction } from '@reduxjs/toolkit'; interface CartState { items: CartItem[]; } const cartSlice = createSlice({ name: 'cart', initialState: { items: [] }, reducers: { addItem: (state, action: PayloadAction<CartItem>) => { state.items.push(action.payload); }, removeItem: (state, action: PayloadAction<string>) => { state.items = state.items.filter(i => i.id !== action.payload); }, }, }); export const { addItem, removeItem } = cartSlice.actions; export default cartSlice.reducer;
Comparison & When to Use:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: State not persisting in Zustand Solution: Add persist middleware, check localStorage, verify name prop Issue: Redux component not updating Solution: Check selector, verify dispatch called, check middleware Issue: Store data undefined on mount Solution: Use loading state, wait for hydration, check persist Issue: Memory leaks from listeners Solution: Return unsubscribe function, cleanup in useEffect
react-hook-form Setup:
import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; const schema = z.object({ email: z.string().email(), password: z.string().min(8), }); type FormData = z.infer<typeof schema>; function LoginForm() { const { register, handleSubmit, formState: { errors } } = useForm<FormData>({ resolver: zodResolver(schema), }); return ( <form onSubmit={handleSubmit(onSubmit)}> <input {...register('email')} /> {errors.email && <span>{errors.email.message}</span>} </form> ); }
Zod Validation:
// Complete validation schema const userSchema = z.object({ name: z.string().min(2).max(50), email: z.string().email(), age: z.number().min(18).max(120), password: z.string().min(8), confirmPassword: z.string(), terms: z.boolean().refine(val => val === true), }).refine(data => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], });
Advanced Patterns:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: Form submitting even with errors Solution: Check handleSubmit usage, verify resolver setup Issue: Async validation taking too long Solution: Add debounce, implement caching, optimize backend Issue: Zod error: "Expected object, received undefined" Solution: Verify schema matches form data structure Issue: Dynamic fields not validating Solution: Use z.array() properly, update schema dynamically Issue: File validation not working Solution: Use refine/superRefine, check file type validation
shadcn/ui Setup & Usage:
// Using pre-built components import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card } from '@/components/ui/card'; export function MyComponent() { return ( <Card> <Input placeholder="Enter text" /> <Button>Submit</Button> </Card> ); }
Available Components:
lucide-react Icons:
import { Heart, ShoppingCart, Menu, X } from 'lucide-react'; export function IconExample() { return ( <> <Heart size={24} /> <ShoppingCart className="text-blue-600" /> <Menu strokeWidth={1.5} /> </> ); }
Customization & Theming:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: shadcn/ui component styles not applying Solution: Check Tailwind config, verify CSS import, check className conflicts Issue: Icons not showing or sizing incorrectly Solution: Specify size prop, check import path, verify CSS classes Issue: Dark mode not working with components Solution: Set darkMode in tailwind.config, wrap with provider Issue: Component variants not working Solution: Check component prop names, verify version compatibility
Stripe Setup:
import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // Create payment intent const paymentIntent = await stripe.paymentIntents.create({ amount: 1000, // in cents currency: 'usd', payment_method_types: ['card'], });
Client-Side Integration:
import { loadStripe } from '@stripe/js'; import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js'; const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY!); function PaymentForm() { const stripe = useStripe(); const elements = useElements(); const handleSubmit = async (e) => { const { paymentIntent } = await stripe.confirmCardPayment( clientSecret, { payment_method: { card: elements.getElement(CardElement) } } ); }; return ( <Elements stripe={stripePromise}> <CardElement /> <button onClick={handleSubmit}>Pay</button> </Elements> ); }
Webhooks & Server-Side:
Common Pitfalls & Solutions:
Troubleshooting Guide:
Issue: "publishable key not found" error Solution: Check NEXT_PUBLIC_STRIPE_KEY env var, restart dev server Issue: Webhook verification failing Solution: Use correct webhook secret, check signature encoding Issue: Payment processing twice Solution: Implement idempotency keys, add retry logic, check order status Issue: Test card not working Solution: Use Stripe test cards (4242424242424242), check mode (test/live)
react-hot-toast:
import toast from 'react-hot-toast'; // Success toast toast.success('Order placed successfully!'); // Error toast toast.error('Payment failed'); // Custom toast toast((t) => ( <div> Custom message <button onClick={() => toast.dismiss(t.id)}>Dismiss</button> </div> ));
axios vs fetch:
// axios - automatic JSON handling, interceptors import axios from 'axios'; const response = await axios.get('/api/products'); // fetch - native, no dependencies const response = await fetch('/api/products'); const data = await response.json();
clsx/classnames:
import clsx from 'clsx'; const buttonClass = clsx( 'px-4 py-2 rounded', variant === 'primary' && 'bg-blue-600 text-white', variant === 'secondary' && 'bg-gray-200 text-gray-900', isLoading && 'opacity-50 cursor-not-allowed' );
// Components use shadcn/ui + lucide-react // Forms use react-hook-form + Zod // State with Zustand + persist // API calls with axios // Payments with Stripe // Database with Firebase // Styling with Tailwind CSS // Routing with Next.js
// Next.js for routing + SSR // React for components // TypeScript for type safety // Firebase Auth + Firestore // Redux Toolkit for complex state // Tailwind + shadcn/ui for UI // react-hook-form for user forms // Stripe for subscriptions
package.json Best Practices:
Updating Dependencies:
# Check outdated packages npm outdated # Update specific package npm install package@latest # Update all patch versions npm update # Check for vulnerabilities npm audit npm audit fix
Common Issues:
Bundle Size Reduction:
Runtime Performance:
Database Performance:
✅ Understanding how to set up each library properly ✅ Learning integration patterns between libraries ✅ Troubleshooting library-specific issues ✅ Optimizing performance with libraries ✅ Upgrading and managing dependencies ✅ Finding solutions to common pitfalls ✅ Learning best practices for each library ✅ Making choices between similar libraries (Zustand vs Redux) ✅ Quick reference for library syntax and APIs ✅ Deep diving into advanced usage
This skill includes:
Versions Covered:
Upgrade Paths:
This comprehensive skill gives you complete mastery of the essential libraries and how they work together!