Port Conflicts
# Check what's running on port 9000lsof -ti:9000
# Kill process if neededkill -9 $(lsof -ti:9000)
# Start with different portpnpm dev --port 3000
This comprehensive troubleshooting guide helps you quickly identify and resolve common issues when working with the React Admin Template. Each section provides practical solutions based on real-world scenarios.
Problem: Build failures or dependency installation errors due to Node.js version mismatch.
Solution:
Check your current Node.js version:
node --version
If your version is below 20.19.0, update Node.js using nvm or fnm:
Using nvm:
nvm install 20.19.0nvm use 20.19.0nvm alias default 20.19.0
Using fnm:
fnm install 20.19.0fnm use 20.19.0fnm default 20.19.0
Clear package manager cache and reinstall dependencies:
rm -rf node_modules package-lock.jsonnpm cache clean --forcenpm install
Problem: Dependency conflicts when using different package managers (npm, pnpm, yarn).
Solution: The template is optimized for pnpm. Always use pnpm for consistency:
# Install pnpm globallynpm install -g pnpm
# Install dependenciespnpm install
# Run development serverpnpm dev
Problem: Import statements using @/
alias fail with module resolution errors.
Symptom:
Cannot find module '@/components/ui/button' or its corresponding type declarations.
Solution: Ensure your tsconfig.json
includes the correct path mapping:
{"compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] }},"include": ["src", "globals.d.ts"]}
Problem: TypeScript strict mode flags unused variables or parameters.
Symptom:
'React' is declared but its value is never read.Parameter 'event' is declared but its value is never used.
Solutions:
// ❌ Incorrect - React not needed in React 19import React from 'react'
// ✅ Correct - Only import what you useimport { useState, useEffect } from 'react'
// ❌ Incorrectconst handleClick = (event) => {console.log('clicked')}
// ✅ Correct - prefix with underscoreconst handleClick = (_event) => {console.log('clicked')}
Problem: TypeScript errors for imported assets (CSS, SVG, etc.).
Solution: Ensure globals.d.ts
includes all necessary module declarations:
declare module '*.css'declare module '*.vue'declare module '*.json'declare module '*.svg'declare module '*.png'declare module '*.jpg'declare module '*.jpeg'
Problem: Development server fails to start or shows CORS errors.
Solutions:
Port Conflicts
# Check what's running on port 9000lsof -ti:9000
# Kill process if neededkill -9 $(lsof -ti:9000)
# Start with different portpnpm dev --port 3000
Network Access
export default defineConfig({server: {port: 9000,host: '0.0.0.0', // Allow external accessstrictPort: true,},})
Problem: Large bundle size or slow build times.
Diagnostic Steps:
Analyze bundle size:
pnpm buildpnpm preview
Check for large dependencies by installing bundle analyzer:
pnpm add -D rollup-plugin-visualizer
Then add to vite.config.ts plugins array:
import { visualizer } from 'rollup-plugin-visualizer'
plugins: [ // ... other plugins visualizer({ filename: 'dist/stats.html', open: true })]
Optimize imports to reduce bundle size:
// ❌ Imports entire libraryimport { format, parseISO, addDays } from 'date-fns'
// ✅ Tree-shaking friendlyimport format from 'date-fns/format'import parseISO from 'date-fns/parseISO'import addDays from 'date-fns/addDays'
Problem: Table becomes slow with large datasets or frequent re-renders.
Solutions:
// ✅ Memoize expensive calculationsconst processedData = useMemo(() => {return rawData.map(item => ({ ...item, calculatedValue: expensiveCalculation(item)}))}, [rawData])
// ✅ Use useCallback for stable referencesconst handleRowClick = useCallback((row) => {console.log('Row clicked:', row.id)}, [])
// ✅ Implement virtual scrolling for large datasetsconst tableConfig = {enableVirtualization: true,estimateSize: () => 35, // Row height in pixelsoverscan: 10}
Problem: Form validation errors or performance issues with large forms.
Solutions:
// ✅ Use schema-level validation instead of field-levelconst formSchema = z.object({email: z.string().email(),password: z.string().min(8),}).refine((data) => {// Complex cross-field validation herereturn data.password !== data.email}, {message: "Password cannot be the same as email",path: ["password"],})
const form = useForm({resolver: zodResolver(schema),mode: 'onChange', // Real-time validationreValidateMode: 'onChange',delayError: 500, // Debounce error display})
Problem: OKLCH color values not working or theme switching failures.
Diagnostic:
// Check if CSS custom properties are properly setconst rootStyles = getComputedStyle(document.documentElement)console.log('Primary color:', rootStyles.getPropertyValue('--primary'))
// Verify OKLCH browser supportconst supportsOKLCH = CSS.supports('color', 'oklch(70% 0.25 180)')console.log('OKLCH supported:', supportsOKLCH)
Solution: Add fallback for older browsers:
// In your CSS:root {--primary: oklch(58.5% 0.233 277.117);--primary-fallback: #4f46e5; /* Fallback for older browsers */}
// Use with fallback.primary-button {background-color: var(--primary-fallback);background-color: var(--primary);}
Problem: State not persisting between browser sessions or hydration mismatches.
Solutions:
// ✅ Handle hydration properlyimport { create } from 'zustand'import { persist, createJSONStorage } from 'zustand/middleware'
export const useStore = create(persist( (set, get) => ({ // Your state here }), { name: 'app-storage', storage: createJSONStorage(() => localStorage), // Handle hydration onRehydrateStorage: (state) => { console.log('Hydration started') return (state, error) => { if (error) { console.log('Hydration error:', error) } else { console.log('Hydration finished') } } }, }))
Problem: State not updating across components or hook dependencies causing infinite loops.
Solution:
// ✅ Use proper dependency arraysconst { theme, setTheme } = useThemeStore()const [localTheme, setLocalTheme] = useState(theme)
useEffect(() => {setLocalTheme(theme)}, [theme]) // Only depend on theme
// ✅ Avoid object dependenciesconst config = useMemo(() => ({theme: theme,colors: colors}), [theme, colors]) // List dependencies explicitly
Problem: Code works locally but fails in production build.
Common Causes & Solutions:
Environment Variables
# ❌ Missing VITE_ prefixREACT_APP_API_URL=https://api.example.com
# ✅ Correct Vite environment variableVITE_API_URL=https://api.example.com
Dynamic Imports
// ✅ Handle dynamic import errorsconst LazyComponent = lazy(() =>import('./Component').catch(() => ({default: () => <div>Failed to load component</div>})))
Problem: Images or assets not loading in production.
Solution: Use proper asset imports and public folder structure:
// ✅ For assets in src/assetsimport logo from '@/assets/images/logo.png'
// ✅ For assets in public folderconst logoUrl = '/images/logo.png'
// ✅ Dynamic imports with proper error handlingconst loadImage = async (imageName: string) => {try { const image = await import(`@/assets/images/${imageName}.png`) return image.default} catch (error) { console.warn('Image not found:', imageName) return '/images/fallback.png'}}
Problem: Application slows down over time due to memory leaks.
Solutions:
// ✅ Clean up event listenersuseEffect(() => {const handleResize = () => { // Handle resize}
window.addEventListener('resize', handleResize)
return () => { window.removeEventListener('resize', handleResize)}}, [])
// ✅ Cancel async operationsuseEffect(() => {let cancelled = false
const fetchData = async () => { try { const data = await api.getData() if (!cancelled) { setData(data) } } catch (error) { if (!cancelled) { setError(error) } }}
fetchData()
return () => { cancelled = true}}, [])
Problem: Large initial bundle affecting loading performance.
Solution: Implement code splitting and lazy loading:
// ✅ Route-level code splittingconst Dashboard = lazy(() => import('@/pages/Dashboard'))const UserManagement = lazy(() => import('@/pages/UserManagement'))
// ✅ Component-level code splittingconst HeavyChart = lazy(() => import('@/components/Charts/HeavyChart'))
// ✅ Wrap in Suspense with proper fallback<Suspense fallback={<ComponentLoader />}><HeavyChart data={chartData} /></Suspense>
Essential debugging setup:
Install React Developer Tools browser extension
Enable Zustand devtools in your store:
import { devtools } from 'zustand/middleware'
export const useStore = create( devtools( persist( // Your store implementation ), { name: 'app-store' } ))
Add error boundaries for better error handling:
import { ErrorBoundary } from 'react-error-boundary'
function ErrorFallback({ error, resetErrorBoundary }) { return ( <div role="alert" className="p-4 border border-red-200 rounded-lg"> <h2>Something went wrong:</h2> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Try again</button> </div> )}
// Wrap your app or components<ErrorBoundary FallbackComponent={ErrorFallback} onError={(error, errorInfo) => { console.error('Error caught by boundary:', error, errorInfo) }}> <YourComponent /></ErrorBoundary>
Useful debugging techniques:
// ✅ Debug state changesuseEffect(() => {console.log('State changed:', { currentState, previousState })}, [currentState])
// ✅ Debug re-rendersuseEffect(() => {console.log('Component re-rendered')})
// ✅ Debug performanceconst expensiveOperation = () => {console.time('expensive-operation')const result = heavyCalculation()console.timeEnd('expensive-operation')return result}
When you encounter issues not covered in this guide:
Check Dependencies
Ensure all package versions are compatible and up-to-date. Check the template’s package.json
for reference versions.
Review Error Logs
Always check both browser console and terminal output for complete error information and stack traces.
Minimal Reproduction
Create a minimal example that reproduces the issue to isolate the problem from other code.
Environment Reset
When in doubt, clear all caches, delete node_modules
, and perform a fresh installation.