Skip to main content

Project Structure

DEVELOPER Beginner

Organize your frontend code effectively.

Overview

This guide explains the recommended project structure for EZ-Console frontend applications. Following this structure helps maintain code organization, scalability, and developer productivity.

Standard Directory Structure

web/
├── src/
│ ├── pages/ # Page components
│ │ ├── products/ # Feature-based pages
│ │ │ ├── ProductList.tsx
│ │ │ ├── ProductForm.tsx
│ │ │ └── ProductDetail.tsx
│ │ └── Dashboard.tsx
│ ├── components/ # Reusable components
│ │ ├── common/ # Common components
│ │ │ ├── DataTable.tsx
│ │ │ └── SearchForm.tsx
│ │ └── products/ # Feature-specific components
│ │ └── ProductCard.tsx
│ ├── contexts/ # React contexts
│ │ ├── AuthContext.tsx
│ │ └── AppContext.tsx
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts
│ │ └── usePermission.ts
│ ├── service/ # API services
│ │ ├── api/
│ │ │ ├── product.ts
│ │ │ └── user.ts
│ │ └── client.ts
│ ├── types/ # TypeScript types
│ │ ├── api.d.ts
│ │ └── index.d.ts
│ ├── utils/ # Utility functions
│ │ ├── format.ts
│ │ └── validation.ts
│ ├── i18n/ # Internationalization
│ │ ├── en-US/
│ │ └── zh-CN/
│ ├── routes/ # Route configuration
│ │ └── index.tsx
│ ├── App.tsx # Main app component
│ └── main.tsx # Entry point
├── public/ # Static assets
├── package.json
├── tsconfig.json
├── vite.config.ts
└── index.html

Directory Descriptions

src/pages/

Contains page-level components. Organize by feature:

// src/pages/products/ProductList.tsx
export const ProductList: React.FC = () => {
// Page implementation
};

Best Practices:

  • One page component per file
  • Group related pages in subdirectories
  • Use descriptive names (e.g., ProductList.tsx, not List.tsx)

src/components/

Reusable UI components:

// src/components/common/DataTable.tsx
export const DataTable: React.FC<DataTableProps> = ({ data, columns }) => {
// Component implementation
};

Organization:

  • common/ - Shared components used across features
  • products/ - Feature-specific components
  • Keep components small and focused

src/contexts/

React Context providers:

// src/contexts/AuthContext.tsx
export const AuthProvider: React.FC = ({ children }) => {
// Context implementation
};

Usage:

  • Global state management
  • Shared data across components
  • Avoid overusing contexts

src/hooks/

Custom React hooks:

// src/hooks/useAuth.ts
export const useAuth = () => {
// Hook implementation
return { user, login, logout };
};

Naming Convention:

  • Always start with use
  • Descriptive names (e.g., useAuth, usePermission)

src/service/

API service layer:

// src/service/api/product.ts
export const productService = {
list: (params: ListParams) => apiGet('/products', params),
get: (id: string) => apiGet(`/products/${id}`),
create: (data: Product) => apiPost('/products', data),
update: (id: string, data: Product) => apiPut(`/products/${id}`, data),
delete: (id: string) => apiDelete(`/products/${id}`),
};

Organization:

  • One service file per resource
  • Group related API calls
  • Use TypeScript for type safety

src/types/

TypeScript type definitions:

// src/types/api.d.ts
export interface Product {
id: string;
name: string;
price: number;
category: string;
}

export interface ApiResponse<T> {
code: string;
data: T;
total?: number;
}

Best Practices:

  • Define types close to usage
  • Use interfaces for object shapes
  • Export types for reuse

src/utils/

Utility functions:

// src/utils/format.ts
export const formatCurrency = (amount: number): string => {
return `$${amount.toFixed(2)}`;
};

export const formatDate = (date: Date): string => {
return date.toLocaleDateString();
};

Organization:

  • Group related utilities
  • Keep functions pure when possible
  • Add JSDoc comments

src/i18n/

Internationalization files:

src/i18n/
├── en-US/
│ ├── common.ts
│ └── product.ts
└── zh-CN/
├── common.ts
└── product.ts

Structure:

  • One file per language per namespace
  • Use dot notation for keys
  • Keep translations organized

src/routes/

Route configuration:

// src/routes/index.tsx
export const routes = [
{
path: '/products',
element: <ProductList />,
name: 'products',
},
];

File Naming Conventions

Components

  • PascalCase for components: ProductList.tsx
  • camelCase for utilities: formatDate.ts
  • kebab-case for assets: product-icon.svg

Examples

✅ Good
- ProductList.tsx
- useAuth.ts
- formatDate.ts
- product-icon.svg

❌ Bad
- productList.tsx
- UseAuth.ts
- format_date.ts
- ProductIcon.svg

Import Organization

Organize imports in this order:

// 1. React and React-related
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

// 2. Third-party libraries
import { Button, Table } from 'antd';
import { useRequest } from 'ahooks';

// 3. Framework imports
import { useTranslation, apiGet, PermissionGuard } from 'ez-console';

// 4. Internal imports (absolute paths)
import { ProductService } from '@/service/api/product';
import { formatCurrency } from '@/utils/format';

// 5. Types
import type { Product } from '@/types';

Path Aliases

Configure path aliases in tsconfig.json:

{
"compilerOptions": {
"paths": {
"@/*": ["src/*"],
"@/components/*": ["src/components/*"],
"@/pages/*": ["src/pages/*"],
"@/service/*": ["src/service/*"],
"@/utils/*": ["src/utils/*"],
"@/types/*": ["src/types/*"]
}
}
}

And in vite.config.ts:

import { defineConfig } from 'vite';
import path from 'path';

export default defineConfig({
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});

Feature-Based Organization

For larger applications, organize by feature:

src/
├── features/
│ ├── products/
│ │ ├── components/
│ │ ├── pages/
│ │ ├── hooks/
│ │ ├── service/
│ │ └── types.ts
│ └── users/
│ ├── components/
│ ├── pages/
│ └── ...

Best Practices

1. Keep Components Small

// ✅ Good: Small, focused component
export const ProductCard: React.FC<{ product: Product }> = ({ product }) => {
return <Card>{product.name}</Card>;
};

// ❌ Bad: Too large, does too much
export const ProductPage: React.FC = () => {
// 500+ lines of code
};

2. Extract Reusable Logic

// ✅ Good: Extract to hook
const useProductList = () => {
const [products, setProducts] = useState([]);
// Logic here
return { products, loading, error };
};

// ❌ Bad: Logic in component
const ProductList = () => {
const [products, setProducts] = useState([]);
// Logic mixed with UI
};

3. Use TypeScript

// ✅ Good: Typed props
interface ProductCardProps {
product: Product;
onEdit?: (id: string) => void;
}

// ❌ Bad: No types
const ProductCard = ({ product, onEdit }) => {
// ...
};

4. Consistent File Structure

// ✅ Good: Consistent structure
// 1. Imports
// 2. Types/Interfaces
// 3. Component
// 4. Exports

Need help? Ask in GitHub Discussions.