Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
31 changes: 17 additions & 14 deletions pages/src/App.tsx
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -19,15 +20,17 @@ const App: React.FC = () => {
return (
<>
<ScrollToTop />
<Routes>
<Route path="/" element={<LandingPage><FeaturesPage /></LandingPage>} />
<Route path="/benchmark" element={<LandingPage><BenchmarkPage /></LandingPage>} />
<Route path="/quickstart" element={<LandingPage><QuickStartPage /></LandingPage>} />
<Route path="/docs" element={<DocsPage />} />
<Route path="/docs/:slug" element={<DocsPage />} />
<Route path="/blog" element={<BlogPage />} />
<Route path="/blog/:slug" element={<BlogPage />} />
</Routes>
<Suspense fallback={<div style={{ minHeight: '100vh', background: '#000000' }} />}>
<Routes>
Comment on lines +23 to +24

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Error Boundary for lazy-loaded components

React.lazy() will throw an error if the chunk fails to load (e.g., due to network issues, server downtime, or a new deployment invalidating old chunk URLs). Without an error boundary wrapping the Suspense, this will result in an unhandled crash and a blank page with no recovery path for the user.

Consider adding an error boundary component around the Suspense (or at a higher level) to gracefully handle chunk loading failures, e.g.:

<ErrorBoundary fallback={<div>Failed to load page. Please refresh.</div>}>
  <Suspense fallback={...}>
    <Routes>...</Routes>
  </Suspense>
</ErrorBoundary>

<Route path="/" element={<LandingPage><FeaturesPage /></LandingPage>} />
<Route path="/benchmark" element={<LandingPage><BenchmarkPage /></LandingPage>} />
<Route path="/quickstart" element={<LandingPage><QuickStartPage /></LandingPage>} />
<Route path="/docs" element={<DocsPage />} />
<Route path="/docs/:slug" element={<DocsPage />} />
<Route path="/blog" element={<BlogPage />} />
<Route path="/blog/:slug" element={<BlogPage />} />
</Routes>
</Suspense>
</>
);
};
Expand Down
80 changes: 55 additions & 25 deletions pages/src/components/HeroSection.tsx
Original file line number Diff line number Diff line change
@@ -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',
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -164,6 +166,29 @@ const HeroSection: React.FC = () => {
return () => clearTimeout(timer);
}, [toastVisible]);

useEffect(() => {
let secondFrame: number | undefined;
const firstFrame = requestAnimationFrame(() => {
secondFrame = requestAnimationFrame(() => setShowShaderBackground(true));
});
Comment on lines +171 to +173

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double requestAnimationFrame pattern is a non-obvious performance optimization technique used to defer rendering past the first paint. Future maintainers may not understand why two frames are needed and might accidentally simplify or remove this logic. Consider adding a brief comment explaining the intent, e.g., // Wait two animation frames to ensure first paint completes before loading the heavy shader background.


return () => {
cancelAnimationFrame(firstFrame);
if (secondFrame !== undefined) cancelAnimationFrame(secondFrame);
};
}, []);

const shaderFallback = (
<div
style={{
position: 'absolute',
inset: 0,
zIndex: 0,
background: 'radial-gradient(circle at 50% 20%, #0d750d 0%, #042e04 38%, #000000 78%)',
}}
/>
);

return (
<>
<section
Expand All @@ -179,29 +204,34 @@ const HeroSection: React.FC = () => {
}}
>
{/* Shader Background */}
<ColorBends
style={{
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
zIndex: 0,
}}
colors={['#0d750d', '#042e04', '#066020']}
rotation={90}
speed={0.23}
scale={1.2}
frequency={1}
warpStrength={1}
mouseInfluence={1}
noise={0.33}
parallax={0.45}
iterations={1}
intensity={0.8}
bandWidth={6}
transparent
/>
{shaderFallback}
{showShaderBackground && (
<Suspense fallback={null}>
<ColorBends
Comment on lines +208 to +210

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lazy-loaded ColorBends component has no error boundary wrapping it. If the dynamic import fails (e.g., network error, missing chunk after deployment), React will throw an unhandled error that can crash the entire HeroSection or page. Since there is no ErrorBoundary component anywhere in the project, consider adding one around the <Suspense> block so that on chunk load failure the component gracefully degrades to the static gradient fallback (shaderFallback) which is already rendered underneath.

style={{
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '100%',
zIndex: 0,
}}
colors={['#0d750d', '#042e04', '#066020']}
rotation={90}
speed={0.23}
scale={1.2}
frequency={1}
warpStrength={1}
mouseInfluence={1}
noise={0.33}
parallax={0.45}
iterations={1}
intensity={0.8}
bandWidth={6}
transparent
/>
</Suspense>
)}

{/* Gradient overlay */}
<div
Expand Down
130 changes: 80 additions & 50 deletions pages/src/components/MarkdownRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,54 @@ import React, { useMemo, useEffect, useRef, useState, useCallback, useId } from
import ReactDOM from 'react-dom';
import { Marked, Renderer } from 'marked';
import DOMPurify from 'dompurify';
import mermaid from 'mermaid';
import { useTranslation } from '../i18n';
import copyIcon from '../assets/icons/icon-copy.svg';
import { generateHeadingId } from '../utils/headingId';

// Initialize mermaid with dark theme
mermaid.initialize({
startOnLoad: false,
// 'strict' makes mermaid sanitize its own SVG output (DOMPurify internally):
// safe label HTML like <b>/<span> 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<Mermaid> | null = null;

function loadMermaid(): Promise<Mermaid> {
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 <b>/<span> 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;
Expand Down Expand Up @@ -132,33 +148,47 @@ const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ 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 <pre> 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 <style>, foreignObject labels), so we inject mermaid's trusted
// output directly.
const wrapper = document.createElement('div');
wrapper.className = 'mermaid-rendered';
// codeql[js/xss-through-dom] -- svg is derived from user-controlled mermaid code, but mermaid
// renders it with securityLevel:'strict' (see initialize above), which sanitizes the output via
// DOMPurify (scripts/handlers stripped). The trust boundary relies on that setting staying 'strict'.
wrapper.innerHTML = svg;
pre.replaceWith(wrapper);

for (const block of Array.from(mermaidBlocks)) {
const pre = block.parentElement;
if (!pre) continue;
const code = block.textContent || '';
try {
const id = `mermaid-diagram-${crypto.randomUUID()}`;
const { svg } = await mermaid.render(id, code);
Comment on lines +156 to +162

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rendering of multiple mermaid diagrams was changed from parallel (Promise.all) to sequential (for...of with await). While this avoids potential mermaid concurrency issues (shared internal state), it means N diagrams now take N× the single-diagram time instead of roughly 1×.

Consider using a concurrency-limited approach (e.g., render 2–3 at a time) or document why fully sequential rendering is necessary. If mermaid's render() truly cannot be called concurrently, adding a brief comment explaining this decision would help future maintainers understand the trade-off.

if (cancelled) return;
// Replace the <pre> with rendered SVG. The SVG is produced by mermaid with
// securityLevel:'strict' (configured in loadMermaid), which already sanitizes
// its output. Re-running DOMPurify over the whole SVG breaks it (namespaces,
// inline <style>, foreignObject labels), so we inject mermaid's trusted output.
const wrapper = document.createElement('div');
wrapper.className = 'mermaid-rendered';
// codeql[js/xss-through-dom] -- svg is derived from user-controlled mermaid code, but mermaid
// renders it with securityLevel:'strict' (see loadMermaid), which sanitizes the output via
// DOMPurify (scripts/handlers stripped). The trust boundary relies on that setting staying 'strict'.
wrapper.innerHTML = svg;
pre.replaceWith(wrapper);
} catch (e) {
if (cancelled) return;
// If rendering fails, show the code block normally
(block as HTMLElement).style.display = 'block';
console.warn('[Mermaid] render failed:', e);
}
}
} catch (e) {
if (cancelled) return;
// If rendering fails, show the code block normally
(block as HTMLElement).style.display = 'block';
console.warn('[Mermaid] render failed:', e);
for (const block of Array.from(mermaidBlocks)) {
(block as HTMLElement).style.display = 'block';
}
console.warn('[Mermaid] failed to load:', e);
}
});
};

void renderMermaidBlocks();

return () => { cancelled = true; };
}, [html]);
Expand Down
Loading
Loading