Welcome to our React TypeScript boilerplate! This project is designed to provide a solid, scalable foundation for building modern web applications. We've carefully selected technologies and structured the project to make development smooth, efficient, and enjoyable.
Our boilerplate is built with:
- React 18
- TypeScript
- Vite for lightning-fast development
- React Router for routing
- Tanstack React Query for data fetching
- Zustand for state management
- Axios for API interactions
- Ant Design for UI components
- Styled Components for styling
- Vitest for testing
-
React (v18.3.1): Our primary UI library, providing a component-based architecture
-
TypeScript (v5.6.2): Adding type safety and enhanced developer experience
-
Vite (v5.4.10): Our blazing-fast build tool and development server
-
Tanstack React Query (v5.59.20): Powerful data synchronization and caching
-
Axios (v1.7.7): Promise-based HTTP client for API requests
-
Zustand (v4.5.4): State management for React applications
-
React Router (v6.27.0): Declarative routing for React applications
-
Ant Design (v5.22.1): Comprehensive React UI library with a wide range of pre-built components
-
Styled Components (v6.1.13): CSS-in-JS solution for component-level styling
-
Vitest (v2.1.5): Testing framework for JavaScript and TypeScript
-
i18next (v23.16.5): Internationalization framework
src/
├── app/ # Top-level application pages
│ ├── authentication/
│ └── dashboard/
├── assets/ # Static assets and global theme
├── components/ # Shared components
│ ├── Atoms/ # Basic building blocks
│ ├── ErrorBoundary/ # Error handling
│ ├── Hoc/ # Higher-order components
│ ├── Layouts/ # Layout components
│ └── Providers/ # Context providers
├── features/ # Feature-specific modules
│ ├── authentication/
│ │ ├── components/
│ │ ├── styles/
│ │ └── types/
│ └── dashboard/
├── hooks/ # Custom hooks
├── lib/ # Configuration and utilities
│ ├── config/ # Application configuration
│ ├── theme/ # Theme configuration
│ ├── translation/ # i18n setup
│ └── utils/ # Utility functions
├── routes/ # Routing configuration
├── services/ # API and authentication services
├── stores/ # Global state management
├── App.tsx # Root application component
└── main.tsx # Application entry point
Responsible for top-level page components that represent entire routes or views in the application.
- Purpose: Compose page-level components using feature-specific components
- Contents:
- High-level page components
- Page-specific layout and structure
- Examples:
authentication/login/index.tsx
: Login page componentdashboard/home/index.tsx
: Dashboard home page
Stores static assets and global styling resources.
- Purpose: Centralize static files and global design tokens
- Contents:
- SVG icons
- Global theme configurations
- Font files
- Global CSS or styling variables
- Examples:
theme/globals.ts
: Global theme configurationreact.svg
: Application logo or icon
Houses shared components used across multiple features.
- Purpose: Provide reusable UI building blocks and common functionality
- Structure:
Atoms/
: Basic UI elements (buttons, inputs, typography)ErrorBoundary/
: Error handling componentsHoc/
: Higher-order components for cross-cutting concernsLayouts/
: Shared layout structuresProviders/
: Context providers for global state/settings
- Examples:
Atoms/Button.tsx
: Reusable button componentLayouts/MainLayout.tsx
: Application shell layoutProviders/ThemeProvider.tsx
: Theme context provider
Organizes feature-specific modules with a modular and scalable approach.
- Purpose: Encapsulate feature-related code with clear boundaries
- Structure:
components/
: Reusable components for the featurestyles/
: Feature-specific stylingtypes/
: TypeScript type definitions
- Examples:
authentication/
: Login, registration, authentication-related codedashboard/
: Dashboard-specific components and logic
components/
:- Reusable React components specific to the feature
- Smaller, focused components that can be composed into pages
styles/
:- Styled-components or CSS modules
- Feature-specific styling logic
types/
:- TypeScript interfaces and type definitions
- Ensures type safety for the feature
Contains custom React hooks for shared functionality.
- Purpose: Abstract common stateful logic and side effects
- Contents:
- Feature-specific hooks
- Utility hooks
- Data fetching hooks
- Examples:
useAuth.ts
: Authentication state and methodsuseForm.ts
: Form handling logicuseLocalStorage.ts
: Local storage interactions
Houses configuration and utility functions.
- Purpose: Centralize application configuration and common utilities
- Structure:
config/
: Application-wide configurationtheme/
: Theme system setuptranslation/
: Internationalization configurationutils/
: Helper functions and utilities
- Examples:
config/constants.ts
: Global constantsutils/formatters.ts
: Data formatting utilitiestranslation/i18n.ts
: Translation setup
Manages application routing configuration.
- Purpose: Define and organize application routes
- Contents:
- Route definitions
- Route protection logic
- Navigation paths
- Key Files:
index.tsx
: Main router configurationpaths.ts
: Centralized route constantsprivate-routes.ts
: Protected route definitionspublic-routes.ts
: Publicly accessible routes
Handles external service interactions and API communications.
- Purpose: Centralize network requests and service logic
- Contents:
- API call implementations
- Authentication service
- External service integrations
- Examples:
api.ts
: Base API configurationauth.ts
: Authentication-related service methods
Manages global state using Zustand.
- Purpose: Provide centralized state management
- Contents:
- Global state stores
- State manipulation logic
- Examples:
useAuthStore.ts
: Authentication state management- Other feature-specific stores
- Modularity: Each feature is self-contained and can be developed independently
- Type Safety: Comprehensive TypeScript usage
- Separation of Concerns: Clear boundaries between different parts of the application
- Scalability: Structure allows easy addition of new features
- Node.js (v22.0.0 or newer)
- PNPM (v9.0.0 or newer)
- Clone the repository
- Run
pnpm install
to install dependencies - Copy
env.example
to.env
and configure your environment variables - Run
pnpm dev
to start the development server - To login, use the following credentials:
- Email:
john@mail.com
- Password:
changeme
- Email:
pnpm dev
: Start development serverpnpm build
: Create production buildpnpm lint
: Run ESLintpnpm preview
: Preview production build
- ESLint: Ensures code quality and catches potential issues
- Prettier: Maintains consistent code formatting
- Husky: Runs linters before commits
We use Zustand for state management in our application. This section outlines our conventions and best practices for working with Zustand stores.
Each store should be defined in a separate file under src/stores
directory. The store file should:
- Define an interface for the store state
- Create and export the store using Zustand's
create
function - Include any necessary actions as part of the store
Example structure:
import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
interface StoreState {
// State properties
someProperty: SomeType;
// Actions
setSomeProperty: (value: SomeType) => void;
}
export const useStore = create<StoreState>()(
devtools(
persist(
// if you need to persist in local storage
(set) => ({
// Initial state and actions implementation
}),
{ name: 'storeName' }
),
{ name: 'Store Name' } // for persist
)
);
We commonly use two middleware functions with our stores:
devtools
: For Redux DevTools integrationpersist
: For persisting store state in localStorage
- Store hooks should be named
useStoreName
(e.g.,useAuthStore
) - Action names should be descriptive and start with a verb (e.g.,
setUser
,updateUser
)
Import and use store hooks in components as follows:
import useStoreName from './path/to/store';
function MyComponent() {
const value = useStoreName((state) => state.someProperty);
const setValue = useStoreName((state) => state.setSomeProperty);
// or
const { value, setValue } = useStoreName();
// Use value and setValue in your component
}
- Keep stores focused on a specific domain or feature
- Use TypeScript for type safety in store definitions
- Prefer multiple small stores over a single large store
- Use selectors to access specific parts of the state
- Clear sensitive data when appropriate (e.g., on logout)
- Use PascalCase for component files (e.g.,
LoginForm.tsx
,UserProfileCard.tsx
). - Use camelCase for other JavaScript/TypeScript files (e.g.,
authService.ts
,userUtils.ts
). - Use lowercase for non-component files and directories (e.g.,
assets/
,features/
).
- Use PascalCase for component names (e.g.,
LoginForm
,UserProfileCard
). - Use descriptive names that reflect the component's purpose.
- For component directories, use PascalCase and keep related files together (e.g.,
LoginForm/LoginForm.tsx
,LoginForm/styles.ts
).
- Use camelCase for variable and function names (e.g.,
userEmail
,handleLogin
). - Use descriptive names that convey purpose.
- For boolean variables, prefix with "is", "has", or "should" (e.g.,
isAuthenticated
,hasPermission
,shouldRefreshData
).
- Use UPPER_SNAKE_CASE (e.g.,
MAX_USER_ATTEMPTS
,API_BASE_URL
). - Group related constants in a single file (e.g.,
constants/index.ts
).
- Use PascalCase (e.g.,
UserProfile
,AuthenticationResponse
).
- Use kebab-case for CSS class names (e.g.,
login-form
,user-profile-card
).
- Prefix with
handle
(e.g.,handleLogin
,handleInputChange
)
- Prefix with
use
(e.g.,useAuthStore
,useUserProfile
)
We use Vitest with React Testing Library for our testing framework.
import { render, screen } from '@testing-library/react';
import { describe, it } from 'vitest';
import MyComponent from './MyComponent';
describe('MyComponent', () => {
it('renders the component', () => {
render(<MyComponent />);
screen.debug();
});
});
pnpm test
: Run all testspnpm test:ui
: Run tests with UIpnpm test:watch
: Run tests in watch mode
- Component Rendering
import { render, screen } from '@testing-library/react';
import Button from './Button';
describe('Button', () => {
it('renders with correct text', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
});
- User Interactions
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
describe('Counter', () => {
it('increments value on click', () => {
render(<Counter />);
fireEvent.click(screen.getByRole('button'));
expect(screen.getByText('Count: 1')).toBeInTheDocument();
});
});
- Async Operations
import { render, screen } from '@testing-library/react';
import UserProfile from './UserProfile';
describe('UserProfile', () => {
it('loads user data', async () => {
render(<UserProfile />);
expect(await screen.findByText('Loading...')).toBeInTheDocument();
expect(await screen.findByText('User Name')).toBeInTheDocument();
});
});
- Create a branch for your feature or bugfix from
dev
branch. Follow the branch name format.git checkout -b feature/feature-name
- Make your changes, ensuring they match our coding standards.
- Make sure there is no merge-conflicts by pulling the
dev
branch. - Issue a pull request and add your teammates as reviewers.
- Respond to any feedback from reviewers.
Follow the Conventional Commits specification:
<type>(ticket-number): <message>
[optional body]
[optional footer(s)]
Types: feat, fix, docs, style, refactor, test, chore.
Example:
feat(AB-000): add login functionality