The Anatomy of a React Project

A scaffolded project has fewer moving parts than it looks. Everything below src/ is yours; everything above it is configuration you will touch a few times a year.

What create-vite generates for the React templateJSX
catalog/
├─ index.html          the real entry point: loads /src/main.jsx as a module
├─ package.json        dependencies and the dev / build / preview scripts
├─ vite.config.js      Vite plugins; the React plugin enables JSX and HMR
├─ public/             copied to dist/ byte for byte, served as /favicon.svg
└─ src/
   ├─ main.jsx         creates the React root and renders <App />
   ├─ App.jsx          the root component; index.css and App.css sit beside it
   └─ assets/          images imported from code, hashed at build time

index.html sitting in the project root surprises people who expect it under public/. Vite 25,978 treats HTML as a source file: it parses the page, rewrites <script type="module" src="/src/main.jsx"> to point at the bundled output, and injects the stylesheet links. Files in public/ are the opposite — never processed, never hashed, always at the path you give them. Use public/ for robots.txt and favicons, src/assets/ for anything you import.

src/main.jsx, the bridge between the page and ReactJSX
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

Those lines are the whole boundary between the DOM and React 7,897 . createRoot claims the <div id="root"> from index.html, and render hands it a component tree. StrictMode renders nothing itself; in development it double-invokes components and effects to surface impure code and missing cleanup (Strict Mode), and it is stripped from production builds. Importing a CSS file from JavaScript is a bundler convention, not a React one.