Skip to content

Commit 071a1f6

Browse files
authored
Merge pull request #88 from Agbasimere/feature/bundle-optimization
feat(frontend): optimize bundle size with dynamic imports and route-based code splitting
2 parents 834040e + 8578920 commit 071a1f6

12 files changed

Lines changed: 209 additions & 261 deletions

File tree

frontend/next.config.js

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
/** @type {import('next').NextConfig} */
22
const { i18n } = require('./next-i18next.config');
3+
const withBundleAnalyzer = require('@next/bundle-analyzer')({
4+
enabled: process.env.ANALYZE === 'true',
5+
});
36

47
const nextConfig = {
58
typescript: {
@@ -26,41 +29,13 @@ const nextConfig = {
2629
},
2730
// Performance monitoring configuration
2831
webpack: (config, { isServer }) => {
29-
// Enable bundle analysis in production
30-
if (process.env.ANALYZE === 'true') {
31-
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
32-
config.plugins.push(
33-
new BundleAnalyzerPlugin({
34-
analyzerMode: 'static',
35-
openAnalyzer: false,
36-
})
37-
);
38-
}
39-
4032
// Performance optimizations
4133
// Stub native-only modules that can't run in browser/build
4234
config.resolve.alias = {
4335
...config.resolve.alias,
4436
brainflow: false,
4537
};
4638

47-
config.optimization.splitChunks = {
48-
chunks: 'all',
49-
cacheGroups: {
50-
vendor: {
51-
test: /[\\/]node_modules[\\/]/,
52-
name: 'vendors',
53-
chunks: 'all',
54-
},
55-
common: {
56-
name: 'common',
57-
minChunks: 2,
58-
chunks: 'all',
59-
enforce: true,
60-
},
61-
},
62-
};
63-
6439
return config;
6540
},
6641
// Enable compression
@@ -95,4 +70,4 @@ const nextConfig = {
9570
},
9671
};
9772

98-
module.exports = nextConfig;
73+
module.exports = withBundleAnalyzer(nextConfig);

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
"husky": "^9.1.7",
8383
"jest": "^29.6.4",
8484
"jest-environment-jsdom": "^30.4.1",
85-
"next-bundle-analyzer": "^0.6.0",
85+
"@next/bundle-analyzer": "^14.0.0",
8686
"postcss": "^8.4.28",
8787
"prettier": "^3.0.2",
8888
"typescript": "^5.1.6"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use client';
2+
3+
import { useEffect } from 'react';
4+
5+
export default function PerformanceInitializer() {
6+
useEffect(() => {
7+
// Dynamically import the performance monitor to keep web-vitals out of initial chunks
8+
import('@/lib/performance-monitor').then((mod) => {
9+
// Reference it to trigger initialization side effects
10+
mod.performanceMonitor;
11+
});
12+
}, []);
13+
14+
return null;
15+
}

frontend/src/app/lab/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Metadata } from 'next';
2-
import { VirtualScienceLab } from '../../components/Lab/VirtualScienceLab';
2+
import { VirtualScienceLab } from '../../components/Lab';
33

44
export const metadata: Metadata = {
55
title: 'Virtual Science Laboratory — StarkEd',

frontend/src/app/layout.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Metadata } from 'next';
22
import { Inter } from 'next/font/google';
33
import './globals.css';
4-
import { performanceMonitor } from '@/lib/performance-monitor';
4+
import PerformanceInitializer from './PerformanceInitializer';
55

66
const inter = Inter({ subsets: ['latin'] });
77

@@ -20,16 +20,15 @@ export default function RootLayout({
2020
children: React.ReactNode;
2121
params?: { locale?: string };
2222
}) {
23-
if (typeof window !== 'undefined') {
24-
performanceMonitor;
25-
}
26-
2723
const locale = params?.locale ?? 'en';
2824
const dir = RTL_LOCALES.has(locale) ? 'rtl' : 'ltr';
2925

3026
return (
3127
<html lang={locale} dir={dir}>
32-
<body className={inter.className}>{children}</body>
28+
<body className={inter.className}>
29+
<PerformanceInitializer />
30+
{children}
31+
</body>
3332
</html>
3433
);
3534
}

frontend/src/components/ARVR/index.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Core AR/VR Components
2-
export { WebXREngine } from './WebXREngine';
3-
export { ModelViewer } from './ModelViewer';
4-
export { VirtualClassroom } from './VirtualClassroom';
5-
export { InteractiveSimulation } from './InteractiveSimulation';
6-
export { GestureControls } from './GestureControls';
7-
export { PerformanceOptimizer } from './PerformanceOptimizer';
1+
import dynamic from 'next/dynamic';
2+
3+
export const WebXREngine = dynamic(() => import('./WebXREngine').then(m => m.WebXREngine), { ssr: false });
4+
export const ModelViewer = dynamic(() => import('./ModelViewer').then(m => m.ModelViewer), { ssr: false });
5+
export const VirtualClassroom = dynamic(() => import('./VirtualClassroom').then(m => m.VirtualClassroom), { ssr: false });
6+
export const InteractiveSimulation = dynamic(() => import('./InteractiveSimulation').then(m => m.InteractiveSimulation), { ssr: false });
7+
export const GestureControls = dynamic(() => import('./GestureControls').then(m => m.GestureControls), { ssr: false });
8+
export const PerformanceOptimizer = dynamic(() => import('./PerformanceOptimizer').then(m => m.PerformanceOptimizer), { ssr: false });
89

910
// Types - only export what is actually exported from source modules
1011
export type { XRMode, XRSessionState } from './WebXREngine';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import dynamic from 'next/dynamic';
2+
3+
export const BCIDashboard = dynamic(() => import('./BCIDashboard').then(m => m.BCIDashboard), { ssr: false });
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
export { VirtualScienceLab } from './VirtualScienceLab';
1+
import dynamic from 'next/dynamic';
2+
3+
export const VirtualScienceLab = dynamic(() => import('./VirtualScienceLab').then(m => m.VirtualScienceLab), { ssr: false });
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
export { MetaverseCampus } from './MetaverseCampus';
2-
export { AvatarCustomizer } from './AvatarCustomizer';
3-
export { BuildingInterior } from './BuildingInterior';
4-
export { CampusHUD } from './CampusHUD';
5-
export { CampusScene } from './CampusScene';
1+
import dynamic from 'next/dynamic';
2+
3+
export const MetaverseCampus = dynamic(() => import('./MetaverseCampus').then(m => m.MetaverseCampus), { ssr: false });
4+
export const AvatarCustomizer = dynamic(() => import('./AvatarCustomizer').then(m => m.AvatarCustomizer), { ssr: false });
5+
export const BuildingInterior = dynamic(() => import('./BuildingInterior').then(m => m.BuildingInterior), { ssr: false });
6+
export const CampusHUD = dynamic(() => import('./CampusHUD').then(m => m.CampusHUD), { ssr: false });
7+
export const CampusScene = dynamic(() => import('./CampusScene').then(m => m.CampusScene), { ssr: false });

frontend/src/pages/analytics.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import ProgressDashboard from '../components/analytics/ProgressDashboard'
2+
import ProgressDashboard from '../components/Analytics/ProgressDashboard'
33

44
const AnalyticsPage: React.FC = () => {
55
return (

0 commit comments

Comments
 (0)