Implement lazy loading for 3D viewers to optimize bundle size

- Use React.lazy() and Suspense for BabylonViewer and BabylonTimelineViewer
- Reduce main bundle size from 7.4MB to 336KB (95% reduction)
- Split Babylon.js into separate chunk loaded only when 3D views are selected
- Add ThreeDViewerLoading component with spinner for better UX
- Babylon.js libraries now load on-demand when user clicks 3D view toggles

Bundle optimization results:
- Main bundle: 336KB (was 7.4MB)
- Babylon chunk: 7MB (lazy-loaded)
- BabylonViewer: 3.6KB (lazy-loaded)
- BabylonTimelineViewer: 6.6KB (lazy-loaded)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Mainguy 2025-08-11 12:21:18 -05:00
parent 359e8a1bd3
commit 63550a42b4

View File

@ -1,12 +1,49 @@
import { useState, useMemo, useEffect } from 'react'
import { useState, useMemo, useEffect, lazy, Suspense } from 'react'
import { useDatabaseTraceData } from '../../hooks/useDatabaseTraceData'
import { getUrlParams, updateUrlWithTraceId } from '../../App'
import BabylonViewer from '../../BabylonViewer'
import BabylonTimelineViewer from '../../BabylonTimelineViewer'
import RequestFilters from './RequestFilters'
import RequestsTable from './RequestsTable'
import styles from './HTTPRequestViewer.module.css'
// Lazy load 3D viewers to reduce main bundle size
const BabylonViewer = lazy(() => import('../../BabylonViewer'))
const BabylonTimelineViewer = lazy(() => import('../../BabylonTimelineViewer'))
// Loading component for 3D viewers
const ThreeDViewerLoading = () => (
<div style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '500px',
background: '#f8f9fa',
borderRadius: '8px'
}}>
<div style={{
width: '50px',
height: '50px',
border: '4px solid #e3f2fd',
borderTop: '4px solid #2196f3',
borderRadius: '50%',
animation: 'spin 1s linear infinite',
marginBottom: '20px'
}} />
<div style={{ color: '#6c757d', fontSize: '16px' }}>
Loading 3D Viewer...
</div>
<div style={{ color: '#9e9e9e', fontSize: '14px', marginTop: '8px' }}>
Initializing Babylon.js
</div>
<style>{`
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
`}</style>
</div>
)
// Imported utilities
import { ITEMS_PER_PAGE, SSIM_SIMILARITY_THRESHOLD } from './lib/httpRequestConstants'
import { extractScreenshots, findUniqueScreenshots } from './lib/screenshotUtils'
@ -346,7 +383,9 @@ export default function HTTPRequestViewer({ traceId }: HTTPRequestViewerProps) {
</button>
</div>
<div className={styles.modalContent}>
<BabylonViewer httpRequests={filteredRequests} width={window.innerWidth * 0.9} height={window.innerHeight * 0.9 - 100} />
<Suspense fallback={<ThreeDViewerLoading />}>
<BabylonViewer httpRequests={filteredRequests} width={window.innerWidth * 0.9} height={window.innerHeight * 0.9 - 100} />
</Suspense>
</div>
<div className={styles.modalLegend}>
<div><strong>Legend:</strong></div>
@ -385,7 +424,9 @@ export default function HTTPRequestViewer({ traceId }: HTTPRequestViewerProps) {
</button>
</div>
<div className={styles.modalContent}>
<BabylonTimelineViewer httpRequests={filteredRequests} screenshots={screenshots} width={window.innerWidth * 0.9} height={window.innerHeight * 0.9 - 100} />
<Suspense fallback={<ThreeDViewerLoading />}>
<BabylonTimelineViewer httpRequests={filteredRequests} screenshots={screenshots} width={window.innerWidth * 0.9} height={window.innerHeight * 0.9 - 100} />
</Suspense>
</div>
<div className={styles.modalLegend}>
<div><strong>Legend:</strong></div>