feat: Migrate to Vite build tool and lazy load components
This commit updates the project to use Vite as the build tool, replacing the previous configuration. It also implements lazy loading for the HostView, PlayerView, and SpectatorView components to improve initial load performance. The spectator view's fastest buzzer calculation has been refactored for clarity and type safety. Dependencies have been updated to include Vite and its React plugin. The import maps in index.html have also been adjusted to reflect the new build tool.
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, Suspense } from 'react';
|
||||
import { GameProvider } from './context/GameContext';
|
||||
import { HostView } from './components/HostView';
|
||||
import { PlayerView } from './components/PlayerView';
|
||||
import { SpectatorView } from './components/SpectatorView';
|
||||
import { Monitor, Smartphone, LayoutDashboard } from 'lucide-react';
|
||||
import { Monitor, Smartphone, LayoutDashboard, Loader2 } from 'lucide-react';
|
||||
|
||||
// Lazy load components to reduce initial bundle size
|
||||
const HostView = React.lazy(() => import('./components/HostView').then(module => ({ default: module.HostView })));
|
||||
const PlayerView = React.lazy(() => import('./components/PlayerView').then(module => ({ default: module.PlayerView })));
|
||||
const SpectatorView = React.lazy(() => import('./components/SpectatorView').then(module => ({ default: module.SpectatorView })));
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [view, setView] = useState<'HOST' | 'PLAYER' | 'SPECTATOR'>('SPECTATOR');
|
||||
@@ -70,7 +72,14 @@ const App: React.FC = () => {
|
||||
|
||||
{/* Main Content Area */}
|
||||
<div className="flex-1 relative w-full h-full overflow-hidden">
|
||||
{renderView()}
|
||||
<Suspense fallback={
|
||||
<div className="h-full w-full flex flex-col items-center justify-center text-slate-500 gap-4">
|
||||
<Loader2 className="animate-spin w-12 h-12 text-indigo-500" />
|
||||
<p>Loading Quiz Module...</p>
|
||||
</div>
|
||||
}>
|
||||
{renderView()}
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</GameProvider>
|
||||
|
||||
@@ -145,15 +145,17 @@ export const SpectatorView: React.FC = () => {
|
||||
// Top 5 Players
|
||||
const topPlayers = [...players].sort((a,b) => b.score - a.score).slice(0, 5);
|
||||
|
||||
// Fastest Buzzer Calculation
|
||||
let fastestPlayer: Player | null = null;
|
||||
let fastestTime = Infinity;
|
||||
players.forEach(p => {
|
||||
if (p.stats.bestReactionTime && p.stats.bestReactionTime < fastestTime) {
|
||||
fastestTime = p.stats.bestReactionTime;
|
||||
fastestPlayer = p;
|
||||
// Fastest Buzzer Calculation using reduce with explicit generic type
|
||||
const fastestPlayer = players.reduce<Player | null>((best, p) => {
|
||||
const pTime = p.stats.bestReactionTime;
|
||||
if (!pTime) return best;
|
||||
if (!best || !best.stats.bestReactionTime || pTime < best.stats.bestReactionTime) {
|
||||
return p;
|
||||
}
|
||||
});
|
||||
return best;
|
||||
}, null);
|
||||
|
||||
const fastestTime = fastestPlayer?.stats.bestReactionTime ?? Infinity;
|
||||
|
||||
return (
|
||||
<div className="text-center w-full max-w-6xl mx-auto pb-10 overflow-y-auto h-full">
|
||||
@@ -203,7 +205,7 @@ export const SpectatorView: React.FC = () => {
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="text-blue-300 font-bold uppercase tracking-wider text-sm">Fastest Finger</div>
|
||||
<div className="text-2xl font-bold text-white">{(fastestPlayer as Player)?.name || '-'}</div>
|
||||
<div className="text-2xl font-bold text-white">{fastestPlayer ? fastestPlayer.name : '-'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-4xl font-mono font-bold text-blue-400">
|
||||
|
||||
+5
-3
@@ -37,7 +37,7 @@
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
</style>
|
||||
<script type="importmap">
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"react": "https://esm.sh/react@^19.2.4",
|
||||
@@ -45,14 +45,16 @@
|
||||
"react/": "https://esm.sh/react@^19.2.4/",
|
||||
"@google/genai": "https://esm.sh/@google/genai@^1.38.0",
|
||||
"lucide-react": "https://esm.sh/lucide-react@^0.563.0",
|
||||
"recharts": "https://esm.sh/recharts@^3.7.0"
|
||||
"recharts": "https://esm.sh/recharts@^3.7.0",
|
||||
"vite": "https://esm.sh/vite@^7.3.1",
|
||||
"@vitejs/plugin-react": "https://esm.sh/@vitejs/plugin-react@^5.1.2"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!-- Vite Entry Point - Points to src/index.tsx -->
|
||||
<!-- Vite Entry Point - Points to src/index.tsx as requested -->
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
+3
-1
@@ -13,7 +13,9 @@
|
||||
"react-dom": "^19.2.4",
|
||||
"@google/genai": "^1.38.0",
|
||||
"lucide-react": "^0.563.0",
|
||||
"recharts": "^3.7.0"
|
||||
"recharts": "^3.7.0",
|
||||
"vite": "^7.3.1",
|
||||
"@vitejs/plugin-react": "^5.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.14.0",
|
||||
|
||||
+10
-21
@@ -1,23 +1,12 @@
|
||||
import path from 'path';
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, '.', '');
|
||||
return {
|
||||
server: {
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
plugins: [react()],
|
||||
define: {
|
||||
'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
|
||||
'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY)
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, '.'),
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
base: './', // Ensures assets are loaded relatively (e.g., "assets/script.js" instead of "/assets/script.js")
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user