Skip to content

Latest commit

Β 

History

History
357 lines (265 loc) Β· 7.65 KB

File metadata and controls

357 lines (265 loc) Β· 7.65 KB

🎯 Template Usage Guide

This guide will help you get the most out of this React TypeScript template.

πŸš€ Getting Started Checklist

After cloning/using this template, follow this checklist:

1. Initial Setup

  • Update package.json name and description
  • Update README.md with your project details
  • Copy .env.example to .env and configure
  • Update LICENSE file with your information
  • Initialize your git repository

2. Customize for Your Project

  • Update app title in index.html
  • Replace favicon and logos in public/
  • Configure environment variables in .env
  • Remove example components if not needed
  • Add your project-specific folders

πŸ“ Code Style Guide

This template enforces consistent code style through:

Prettier Configuration

{
  "semi": false,           // No semicolons
  "singleQuote": true,     // Single quotes for strings
  "tabWidth": 2,           // 2 spaces for indentation
  "trailingComma": "es5",  // Trailing commas where valid
  "printWidth": 80,        // Line width
  "endOfLine": "lf",       // Unix line endings
  "arrowParens": "avoid"   // Avoid parens around single arrow function parameters
}

ESLint Rules

  • TypeScript strict mode enabled
  • React Hooks rules enforced
  • React Refresh compatibility
  • Import/export best practices

🧩 Adding Dependencies

Regular Dependencies

# UI Libraries
pnpm add @chakra-ui/react @emotion/react @emotion/styled framer-motion

# State Management
pnpm add zustand
# or
pnpm add @reduxjs/toolkit react-redux

# Routing
pnpm add react-router-dom
pnpm add -D @types/react-router-dom

# Data Fetching
pnpm add @tanstack/react-query
# or
pnpm add swr

# Forms
pnpm add react-hook-form @hookform/resolvers zod

Development Dependencies

# Storybook
pnpm add -D @storybook/react @storybook/addon-essentials

# Testing utilities
pnpm add -D @testing-library/user-event msw

# Build tools
pnpm add -D rollup-plugin-visualizer

# Linting
pnpm add -D @typescript-eslint/eslint-plugin @typescript-eslint/parser

πŸ—οΈ Project Architecture

Recommended Folder Structure

src/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ ui/              # Reusable UI components
β”‚   β”œβ”€β”€ forms/           # Form components
β”‚   β”œβ”€β”€ layout/          # Layout components
β”‚   └── pages/           # Page-specific components
β”œβ”€β”€ hooks/               # Custom React hooks
β”œβ”€β”€ services/            # API calls and external services
β”œβ”€β”€ stores/              # State management (Zustand/Redux)
β”œβ”€β”€ types/               # TypeScript type definitions
β”œβ”€β”€ utils/               # Helper functions
β”œβ”€β”€ constants/           # App constants
└── styles/              # Global styles and themes

Component Patterns

Basic Component

import type { FC } from 'react'

interface ComponentProps {
  title: string
  onClick?: () => void
}

const Component: FC<ComponentProps> = ({ title, onClick }) => {
  return (
    <button onClick={onClick} type="button">
      {title}
    </button>
  )
}

export default Component

Component with Children

import type { FC, ReactNode } from 'react'

interface ContainerProps {
  children: ReactNode
  className?: string
}

const Container: FC<ContainerProps> = ({ children, className = '' }) => {
  return <div className={`container ${className}`}>{children}</div>
}

export default Container

Custom Hook

import { useState, useEffect } from 'react'

interface UseApiResult<T> {
  data: T | null
  loading: boolean
  error: string | null
}

export const useApi = <T>(url: string): UseApiResult<T> => {
  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(setData)
      .catch(err => setError(err.message))
      .finally(() => setLoading(false))
  }, [url])

  return { data, loading, error }
}

πŸ§ͺ Testing Strategies

Component Testing

import { render, screen, fireEvent } from '@testing-library/react'
import '@testing-library/jest-dom'
import Button from '../Button'

describe('Button Component', () => {
  it('renders with correct text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })

  it('calls onClick when clicked', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click me</Button>)
    
    fireEvent.click(screen.getByText('Click me'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})

Hook Testing

import { renderHook, waitFor } from '@testing-library/react'
import { useApi } from '../useApi'

// Mock fetch
global.fetch = jest.fn()

describe('useApi Hook', () => {
  beforeEach(() => {
    (fetch as jest.Mock).mockClear()
  })

  it('fetches data successfully', async () => {
    const mockData = { id: 1, name: 'Test' }
    ;(fetch as jest.Mock).mockResolvedValueOnce({
      json: async () => mockData,
    })

    const { result } = renderHook(() => useApi('/api/test'))

    await waitFor(() => {
      expect(result.current.loading).toBe(false)
    })

    expect(result.current.data).toEqual(mockData)
    expect(result.current.error).toBeNull()
  })
})

πŸš€ Deployment

Environment-Specific Builds

# Development
pnpm dev

# Staging
NODE_ENV=staging pnpm build

# Production
NODE_ENV=production pnpm build

Docker Deployment

# Dockerfile
FROM node:18-alpine as builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Vercel Deployment

{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/static-build",
      "config": {
        "distDir": "dist"
      }
    }
  ]
}

πŸ“Š Performance Optimization

Code Splitting

import { lazy, Suspense } from 'react'

const LazyComponent = lazy(() => import('./LazyComponent'))

const App = () => (
  <Suspense fallback={<div>Loading...</div>}>
    <LazyComponent />
  </Suspense>
)

Bundle Analysis

# Add to package.json scripts
"analyze": "vite build && npx vite-bundle-analyzer dist"

# Run analysis
pnpm analyze

πŸ”’ Security Best Practices

  • Always validate environment variables
  • Use TypeScript for type safety
  • Sanitize user inputs
  • Keep dependencies updated
  • Use HTTPS in production
  • Implement proper error boundaries

πŸ“š Learning Resources

πŸ†˜ Troubleshooting

Common Issues

  1. Build fails with TypeScript errors

    • Run pnpm type-check to see detailed errors
    • Check tsconfig.json configuration
  2. Tests fail to run

    • Verify Jest configuration in jest.config.js
    • Check if all test dependencies are installed
  3. Linting errors

    • Run pnpm lint:fix to auto-fix issues
    • Check ESLint configuration
  4. Import path errors

    • Verify path aliases in vite.config.ts and tsconfig.json
    • Ensure paths are consistent

Getting Help

  • Check the Issues section
  • Create a new issue with detailed description
  • Review documentation and examples