Vite + React Project Structure
This skill documents the file organization and naming conventions for the OSCAR Export Analyzer codebase, which follows Vite + React best practices.
Directory Structure
code
src/ ├── components/ # All React components (.jsx) │ ├── charts/ # Chart components grouped by feature │ ├── fitbit/ # Fitbit-related components grouped │ ├── ComponentName.jsx │ └── ComponentName.test.jsx ├── hooks/ # All custom React hooks (.js) │ ├── hookName.js │ └── hookName.test.js ├── utils/ # Utility functions (.js) │ ├── utilName.js │ └── utilName.test.js ├── workers/ # Web Worker files (.js) │ └── workerName.js ├── context/ # React Context providers (.js) │ └── ContextName.jsx ├── constants/ # Constant definitions (.js) │ └── constantsName.js ├── features/ # Feature modules (complex features) │ └── featureName/ │ ├── components/ │ ├── hooks/ │ └── utils/ ├── test-utils/ # Shared test utilities │ ├── builders.js │ ├── mockHooks.js │ └── fixtures/ ├── app/ # App-level components │ ├── AppProviders.jsx │ └── AppShell.jsx ├── App.jsx # Main application component ├── main.jsx # Entry point └── setupTests.js # Test configuration
Naming Conventions
Components
Files:
- •PascalCase:
UsagePatternsCharts.jsx - •Test files:
UsagePatternsCharts.test.jsx - •Use
.jsxextension for files containing JSX
Examples:
code
src/components/
├── DateRangeControls.jsx
├── DateRangeControls.test.jsx
├── ExportDataModal.jsx
├── ExportDataModal.test.jsx
├── charts/
│ ├── UsagePatternsCharts.jsx
│ ├── UsagePatternsCharts.test.jsx
│ ├── AhiTrendsCharts.jsx
│ └── AhiTrendsCharts.test.jsx
└── fitbit/
├── FitbitConnection.jsx
├── FitbitConnection.test.jsx
├── FitbitCharts.jsx
└── FitbitCharts.test.jsx
Hooks
Files:
- •camelCase with
useprefix:useDateRangeFilter.js - •Test files:
useDateRangeFilter.test.js - •Use
.jsextension (hooks typically don't have JSX)
Examples:
code
src/hooks/ ├── useAppState.js ├── useAppState.test.js ├── useCSVUpload.js ├── useCSVUpload.test.js ├── useDateRangeFilter.js └── useDateRangeFilter.test.js
Utilities
Files:
- •camelCase:
dateFilter.js,statsCalculations.js - •Test files:
dateFilter.test.js - •Group related utilities in single file
Examples:
code
src/utils/ ├── dateFilter.js ├── dateFilter.test.js ├── statsCalculations.js ├── statsCalculations.test.js ├── csvParsing.js └── csvParsing.test.js
Constants
Files:
- •camelCase:
thresholds.js,chartConfig.js - •Constants inside: UPPER_SNAKE_CASE
Example:
javascript
// src/constants/thresholds.js export const AHI_NORMAL = 5; export const AHI_MILD = 15; export const AHI_MODERATE = 30; export const EPAP_MIN = 4.0; export const EPAP_MAX = 25.0;
Workers
Files:
- •camelCase with
.worker.jssuffix:csvParser.worker.js - •Vite recognizes
*.worker.jspattern
Examples:
code
src/workers/ ├── csvParser.worker.js ├── analytics.worker.js └── fitbitApi.worker.js
Test Collocation
Key principle: Tests live next to the code they test.
code
src/components/UsagePatternsCharts.jsx src/components/UsagePatternsCharts.test.jsx ← Same directory src/hooks/useDateRangeFilter.js src/hooks/useDateRangeFilter.test.js ← Same directory src/utils/dateFilter.js src/utils/dateFilter.test.js ← Same directory
Exception: App-level integration tests can live in src/tests/ for clarity:
code
src/tests/
├── integration/
│ ├── csvUploadFlow.test.jsx
│ └── chartInteraction.test.jsx
└── e2e/
├── fullWorkflow.test.jsx
└── fitbitIntegration.test.jsx
Feature Modules
Complex features with multiple components can be grouped:
code
src/features/fitbit/
├── components/
│ ├── FitbitConnection.jsx
│ ├── FitbitConnection.test.jsx
│ ├── FitbitCharts.jsx
│ └── FitbitCharts.test.jsx
├── hooks/
│ ├── useFitbitAuth.js
│ ├── useFitbitAuth.test.js
│ ├── useFitbitData.js
│ └── useFitbitData.test.js
├── utils/
│ ├── fitbitEncryption.js
│ └── fitbitEncryption.test.js
└── workers/
└── fitbitApi.worker.js
When to use feature modules:
- •Feature has 3+ related components
- •Feature has dedicated hooks/utilities
- •Feature is logically independent
- •Examples: Fitbit integration, chart system, clustering analysis
When NOT to use:
- •Single component or simple utility
- •Shared across multiple features
- •Core app infrastructure
Import Patterns
Relative imports within feature
javascript
// src/features/fitbit/components/FitbitCharts.jsx
import { useFitbitData } from '../hooks/useFitbitData';
import { encryptToken } from '../utils/fitbitEncryption';
Absolute imports from src root
javascript
// Any component
import { buildSession } from '@/test-utils/builders'; // if alias configured
import { AHI_NORMAL } from '@/constants/thresholds';
// Or use Vite's relative paths
import { buildSession } from '../../../test-utils/builders';
Import ordering (ESLint rule)
javascript
// 1. External dependencies
import React, { useState, useEffect } from 'react';
import Plot from 'react-plotly.js';
// 2. Internal modules (absolute imports)
import { useData } from '@/context/DataContext';
import { AHI_NORMAL } from '@/constants/thresholds';
// 3. Relative imports
import { ChartWrapper } from './ChartWrapper';
import './styles.css';
App-Level Organization
Entry point (main.jsx)
javascript
// Minimal - just bootstrap React
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
App component (App.jsx)
javascript
// Orchestrates top-level hooks and renders shell
import { AppProviders } from './app/AppProviders';
import { AppShell } from './app/AppShell';
function App() {
return (
<AppProviders>
<AppShell />
</AppProviders>
);
}
App providers (app/AppProviders.jsx)
javascript
// Centralizes all context providers
export function AppProviders({ children }) {
return (
<DataProvider>
<ThemeProvider>
<UserPreferencesProvider>{children}</UserPreferencesProvider>
</ThemeProvider>
</DataProvider>
);
}
File Location Rules
Components go in src/components/:
- •✅
src/components/DateRangeControls.jsx - •❌
src/DateRangeControls.jsx(not in root) - •❌
src/utils/DateRangeControls.jsx(not a utility)
Hooks go in src/hooks/:
- •✅
src/hooks/useDateRangeFilter.js - •❌
src/components/useDateRangeFilter.js(wrong directory)
Tests colocated next to code:
- •✅
src/components/DateRangeControls.test.jsx - •❌
src/tests/DateRangeControls.test.jsx(unless integration test)
Utilities centralized in src/utils/:
- •✅
src/utils/dateFilter.js - •❌
src/components/dateFilter.js(extract to utils)
Common Violations
Wrong: Component in src root
code
❌ src/MyComponent.jsx ✅ src/components/MyComponent.jsx
Wrong: Non-colocated tests
code
❌ src/tests/MyComponent.test.jsx ❌ src/__tests__/MyComponent.test.jsx ✅ src/components/MyComponent.test.jsx
Wrong: Inconsistent file extensions
code
❌ src/components/MyComponent.js (should be .jsx if has JSX) ✅ src/components/MyComponent.jsx
Wrong: Utilities in components
code
❌ src/components/dateFilterHelper.js ✅ src/utils/dateFilter.js
Wrong: Hooks not prefixed with 'use'
code
❌ src/hooks/dateRangeFilter.js ✅ src/hooks/useDateRangeFilter.js
Resources
- •Project structure: Inspect
src/directory tree - •Vite config:
vite.config.js(import aliases, worker config) - •ESLint config:
eslint.config.js(import rules)