diff --git a/apps/web/src/components/blog/SkillDifficultyCharts.tsx b/apps/web/src/components/blog/SkillDifficultyCharts.tsx index d67dd476..02b0e64e 100644 --- a/apps/web/src/components/blog/SkillDifficultyCharts.tsx +++ b/apps/web/src/components/blog/SkillDifficultyCharts.tsx @@ -1,8 +1,14 @@ 'use client' +import dynamic from 'next/dynamic' import { useState, useEffect } from 'react' -import ReactECharts from 'echarts-for-react' import * as Tabs from '@radix-ui/react-tabs' + +// Dynamic import echarts to reduce bundle size +const ReactECharts = dynamic(() => import('echarts-for-react'), { + ssr: false, + loading: () =>
Loading chart...
, +}) import { css } from '../../../styled-system/css' interface SkillData { diff --git a/apps/web/src/components/blog/ValidationCharts.tsx b/apps/web/src/components/blog/ValidationCharts.tsx index 68b6b144..09a19fad 100644 --- a/apps/web/src/components/blog/ValidationCharts.tsx +++ b/apps/web/src/components/blog/ValidationCharts.tsx @@ -1,8 +1,14 @@ 'use client' import * as Tabs from '@radix-ui/react-tabs' -import ReactECharts from 'echarts-for-react' +import dynamic from 'next/dynamic' import { useEffect, useState } from 'react' + +// Dynamic import echarts to reduce bundle size +const ReactECharts = dynamic(() => import('echarts-for-react'), { + ssr: false, + loading: () =>
Loading chart...
, +}) import { css } from '../../../styled-system/css' const chartContainerStyles = css({ diff --git a/apps/web/src/components/nav/CreateRoomModal.tsx b/apps/web/src/components/nav/CreateRoomModal.tsx index a1a25f84..d71c1051 100644 --- a/apps/web/src/components/nav/CreateRoomModal.tsx +++ b/apps/web/src/components/nav/CreateRoomModal.tsx @@ -1,10 +1,10 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import * as Select from '@radix-ui/react-select' import { animated } from '@react-spring/web' import { Modal } from '@/components/common/Modal' import { useCreateRoom, useRoomData } from '@/hooks/useRoomData' -import { getAvailableGames } from '@/lib/arcade/game-registry' import { RoomShareButtons } from './RoomShareButtons' +import type { GameDefinition } from '@/lib/arcade/game-sdk/types' export interface CreateRoomModalProps { /** @@ -31,8 +31,17 @@ type ModalState = 'creating' | 'created' export function CreateRoomModal({ isOpen, onClose, onSuccess }: CreateRoomModalProps) { const { mutateAsync: createRoom, isPending } = useCreateRoom() const { getRoomShareUrl } = useRoomData() - const availableGames = getAvailableGames() + const [availableGames, setAvailableGames] = useState[]>([]) const [error, setError] = useState('') + + // Lazy load game registry only when modal opens + useEffect(() => { + if (isOpen && availableGames.length === 0) { + import('@/lib/arcade/game-registry').then(({ getAvailableGames }) => { + setAvailableGames(getAvailableGames()) + }) + } + }, [isOpen, availableGames.length]) const [gameName, setGameName] = useState('__choose_later__') // Special value = user will choose later const [accessMode, setAccessMode] = useState< 'open' | 'password' | 'approval-only' | 'restricted' diff --git a/apps/web/src/components/practice/SkillProgressChart.tsx b/apps/web/src/components/practice/SkillProgressChart.tsx index 08c47343..09bc74c1 100644 --- a/apps/web/src/components/practice/SkillProgressChart.tsx +++ b/apps/web/src/components/practice/SkillProgressChart.tsx @@ -1,7 +1,13 @@ 'use client' -import ReactECharts from 'echarts-for-react' +import dynamic from 'next/dynamic' import { useCallback, useMemo, useState } from 'react' + +// Dynamic import echarts to avoid bundling 58MB library on pages that don't use charts +const ReactECharts = dynamic(() => import('echarts-for-react'), { + ssr: false, + loading: () =>
Loading chart...
, +}) import { getExtendedClassification, type ExtendedSkillClassification,