Modern React Development Environment
Setting up an efficient React development environment is crucial for productivity and code quality. Today's React development involves several tools and configurations that work together to provide a smooth development experience.
The Workshop Analogy
Think of a React development environment like a woodworking workshop:
- Package Manager (npm/yarn/pnpm): Like the supply store where you get your materials and tools
- Build Tools (Webpack/Vite): Like your workbench that holds everything together
- Transpilers (Babel/TypeScript): Like planers and sanders that transform raw wood into usable pieces
- Development Server: Like a showroom where you can view your work in progress
- Linters (ESLint): Like measuring tools that ensure everything is straight and correct
- Formatters (Prettier): Like finishing tools that make your work look polished
- Testing Tools: Like quality control checks before delivery
Just as a well-organized workshop helps a carpenter work efficiently, a properly configured development environment helps React developers build applications more effectively.
Why a Development Environment Matters
A robust React development environment provides several key benefits:
- Developer Experience: Fast feedback loops, helpful error messages, and convenient tooling
- Code Quality: Enforced best practices, automatic formatting, and type checking
- Performance: Optimized production builds and efficient development rebuilds
- Consistency: Standardized code style and structure across teams
- Productivity: Automated tasks and workflows to reduce manual effort
Evolution of React Development Tooling
React development tooling has evolved significantly over the years:
Early Days (2013-2015)
- Manual script tags and simple builds
- Basic Browserify or Gulp configurations
- JSX transformations with standalone tools
- Limited hot-reloading capabilities
Webpack Era (2015-2020)
- Complex Webpack configurations became standard
- Create React App emerged to simplify setup
- Babel gained sophisticated React plugins
- Hot Module Replacement improved developer experience
- ESLint with React plugins became common
Modern Era (2020-Present)
- New build tools like Vite deliver 10-100x faster development builds
- TypeScript adoption has become mainstream
- React frameworks like Next.js and Remix provide integrated experiences
- Testing practices have matured with React Testing Library
- Integrated solutions manage more of the toolchain automatically
Companies like Facebook, Airbnb, and Shopify invest heavily in their React development environments to maximize developer productivity. Many have dedicated teams that maintain custom tooling tailored to their specific needs.
Using Create React App
Create React App (CRA) remains one of the most popular ways to set up a new React project with minimal configuration. It's an officially supported way to create single-page React applications with a robust development environment.
Features of Create React App
- Zero Configuration: Works out of the box with no build configuration needed
- Modern JavaScript Features: Built-in Babel transformation for latest ECMAScript features
- CSS Support: CSS Modules, Sass, and PostCSS processing
- Developer Experience: Fast refresh, runtime error reporting, and development server
- Testing: Built-in Jest setup for unit and integration tests
- Production Optimization: Code splitting, asset optimization, and source maps
- Accessibility Checks: Development-time accessibility warnings
Creating a New React App with CRA
# Using npx (recommended)
npx create-react-app my-app
# Using npm
npm init react-app my-app
# Using yarn
yarn create react-app my-app
# With TypeScript template
npx create-react-app my-app --template typescript
# With specific package manager
npx create-react-app my-app --use-npm
# or
npx create-react-app my-app --use-pnpm
After running these commands, CRA will set up a new project with all the necessary dependencies and configuration. It will also initialize a Git repository and perform an initial commit.
CRA Project Structure
my-app/
├── README.md # Project documentation
├── node_modules/ # Installed packages
├── package.json # Dependencies and scripts
├── .gitignore # Git ignore file
├── public/ # Static files
│ ├── favicon.ico # Favicon file
│ ├── index.html # HTML template
│ ├── logo192.png # Small logo
│ ├── logo512.png # Large logo
│ ├── manifest.json # PWA manifest
│ └── robots.txt # Robots file
└── src/ # Source code
├── App.css # App component styles
├── App.js # Main App component
├── App.test.js # App component test
├── index.css # Global styles
├── index.js # Entry point
├── logo.svg # React logo
├── reportWebVitals.js # Performance monitoring
└── setupTests.js # Test configuration
This structure provides a good starting point for React applications. The src directory is where you'll spend most of your time, adding components, styles, and other application code.
Available Scripts
# Start development server
npm start
# or
yarn start
# Run tests
npm test
# or
yarn test
# Build for production
npm run build
# or
yarn build
# Eject from CRA
npm run eject
# or
yarn eject
Create React App provides these built-in scripts to handle common development tasks. The "eject" command is a one-way operation that exposes all the configuration files and dependencies, giving you full control but removing the ability to receive CRA updates.
Customizing the Environment
# Create .env file in the project root
touch .env
# Add environment variables (must start with REACT_APP_)
# .env file content:
REACT_APP_API_URL=https://api.example.com
REACT_APP_FEATURE_FLAG=true
REACT_APP_VERSION=$npm_package_version
# Using environment variables in your code
function App() {
return (
<div className="App">
<header className="App-header">
<p>API URL: {process.env.REACT_APP_API_URL}</p>
<p>Version: {process.env.REACT_APP_VERSION}</p>
{process.env.REACT_APP_FEATURE_FLAG === 'true' && (
<p>🎉 New feature is enabled!</p>
)}
</header>
</div>
);
}
Environment variables provide a way to customize your application for different environments (development, staging, production) without changing the code. In Create React App, environment variables must start with REACT_APP_ to be included in the bundle.
When to Use Create React App
Create React App is well-suited for many projects, but it's important to understand when it's the right choice:
Good Use Cases for CRA
- Learning React: Ideal for beginners getting started with React
- Single-Page Applications: Well-designed for SPAs with client-side routing
- Prototypes and MVPs: Quick to set up with minimal overhead
- Small to Medium Projects: Provides all essential tools without complexity
- Internal Tools: Great for dashboards and admin interfaces
When to Consider Alternatives
- Server-Side Rendering Needed: Consider Next.js or Remix instead
- Static Site Generation: Gatsby or Next.js might be better options
- Highly Custom Builds: If you need extensive webpack customization
- Performance-Critical Applications: Newer tools like Vite may offer better performance
- Micro-Frontends: May require more specialized setups
Companies often start with Create React App and later migrate to more specialized solutions as their needs evolve. For example, Airbnb began with CRA but eventually created their own build configuration to support their specific requirements.
Modern Alternatives to Create React App
While Create React App has been the go-to solution for years, several modern alternatives have emerged that offer different advantages. Let's explore some of the most popular options.
Vite
Vite (French for "quick") is a build tool created by Evan You, the creator of Vue.js. It has gained significant popularity in the React community due to its exceptional speed and developer experience.
Setting Up a React Project with Vite
# Using npm
npm create vite@latest my-react-app -- --template react
# Using yarn
yarn create vite my-react-app --template react
# Using pnpm
pnpm create vite my-react-app --template react
# With TypeScript
npm create vite@latest my-react-app -- --template react-ts
After creation, you'll need to install dependencies and start the development server:
cd my-react-app
npm install # or yarn or pnpm install
npm run dev # or yarn dev or pnpm dev
Vite Project Structure
my-react-app/
├── README.md # Project documentation
├── node_modules/ # Installed packages
├── package.json # Dependencies and scripts
├── vite.config.js # Vite configuration
├── index.html # HTML template (at root level)
├── public/ # Static files
│ └── vite.svg # Vite logo
└── src/ # Source code
├── App.css # App component styles
├── App.jsx # Main App component
├── index.css # Global styles
├── main.jsx # Entry point
└── assets/ # Static assets
└── react.svg # React logo
Unlike CRA, Vite places the HTML template at the root level and treats it as the entry point. This reflects Vite's approach of leveraging native ES modules during development.
Why Choose Vite?
- Development Speed: Much faster startup and hot module replacement
- Modern Architecture: Native ES modules in development, optimized rollup build for production
- Lean Configuration: Simpler and more transparent than webpack-based setups
- Plugin Ecosystem: Growing selection of plugins for various needs
- Active Development: Receiving regular updates and improvements
Next.js
Next.js is a full-featured React framework that provides server-side rendering, static site generation, and other advanced features out of the box.
Setting Up a Next.js Project
# Using npx
npx create-next-app@latest my-next-app
# Using yarn
yarn create next-app my-next-app
# Using pnpm
pnpm create next-app my-next-app
# With TypeScript
npx create-next-app@latest my-next-app --typescript
After creation, you can start the development server:
cd my-next-app
npm run dev # or yarn dev or pnpm dev
Next.js Project Structure
my-next-app/
├── README.md # Project documentation
├── node_modules/ # Installed packages
├── package.json # Dependencies and scripts
├── .eslintrc.json # ESLint configuration
├── next.config.js # Next.js configuration
├── public/ # Static files
│ ├── favicon.ico # Favicon file
│ └── vercel.svg # Vercel logo
└── pages/ # File-based routing
├── _app.js # Custom App component
├── _document.js # Custom Document component
├── index.js # Home page
└── api/ # API routes
└── hello.js # Example API endpoint
└── styles/ # CSS styles
├── globals.css # Global styles
└── Home.module.css # CSS modules
Next.js uses a file-based routing system where files in the pages directory automatically become routes. This is a key difference from CRA and Vite.
Why Choose Next.js?
- Server-Side Rendering (SSR): Improved SEO and initial load performance
- Static Site Generation (SSG): Pre-render pages at build time
- Incremental Static Regeneration: Update static pages after deployment
- API Routes: Build API endpoints alongside your frontend
- File-Based Routing: Intuitive routing based on file structure
- Image Optimization: Automatic image optimization with next/image
- Production-Ready: Optimized for deployment on Vercel or other platforms
Remix
Remix is a newer React framework that focuses on web fundamentals and progressive enhancement. It was created by the team behind React Router.
Setting Up a Remix Project
# Using npx
npx create-remix@latest my-remix-app
# When prompted, choose:
# - Just the basics
# - Remix App Server
# - TypeScript or JavaScript
# - Run npm install
# Start the development server
cd my-remix-app
npm run dev
Remix will guide you through a few decisions during setup, allowing you to customize your starting point.
Remix Project Structure
my-remix-app/
├── README.md # Project documentation
├── node_modules/ # Installed packages
├── package.json # Dependencies and scripts
├── remix.config.js # Remix configuration
├── app/ # Application code
│ ├── entry.client.tsx # Client entry point
│ ├── entry.server.tsx # Server entry point
│ ├── root.tsx # Root component
│ ├── routes/ # Route components
│ │ ├── index.tsx # Home page
│ │ └── about.tsx # About page
│ └── styles/ # CSS styles
│ └── global.css # Global styles
├── public/ # Static files
│ └── favicon.ico # Favicon file
└── server.js # Server entry point
Remix uses a nested route structure in the app/routes directory, which is different from both CRA and Next.js approaches.
Why Choose Remix?
- Nested Routing: Advanced routing with nested layouts
- Data Loading: Parallel data loading at the route level
- Progressive Enhancement: Works even without JavaScript
- Form Handling: First-class support for HTML forms
- Error Boundaries: Built-in error handling at the route level
- Modern UX Patterns: Built-in support for optimistic UI and transitions
- Multiple Deployment Targets: Deploy to various platforms
Comparison of Modern React Setups
| Feature | Create React App | Vite | Next.js | Remix |
|---|---|---|---|---|
| Development Speed | Moderate | Very Fast | Fast | Fast |
| SSR Support | No | No (needs plugins) | Yes | Yes |
| Routing | Manual (React Router) | Manual (React Router) | File-based | File-based (nested) |
| API Routes | No | No | Yes | Yes (loader/action) |
| Bundle Size | Larger | Smaller | Optimized | Optimized |
| Configuration | Hidden (Eject needed) | Minimal, transparent | Moderate | Moderate |
| Learning Curve | Low | Low | Moderate | Moderate-High |
| Ideal For | SPAs, Learning | SPAs, Fast Development | SEO, Production Apps | UX-focused Apps |
Companies often choose different tools based on their specific needs:
- Shopify: Uses Next.js for many customer-facing pages to optimize SEO
- Netflix: Uses custom CRA-like setups for their internal dashboards
- Airbnb: Uses a custom build system with SSR capabilities
- Meta: Uses custom internal tools but contributes to create-react-app
Many companies are migrating from Create React App to Vite for faster development experience or to Next.js for better SEO and performance.
Development Environment Customization
Regardless of which tool you choose to start your React project, you'll likely want to customize your development environment to suit your team's needs and preferences.
Code Quality Tools
Ensuring code quality is essential for maintainable React applications. Here are some essential tools:
ESLint Configuration
# Install ESLint with React support
npm install --save-dev eslint eslint-plugin-react eslint-plugin-react-hooks
# Create ESLint configuration file
# .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['react', 'react-hooks'],
rules: {
// Custom rules
'react/prop-types': 'warn',
'react/react-in-jsx-scope': 'off', // Not needed in React 17+
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'no-unused-vars': 'warn',
},
settings: {
react: {
version: 'detect',
},
},
};
This configuration enforces React best practices, including the Rules of Hooks. You can adjust the rules to match your team's preferences.
Prettier Configuration
# Install Prettier
npm install --save-dev prettier
# Create Prettier configuration file
# .prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 80,
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid"
}
# Create .prettierignore file
# .prettierignore
build
dist
node_modules
coverage
Prettier ensures consistent code formatting across your team, reducing code review discussions about style.
Integrating ESLint with Prettier
# Install integration packages
npm install --save-dev eslint-config-prettier eslint-plugin-prettier
# Update ESLint configuration
# .eslintrc.js
module.exports = {
// Previous config...
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended', // Add this line
],
// Rest of config...
};
This integration ensures that ESLint and Prettier work together without conflicts.
TypeScript Integration
Adding TypeScript to your React project provides type safety and better IDE support.
Adding TypeScript to an Existing Project
# Install TypeScript and React types
npm install --save-dev typescript @types/react @types/react-dom @types/node
# Create a basic tsconfig.json file
# tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
After setting up TypeScript, you can gradually convert your .js/.jsx files to .ts/.tsx files.
Converting a Component to TypeScript
// Before: UserProfile.jsx
import React from 'react';
function UserProfile({ name, age, roles }) {
return (
<div className="user-profile">
<h2>{name}, {age}</h2>
<ul>
{roles.map(role => (
<li key={role}>{role}</li>
))}
</ul>
</div>
);
}
export default UserProfile;
// After: UserProfile.tsx
import React from 'react';
interface UserProfileProps {
name: string;
age: number;
roles: string[];
isActive?: boolean; // Optional prop
}
function UserProfile({ name, age, roles, isActive = true }: UserProfileProps) {
return (
<div className={`user-profile ${isActive ? 'active' : 'inactive'}`}>
<h2>{name}, {age}</h2>
<ul>
{roles.map(role => (
<li key={role}>{role}</li>
))}
</ul>
</div>
);
}
export default UserProfile;
TypeScript provides clear documentation of the component's API through interfaces, making it easier for other developers to use your components correctly.
Customizing Build Configuration
Sometimes you need to customize the build configuration to add features or optimize performance.
Create React App Configuration
# Using CRACO (Create React App Configuration Override)
npm install --save-dev @craco/craco
# Create craco.config.js in the project root
# craco.config.js
const path = require('path');
module.exports = {
webpack: {
alias: {
'@components': path.resolve(__dirname, 'src/components'),
'@hooks': path.resolve(__dirname, 'src/hooks'),
'@utils': path.resolve(__dirname, 'src/utils'),
'@styles': path.resolve(__dirname, 'src/styles'),
},
plugins: [
// Add custom webpack plugins here
],
},
style: {
postcss: {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
],
},
},
};
# Update package.json scripts
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "react-scripts eject"
}
CRACO allows you to customize the webpack configuration without ejecting from Create React App.
Vite Configuration
# vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
},
},
server: {
port: 3000,
open: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
build: {
outDir: 'build',
sourcemap: true,
chunkSizeWarningLimit: 1600,
},
});
Vite has a more straightforward configuration system that's easier to customize.
Next.js Configuration
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ['images.example.com', 'cdn.someservice.com'],
},
async redirects() {
return [
{
source: '/old-page',
destination: '/new-page',
permanent: true,
},
];
},
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
];
},
env: {
NEXT_PUBLIC_ANALYTICS_ID: 'your-analytics-id',
},
}
module.exports = nextConfig
Next.js has its own configuration system that provides features specific to its architecture, such as image optimization, redirects, and rewrites.
Environment Customization in Practice
In professional React projects, development environments often include additional customizations:
Git Hooks with Husky
# Install Husky and lint-staged
npm install --save-dev husky lint-staged
# Setup Husky
npx husky install
npm set-script prepare "husky install"
# Add a pre-commit hook
npx husky add .husky/pre-commit "npx lint-staged"
# Configure lint-staged in package.json
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,md}": [
"prettier --write"
]
}
This setup ensures that all code is linted and formatted before being committed, maintaining code quality standards.
Custom Development Proxies
Real-world applications often need to communicate with APIs during development:
// For Create React App, in package.json:
"proxy": "http://localhost:8080"
// For more complex scenarios, create a setupProxy.js file:
// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:8080',
changeOrigin: true,
})
);
app.use(
'/auth',
createProxyMiddleware({
target: 'http://localhost:8081',
changeOrigin: true,
})
);
};
Testing Configuration
Comprehensive testing setups for React applications:
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
},
transform: {
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
coverageThreshold: {
global: {
branches: 70,
functions: 70,
lines: 70,
statements: 70,
},
},
};
// src/setupTests.js
import '@testing-library/jest-dom';
Companies like Airbnb, Shopify, and Netflix invest significant effort in customizing their development environments to maximize developer productivity and code quality. These customizations often evolve over time as the team learns what works best for their specific needs.
Developer Tools and Extensions
A powerful development environment extends beyond the project setup to include browser tools and IDE extensions that enhance productivity.
React Developer Tools
React Developer Tools is a browser extension that allows you to inspect the React component tree and the props and state of your components.
React Developer Tools is available for:
- Chrome Extension
- Firefox Add-on
- Standalone App (for Safari and React Native)
Key Features:
- Component Inspection: View the React component tree and component properties
- State and Props Monitoring: Inspect and edit component state and props
- Performance Profiling: Identify performance bottlenecks in your components
- Component Filtering: Find specific components in complex applications
- Context Inspection: Examine React Context values
- Hook Debugging: Inspect hooks like useState and useEffect
VS Code Extensions for React Development
Visual Studio Code has become the most popular editor for React development due to its extensive extension ecosystem.
Essential VS Code Extensions:
- ESLint: Integrates ESLint into VS Code for real-time linting
- Prettier - Code formatter: Formats your code according to Prettier rules
- ES7+ React/Redux/React-Native snippets: Provides useful code snippets for React development
- Auto Import: Automatically finds, parses and provides code actions for imports
- Path Intellisense: Autocompletes filenames in import statements
- Import Cost: Displays the size of imported packages
- Error Lens: Improves error visibility by highlighting errors inline
- Jest Runner: Run and debug Jest tests from the editor
- GitHub Copilot: AI-assisted code suggestions (paid)
TypeScript-Specific Extensions:
- TypeScript React code snippets: Snippets for TypeScript React development
- TypeScript Hero: Organizes your imports
- Move TS: Move TypeScript files and update imports
Browser Extensions for Web Development
- Redux DevTools: Debug Redux state management
- Axe DevTools: Accessibility testing
- Web Vitals: Measure Core Web Vitals in real-time
- JSON Formatter: Format and validate JSON
- Apollo Client DevTools: Debug GraphQL queries and cache (if using Apollo)
Professional Development Workflows
Experienced React developers typically set up their development environment to maximize productivity:
IDE Setup
- Custom VS Code Settings: Teams often share a standardized .vscode/settings.json file in their repositories
- Snippets Library: Custom snippets for company-specific patterns
- Custom Key Bindings: Shortcuts for common React operations
Example VS Code Settings for React Projects
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"typescript.tsdk": "node_modules/typescript/lib",
"javascript.updateImportsOnFileMove.enabled": "always",
"typescript.updateImportsOnFileMove.enabled": "always",
"emmet.includeLanguages": {
"javascript": "javascriptreact",
"typescript": "typescriptreact"
},
"workbench.colorCustomizations": {
"activityBar.background": "#282c34",
"titleBar.activeBackground": "#282c34",
"titleBar.activeForeground": "#61dafb"
}
}
Terminal and Git Integration
Many developers integrate terminals and Git directly into their workflow:
- VS Code Integrated Terminal: Running development servers and commands without switching context
- Git Lens: View file history and blame information inline
- GitHub Pull Requests: Review and manage PRs from within VS Code
Component Development
Tools that assist in developing and testing components:
- Storybook: Develop and test UI components in isolation
- Bit.dev: Share and reuse components across projects
- Figma/Sketch Integration: Plugins that connect design tools to code
Companies like Airbnb provide comprehensive onboarding documentation for their preferred development environment setup, ensuring that all developers have a consistent and productive experience.
Practical Exercise: Setting Up Your React Environment
Let's put everything we've learned into practice by setting up a complete React development environment.
Complete React Environment Setup
Objective: Create a modern React development environment with TypeScript, ESLint, Prettier, and testing tools.
Requirements:
- Choose and set up a React project using one of the tools we discussed (CRA, Vite, or Next.js)
- Configure TypeScript for type safety
- Set up ESLint with React-specific rules
- Configure Prettier for consistent formatting
- Add Git hooks with Husky and lint-staged
- Configure path aliases for better imports
- Set up a basic testing environment
- Create a simple React component to verify the setup
Step-by-Step Instructions:
1. Project Setup
# Choose one of these options:
# Option A: Create React App with TypeScript
npx create-react-app my-react-app --template typescript
# Option B: Vite with TypeScript
npm create vite@latest my-react-app -- --template react-ts
# Option C: Next.js with TypeScript
npx create-next-app@latest my-react-app --typescript
# Navigate to the project directory
cd my-react-app
2. ESLint and Prettier Setup
# Install ESLint and Prettier dependencies
npm install --save-dev eslint-config-prettier eslint-plugin-prettier prettier
# Create .prettierrc file
echo '{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}' > .prettierrc
# Create .prettierignore file
echo 'build
dist
node_modules
coverage
.next
out' > .prettierignore
3. ESLint Configuration
Create or update .eslintrc.js:
module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:@typescript-eslint/recommended',
'prettier'
],
plugins: ['react', 'react-hooks', '@typescript-eslint', 'prettier'],
rules: {
'prettier/prettier': 'error',
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off'
},
settings: {
react: {
version: 'detect'
}
},
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 2021,
sourceType: 'module'
},
env: {
browser: true,
es2021: true,
node: true
}
};
4. Git Hooks Setup
# Install Husky and lint-staged
npm install --save-dev husky lint-staged
# Setup Husky
npx husky install
npm set-script prepare "husky install"
npx husky add .husky/pre-commit "npx lint-staged"
# Configure lint-staged in package.json
# Add this to your package.json:
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,css,md}": [
"prettier --write"
]
}
5. Path Aliases Setup
For TypeScript, update tsconfig.json:
// Add to compilerOptions in tsconfig.json
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"],
"@styles/*": ["src/styles/*"]
}
For Vite, update vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@styles': path.resolve(__dirname, './src/styles')
}
}
});
6. Create Project Structure
# Create directory structure
mkdir -p src/components/ui
mkdir -p src/hooks
mkdir -p src/utils
mkdir -p src/styles
mkdir -p src/pages # For Next.js or client-side routing
7. Create a Sample Component
Create src/components/ui/Button.tsx:
import React from 'react';
interface ButtonProps {
children: React.ReactNode;
variant?: 'primary' | 'secondary' | 'danger';
size?: 'small' | 'medium' | 'large';
onClick?: () => void;
disabled?: boolean;
}
const Button: React.FC<ButtonProps> = ({
children,
variant = 'primary',
size = 'medium',
onClick,
disabled = false
}) => {
const baseClasses = 'rounded font-semibold transition-colors';
const variantClasses = {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
danger: 'bg-red-500 text-white hover:bg-red-600'
};
const sizeClasses = {
small: 'px-3 py-1 text-sm',
medium: 'px-4 py-2',
large: 'px-6 py-3 text-lg'
};
const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : '';
const classes = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${disabledClasses}`;
return (
<button
className={classes}
onClick={onClick}
disabled={disabled}
type="button"
>
{children}
</button>
);
};
export default Button;
8. Add a Simple Test
Create src/components/ui/Button.test.tsx:
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';
describe('Button component', () => {
test('renders button with children', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
test('calls onClick handler when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
test('is disabled when disabled prop is true', () => {
render(<Button disabled>Click me</Button>);
expect(screen.getByText('Click me')).toBeDisabled();
});
});
9. Use the Component in Your App
Update src/App.tsx to use your new component:
import React, { useState } from 'react';
import Button from '@components/ui/Button';
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<header className="App-header">
<h1>React Environment Setup</h1>
<p>Count: {count}</p>
<div className="flex gap-2">
<Button
variant="primary"
onClick={() => setCount(count + 1)}
>
Increment
</Button>
<Button
variant="secondary"
onClick={() => setCount(count - 1)}
disabled={count === 0}
>
Decrement
</Button>
<Button
variant="danger"
onClick={() => setCount(0)}
size="small"
>
Reset
</Button>
</div>
</header>
</div>
);
}
export default App;
10. Run the Application
# Start the development server
npm start # for CRA
# or
npm run dev # for Vite or Next.js
# Run tests
npm test
# Check linting
npx eslint src --ext .ts,.tsx
Bonus Challenge: Add Tailwind CSS to your project for styling, or integrate Storybook for component development and documentation.