Chapter 4: Creating a React Application
Scaffolding a project is only the first step. To build scalable software, professional engineers must understand project configuration files, maintain modular folder architectures, manage environment variables securely, and execute optimized production builds.
1. Project Scaffolding & Initial Commands
We will initialize a clean, modern React project using Vite. Run the following command in your terminal:
# 1. Initialize project directory with React template npm create vite@latest hifi-react-store -- --template react # 2. Enter project directory cd hifi-react-store # 3. Install core dependencies npm install # 4. Start local development server npm run dev
Your terminal will display a local URL (typically http://localhost:5173/). Any modifications made to your source files will immediately reflect in the browser without losing component state viaHot Module Replacement (HMR).
2. Dissecting Project Configuration Files
Let's examine the core files that orchestrate your project's dependencies, compilation, and behavior:
A. The `package.json` File
The manifest containing project metadata, executable scripts, and required dependencies:
{
"name": "hifi-react-store",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite", // Starts instant local development server
"build": "vite build", // Transpiles, bundles, and minifies for production
"lint": "eslint .", // Scans codebase for code quality & React hook bugs
"preview": "vite preview" // Spreads production dist/ bundle locally for testing
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^9.9.0",
"vite": "^5.4.1"
}
}B. The `vite.config.js` File
Controls the compilation pipeline. You can configure plugins, path aliases, and backend proxy tunnels here:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
// Allows using '@/components/Button' instead of '../../components/Button'
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 3000, // Customize dev server port
proxy: {
// Route API requests to a backend server to prevent CORS issues in development
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
},
},
},
});3. Managing Environment Variables Securely
Never hardcode API endpoint URLs, payment keys, or configuration constants directly into your source code. Instead, store them in environment files:
| File Name | Purpose & Git Tracking |
|---|---|
.env | Default variables loaded in all environments. Tracked in git unless containing secrets. |
.env.development | Variables loaded only during npm run dev (e.g., local mock API endpoints). |
.env.production | Variables loaded during npm run build (e.g., production cloud API URLs). |
.env.local | Local override file containing sensitive secrets. MUST be added to .gitignore! |
Any environment variable prefixed with VITE_ or bundled into client-side JavaScript ispublicly readable by anyone who opens your website and inspects the bundle in browser DevTools.NEVER store private API secret keys, database passwords, or private signing tokens in frontend .env files!
Example usage in Vite:
// .env
VITE_API_BASE_URL=https://api.hifitoolkit.com/v1
// In your React Component (e.g., src/services/api.js):
const API_URL = import.meta.env.VITE_API_BASE_URL;
export async function fetchCatalog() {
const response = await fetch(`${API_URL}/products`);
return response.json();
}4. Scalable Folder Architecture for Enterprise Projects
As applications expand past 50 components, flat structures become unmaintainable. The industry standard pattern organizes files by feature/domain alongside shared core utilities:
src/ ├── assets/ # Global static media (images, fonts, vector icons) ├── components/ # Shared, domain-agnostic UI primitives (Button, Modal, Input, Navbar) │ ├── Button/ │ │ ├── Button.jsx │ │ ├── Button.module.css │ │ └── Button.test.jsx ├── context/ # Global React Context providers (AuthContext, ThemeContext) ├── features/ # Domain-specific modules (User, Checkout, Products) │ ├── auth/ │ │ ├── components/ # LoginForm.jsx, RegisterModal.jsx │ │ ├── hooks/ # useAuth.js │ │ └── services/ # authApi.js │ └── cart/ │ ├── components/ # CartDrawer.jsx, CartItem.jsx │ └── hooks/ # useCart.js ├── hooks/ # Global custom hooks (useDebounce, useMediaQuery, useLocalStorage) ├── layouts/ # Page shell wrappers (MainLayout.jsx, DashboardLayout.jsx) ├── pages/ # Routed view screens (HomePage.jsx, ProductDetailPage.jsx) ├── services/ # HTTP clients and base Axios / Fetch configurations ├── utils/ # Pure helper functions (formatCurrency.js, formatDate.js) ├── App.jsx # Top-level root router and providers └── main.jsx # DOM mount entry point
5. Building for Production & Deployment Pipelines
When you are ready to ship your application to live users, run the build command:
npm run build
Vite executes the following automated pipeline:
- Tree-Shaking: Removes unused library code and functions.
- Minification: Strips whitespace, comments, and shortens variable names using Terser / esbuild.
- Code-Splitting: Breaks large bundles into smaller asynchronous chunks loaded only when routes are accessed.
- Asset Hashing: Appends content hashes to filenames (e.g.,
index-B1z9eA.js) to enable long-term browser cache invalidation.
Previewing the Production Bundle Locally:
npm run preview
Deploying to Modern Hosting Providers:
| Hosting Provider | Build Command | Publish / Output Directory |
|---|---|---|
| Vercel | npm run build | dist |
| Netlify | npm run build | dist |
| GitHub Pages | npm run build | dist |
| AWS S3 + CloudFront | npm run build | dist |
Frequently Asked Questions (FAQ)
What is the difference between dependencies and devDependencies in package.json?
Dependencies are packages required for the application to run in production (e.g., react, react-dom, react-router-dom). DevDependencies are packages only needed during local development and build time (e.g., vite, eslint, prettier, typescript, test runners). DevDependencies are stripped away during the production build.
How do environment variables work in Vite compared to Create React App?
In Vite, environment variables in your .env file must be prefixed with 'VITE_' (e.g., VITE_API_URL=https://api.example.com) and are accessed in client code via 'import.meta.env.VITE_API_URL'. In legacy Create React App, they were prefixed with 'REACT_APP_' and accessed via 'process.env.REACT_APP_API_URL'.
What is tree-shaking during the production build?
Tree-shaking is a dead-code elimination technique performed by module bundlers (like Rollup in Vite or Webpack). Because ES Modules use static 'import' and 'export' syntax, the bundler analyzes your code and excludes any exported functions or modules that are never actually called, reducing production bundle size.
How do you test a production build locally before deploying?
After compiling your production bundle with 'npm run build', you can immediately spin up a local preview server matching production behavior by executing 'npm run preview' in Vite, or using the 'serve -s dist' utility.
Explore Related Tools
Hand-picked utilities and calculators related to this tool.
