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.
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 timeindex.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.
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.