This guide will help you get the most out of this React TypeScript template.
After cloning/using this template, follow this checklist:
- Update
package.jsonname and description - Update
README.mdwith your project details - Copy
.env.exampleto.envand configure - Update
LICENSEfile with your information - Initialize your git repository
- 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
This template enforces consistent code style through:
{
"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
}- TypeScript strict mode enabled
- React Hooks rules enforced
- React Refresh compatibility
- Import/export best practices
# 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# 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/parsersrc/
βββ 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
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 Componentimport 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 Containerimport { 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 }
}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)
})
})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()
})
})# Development
pnpm dev
# Staging
NODE_ENV=staging pnpm build
# Production
NODE_ENV=production pnpm build# 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;"]{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"distDir": "dist"
}
}
]
}import { lazy, Suspense } from 'react'
const LazyComponent = lazy(() => import('./LazyComponent'))
const App = () => (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
)# Add to package.json scripts
"analyze": "vite build && npx vite-bundle-analyzer dist"
# Run analysis
pnpm analyze- Always validate environment variables
- Use TypeScript for type safety
- Sanitize user inputs
- Keep dependencies updated
- Use HTTPS in production
- Implement proper error boundaries
-
Build fails with TypeScript errors
- Run
pnpm type-checkto see detailed errors - Check
tsconfig.jsonconfiguration
- Run
-
Tests fail to run
- Verify Jest configuration in
jest.config.js - Check if all test dependencies are installed
- Verify Jest configuration in
-
Linting errors
- Run
pnpm lint:fixto auto-fix issues - Check ESLint configuration
- Run
-
Import path errors
- Verify path aliases in
vite.config.tsandtsconfig.json - Ensure paths are consistent
- Verify path aliases in
- Check the Issues section
- Create a new issue with detailed description
- Review documentation and examples