diff --git a/pages/package.json b/pages/package.json
index 6a058129..9a6b5b14 100644
--- a/pages/package.json
+++ b/pages/package.json
@@ -31,6 +31,7 @@
"@types/three": "^0.185.0",
"autoprefixer": "^10.4.16",
"babel-loader": "^9.1.3",
+ "compression-webpack-plugin": "^12.0.0",
"copy-webpack-plugin": "^14.0.0",
"css-loader": "^6.8.1",
"html-webpack-plugin": "^5.5.3",
diff --git a/pages/src/App.tsx b/pages/src/App.tsx
index 765c37ad..6c4fe913 100644
--- a/pages/src/App.tsx
+++ b/pages/src/App.tsx
@@ -1,11 +1,12 @@
-import React, { useEffect } from 'react';
+import React, { Suspense, useEffect } from 'react';
import { Routes, Route, useLocation } from 'react-router-dom';
import LandingPage from './components/LandingPage';
import FeaturesPage from './pages/FeaturesPage';
-import BenchmarkPage from './pages/BenchmarkPage';
-import QuickStartPage from './pages/QuickStartPage';
-import DocsPage from './pages/DocsPage';
-import BlogPage from './pages/BlogPage';
+
+const BenchmarkPage = React.lazy(() => import(/* webpackChunkName: "benchmark-page" */ './pages/BenchmarkPage'));
+const QuickStartPage = React.lazy(() => import(/* webpackChunkName: "quickstart-page" */ './pages/QuickStartPage'));
+const DocsPage = React.lazy(() => import(/* webpackChunkName: "docs-page" */ './pages/DocsPage'));
+const BlogPage = React.lazy(() => import(/* webpackChunkName: "blog-page" */ './pages/BlogPage'));
const ScrollToTop: React.FC = () => {
const { pathname } = useLocation();
@@ -19,15 +20,17 @@ const App: React.FC = () => {
return (
<>
-
- } />
- } />
- } />
- } />
- } />
- } />
- } />
-
+ }>
+
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+
+
>
);
};
diff --git a/pages/src/components/HeroSection.tsx b/pages/src/components/HeroSection.tsx
index 0af00952..852c71fd 100644
--- a/pages/src/components/HeroSection.tsx
+++ b/pages/src/components/HeroSection.tsx
@@ -1,12 +1,13 @@
-import React, { useCallback, useState, useEffect } from 'react';
+import React, { Suspense, useCallback, useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Link } from 'react-router-dom';
import { useTranslation } from '../i18n';
import { useResponsive } from '../hooks/useResponsive';
-import ColorBends from './ColorBends';
import docDownloadIcon from '../assets/icons/doc-download-green.svg';
import copyIcon from '../assets/icons/icon-copy.svg';
+const ColorBends = React.lazy(() => import(/* webpackChunkName: "color-bends" */ './ColorBends'));
+
const TC = {
brand: '#756BFF',
@@ -123,6 +124,7 @@ const HeroSection: React.FC = () => {
const { isMobile, isTablet } = useResponsive();
const [toastVisible, setToastVisible] = useState(false);
const [toastMessage, setToastMessage] = useState('');
+ const [showShaderBackground, setShowShaderBackground] = useState(false);
const showToast = (message: string) => {
setToastMessage(message);
@@ -164,6 +166,29 @@ const HeroSection: React.FC = () => {
return () => clearTimeout(timer);
}, [toastVisible]);
+ useEffect(() => {
+ let secondFrame: number | undefined;
+ const firstFrame = requestAnimationFrame(() => {
+ secondFrame = requestAnimationFrame(() => setShowShaderBackground(true));
+ });
+
+ return () => {
+ cancelAnimationFrame(firstFrame);
+ if (secondFrame !== undefined) cancelAnimationFrame(secondFrame);
+ };
+ }, []);
+
+ const shaderFallback = (
+
+ );
+
return (
<>
{
}}
>
{/* Shader Background */}
-
+ {shaderFallback}
+ {showShaderBackground && (
+
+
+
+ )}
{/* Gradient overlay */}
/
is kept, scripts/handlers are stripped.
- // This is why we can inject the returned SVG directly below without re-sanitizing.
- securityLevel: 'strict',
- theme: 'dark',
- themeVariables: {
- primaryColor: '#1a1a2e',
- primaryTextColor: 'rgba(255,255,255,0.85)',
- primaryBorderColor: 'rgba(255,255,255,0.2)',
- lineColor: 'rgba(255,255,255,0.4)',
- secondaryColor: '#16213e',
- tertiaryColor: '#0f3460',
- background: '#000000',
- mainBkg: 'rgba(255,255,255,0.04)',
- nodeBorder: 'rgba(255,255,255,0.16)',
- clusterBkg: 'rgba(255,255,255,0.02)',
- titleColor: '#FFFFFF',
- edgeLabelBackground: '#000000',
- },
- flowchart: {
- htmlLabels: true,
- curve: 'basis',
- },
-});
+type Mermaid = typeof import('mermaid')['default'];
+
+let mermaidPromise: Promise | null = null;
+
+function loadMermaid(): Promise {
+ if (!mermaidPromise) {
+ mermaidPromise = import('mermaid')
+ .then(({ default: mermaid }) => {
+ mermaid.initialize({
+ startOnLoad: false,
+ // 'strict' makes mermaid sanitize its own SVG output (DOMPurify internally):
+ // safe label HTML like / is kept, scripts/handlers are stripped.
+ // This is why we can inject the returned SVG directly below without re-sanitizing.
+ securityLevel: 'strict',
+ theme: 'dark',
+ themeVariables: {
+ primaryColor: '#1a1a2e',
+ primaryTextColor: 'rgba(255,255,255,0.85)',
+ primaryBorderColor: 'rgba(255,255,255,0.2)',
+ lineColor: 'rgba(255,255,255,0.4)',
+ secondaryColor: '#16213e',
+ tertiaryColor: '#0f3460',
+ background: '#000000',
+ mainBkg: 'rgba(255,255,255,0.04)',
+ nodeBorder: 'rgba(255,255,255,0.16)',
+ clusterBkg: 'rgba(255,255,255,0.02)',
+ titleColor: '#FFFFFF',
+ edgeLabelBackground: '#000000',
+ },
+ flowchart: {
+ htmlLabels: true,
+ curve: 'basis',
+ },
+ });
+ return mermaid;
+ })
+ .catch((error) => {
+ // Allow a later navigation to retry after a transient chunk-load failure.
+ mermaidPromise = null;
+ throw error;
+ });
+ }
+ return mermaidPromise;
+}
interface MarkdownRendererProps {
content: string;
@@ -132,33 +148,47 @@ const MarkdownRenderer: React.FC = ({ content }) => {
const mermaidBlocks = containerRef.current.querySelectorAll('code.language-mermaid');
if (mermaidBlocks.length === 0) return;
- const renderPromises = Array.from(mermaidBlocks).map(async (block) => {
- const pre = block.parentElement;
- if (!pre) return;
- const code = block.textContent || '';
+ const renderMermaidBlocks = async () => {
try {
- const id = `mermaid-diagram-${crypto.randomUUID()}`;
- const { svg } = await mermaid.render(id, code);
+ const mermaid = await loadMermaid();
if (cancelled) return;
- // Replace the with rendered SVG. The SVG is produced by mermaid with
- // securityLevel:'strict' (see initialize above), which already sanitizes its
- // output. Re-running DOMPurify over the whole SVG breaks it (namespaces,
- // inline