import { StrictMode } from 'react'; import { createRoot, hydrateRoot } from 'react-dom/client'; import { HelmetProvider } from '@dr.pogodin/react-helmet'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import AiroErrorBoundary from '../dev-tools/src/AiroErrorBoundary'; import App from './App'; import './styles/globals.css'; if (import.meta.env.MODE === 'development') { const meta = document.createElement('meta'); meta.name = 'robots'; meta.content = 'noindex, nofollow'; document.head.appendChild(meta); } const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, gcTime: 1000 * 60 * 10, retry: 1, refetchOnWindowFocus: false, }, mutations: { retry: 0 }, }, }); const rootElement = document.getElementById('app'); if (!rootElement) throw new Error('Root element not found'); const providers = ( ); // Root-level dev error boundary. The inner boundary in App.tsx lives // inside the route element (so it can catch route render errors before // React Router swaps in its own error UI), which leaves everything // OUTSIDE the router uncaught: provider crashes, errors in App itself, // and render errors in components mounted as siblings of // (e.g. an analytics loader calling useLocation() outside the router). // Those throw on first render before the inner boundary ever mounts, so // only an ancestor boundary above the providers can catch them. This // boundary also owns the global window.onerror/unhandledrejection // handlers (the inner one opts out via captureGlobalErrors={false}). const tree = ( {import.meta.env.MODE === 'development' ? ( {providers} ) : ( providers )} ); // SSR markup is detected via a child element inside the #app root. hydrateRoot // reattaches to the server-rendered tree; createRoot mounts fresh for dev/ // pre-SSR fallback. if (rootElement.firstElementChild) { hydrateRoot(rootElement, tree); } else { createRoot(rootElement).render(tree); }