Первоначальная версия VidConf
This commit is contained in:
67
frontend/src/main.tsx
Normal file
67
frontend/src/main.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
// Шрифты дизайн-системы — self-hosted через @fontsource (без внешних CDN),
|
||||
// импортируются ДО ./index.css, чтобы @font-face объявились раньше стилей.
|
||||
// Агрегатные <вес>.css включают все subset'ы, включая кириллицу (интерфейс
|
||||
// русский). Веса — по DESIGN_SYSTEM.md: Unbounded 400/600/700 (display),
|
||||
// Inter 400/500/600/700 (body), JetBrains Mono 500 (mono).
|
||||
import '@fontsource/unbounded/400.css'
|
||||
import '@fontsource/unbounded/600.css'
|
||||
import '@fontsource/unbounded/700.css'
|
||||
import '@fontsource/inter/400.css'
|
||||
import '@fontsource/inter/500.css'
|
||||
import '@fontsource/inter/600.css'
|
||||
import '@fontsource/inter/700.css'
|
||||
import '@fontsource/jetbrains-mono/500.css'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import { AuthProvider } from '@/auth/AuthProvider'
|
||||
import { ToastProvider } from '@/components/ui/ToastProvider'
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
// Данные почти всегда актуализируются через собственные refetchInterval —
|
||||
// не рефетчим агрессивно при каждом фокусе окна.
|
||||
refetchOnWindowFocus: false,
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/*
|
||||
* Без <StrictMode>: намеренно, из-за экрана конференции (RoomPage).
|
||||
*
|
||||
* `@livekit/components-react` <LiveKitRoom> (хук useLiveKitRoom) создаёт
|
||||
* `Room` в useEffect и вызывает `room.disconnect()` в cleanup-эффекте при
|
||||
* размонтировании. Двойной вызов эффектов StrictMode в dev (mount → cleanup
|
||||
* → mount) укладывается в ровно тот гоночный сценарий, от которого сама
|
||||
* библиотека предупреждает в комментарии к своему (неиспользуемому внутри
|
||||
* <LiveKitRoom>) хуку useSequentialRoomConnectDisconnect: «room.connect() в
|
||||
* теле эффекта может продолжить выполняться, пока ещё не завершился
|
||||
* room.disconnect() из cleanup предыдущего рендера» — т.е. первый Room
|
||||
* успевает частично подключиться (в т.ч. опубликовать локальный трек камеры
|
||||
* с реальным sid) и почти сразу схлопывается вместе со вторым, из-за чего
|
||||
* реальный (переживший гонку) Room получает событие Disconnected и роняет
|
||||
* нас в /lobby через onDisconnected, а GridLayout/useVisualStableUpdate
|
||||
* параллельно ловит смену идентичности трека (placeholder → реальный трек
|
||||
* → снова placeholder) и логирует `Error while running updatePages()`.
|
||||
* Внутри `<LiveKitRoom>` эта гонка не сериализуется (в отличие от
|
||||
* useSequentialRoomConnectDisconnect), поэтому единственный надёжный фикс на
|
||||
* уровне приложения — не выполнять эффекты дважды. В production-сборке
|
||||
* StrictMode всё равно не даёт двойного вызова эффектов, так что для
|
||||
* собранного бандла разницы нет — риск только в dev-режиме, где мы и теряли
|
||||
* подключение к комнате.
|
||||
*/
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<BrowserRouter>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ToastProvider>
|
||||
<AuthProvider>
|
||||
<App />
|
||||
</AuthProvider>
|
||||
</ToastProvider>
|
||||
</QueryClientProvider>
|
||||
</BrowserRouter>,
|
||||
)
|
||||
Reference in New Issue
Block a user