diff --git a/docusaurus.config.js b/docusaurus.config.js
index 0ff78a9b5..4b28e1a3e 100644
--- a/docusaurus.config.js
+++ b/docusaurus.config.js
@@ -63,7 +63,16 @@ module.exports = {
{property: "og:image:height", content: "630"},
],
headTags: [
- // Google Fonts - DM Sans (loaded via headTags instead of CSS @import)
+ // ── Preconnect / DNS-prefetch for critical third-party origins ─────
+ // Keploy CDN
+ {
+ tagName: "link",
+ attributes: {
+ rel: "preconnect",
+ href: "https://keploy.io/",
+ },
+ },
+ // Google Fonts (used by Docusaurus default theme)
{
tagName: "link",
attributes: {
@@ -79,6 +88,7 @@ module.exports = {
crossorigin: "anonymous",
},
},
+ // Google Fonts - DM Sans (loaded via headTags instead of CSS @import)
{
tagName: "link",
attributes: {
@@ -86,12 +96,35 @@ module.exports = {
href: "https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;700&display=swap",
},
},
- // Preconnect tag
+ // Algolia search
{
tagName: "link",
attributes: {
rel: "preconnect",
- href: "https://keploy.io/",
+ href: "https://WZTL8PLCOD-dsn.algolia.net",
+ crossorigin: "anonymous",
+ },
+ },
+ // Analytics (dns-prefetch only — not render-blocking)
+ {
+ tagName: "link",
+ attributes: {
+ rel: "dns-prefetch",
+ href: "https://www.clarity.ms",
+ },
+ },
+ {
+ tagName: "link",
+ attributes: {
+ rel: "dns-prefetch",
+ href: "https://www.googletagmanager.com",
+ },
+ },
+ {
+ tagName: "link",
+ attributes: {
+ rel: "dns-prefetch",
+ href: "https://www.google-analytics.com",
},
},
{
diff --git a/netlify.toml b/netlify.toml
index 2104fcf94..5e68b2a6b 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -9,7 +9,38 @@
## Note: if you are looking for Redirects
# they have been moved to /static/_redirects to make it more manageable - swyx
-# Security headers for all pages
+# ── Performance: Cache headers ────────────────────────────────────────────────
+# Hashed JS/CSS bundles emitted by Docusaurus/webpack → safe to cache 1 year
+[[headers]]
+ for = "/assets/*"
+ [headers.values]
+ Cache-Control = "public, max-age=31536000, immutable"
+
+# Static images served from /img
+[[headers]]
+ for = "/img/*"
+ [headers.values]
+ Cache-Control = "public, max-age=86400, stale-while-revalidate=604800"
+
+# Fonts are NOT content-hashed (e.g. Roboto-Bold.woff2) so immutable is unsafe.
+# Use a 1-week cache with stale-while-revalidate instead.
+[[headers]]
+ for = "/fonts/*"
+ [headers.values]
+ Cache-Control = "public, max-age=604800, stale-while-revalidate=86400"
+
+# Static JS helpers (non-hashed scripts in /docs/js and /docs/scripts)
+[[headers]]
+ for = "/js/*"
+ [headers.values]
+ Cache-Control = "public, max-age=86400"
+
+[[headers]]
+ for = "/scripts/*"
+ [headers.values]
+ Cache-Control = "public, max-age=86400"
+
+# ── Security headers (improves PageSpeed Best Practices score) ──────────────
[[headers]]
for = "/*"
[headers.values]
diff --git a/src/components/responsive-player/ResponsivePlayer.js b/src/components/responsive-player/ResponsivePlayer.js
index d08af04c3..9237b9e2c 100644
--- a/src/components/responsive-player/ResponsivePlayer.js
+++ b/src/components/responsive-player/ResponsivePlayer.js
@@ -1,5 +1,9 @@
-import React from "react";
-import ReactPlayer from "react-player";
+import React, {Suspense, lazy} from "react";
+
+// Lazy-load react-player so it is NOT included in the initial JS bundle.
+// react-player/lazy defers loading the actual player implementation until
+// the component is rendered, reducing the first-page-load JS payload.
+const ReactPlayer = lazy(() => import("react-player/lazy"));
function ResponsivePlayer({url, loop, playing}) {
return (
@@ -7,16 +11,31 @@ function ResponsivePlayer({url, loop, playing}) {
className="relative rounded-lg shadow-lg"
style={{paddingTop: "56.25%"}}
>
- {/* /* Player ratio: 100 / (1280 / 720) */}
-
+ {/* Player ratio: 100 / (1280 / 720) */}
+
+
+
+ Loading video player...
+
+
+ }
+ >
+
+
);
}
diff --git a/src/css/custom.css b/src/css/custom.css
index 739b7f172..115b78b17 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -806,7 +806,8 @@ td img {
margin: 0;
}
-.codeBlockContainer_node_modules-\@docusaurus-theme-classic-lib-next-theme-CodeBlock-styles-module {
+[class^="codeBlockContainer_"],
+[class*=" codeBlockContainer_"] {
box-shadow: none !important;
margin: 0;
padding: 0;
@@ -3202,3 +3203,50 @@ html[data-theme="dark"] .docs-inline-footer__slack {
font-size: 0.95rem;
}
}
+
+/* ===== PERFORMANCE: Rendering & paint optimisations ===== */
+
+/*
+ * content-visibility: auto — lets the browser skip layout/paint for
+ * off-screen sections, reducing LCP and INP on mobile.
+ * contain-intrinsic-size gives the browser a size estimate so the
+ * scroll-bar doesn't jump when content is rendered.
+ */
+footer,
+.footer {
+ content-visibility: auto;
+ contain-intrinsic-size: 0 200px;
+}
+
+/* Sidebar is always below the fold on small viewports */
+@media (max-width: 996px) {
+ .theme-doc-sidebar-container {
+ content-visibility: auto;
+ contain-intrinsic-size: 0 600px;
+ }
+}
+
+/*
+ * Lazy-decoded images — any
without an explicit loading attribute
+ * should at minimum decode off the main thread.
+ */
+img:not([loading]) {
+ decoding: async;
+}
+
+/*
+ * Reduce paint layers for the announcement bar (it's a position:sticky
+ * element and can cause extra compositing cost on mobile).
+ * Using attribute substring selector to avoid relying on a hashed class name
+ * that changes between Docusaurus builds.
+ */
+[class*="announcementBar"] {
+ will-change: auto;
+ transform: translateZ(0);
+}
+
+/*
+ * Font-display: swap is configured per @font-face declaration in
+ * src/fonts. Docusaurus-injected Google Fonts links already include
+ * &display=swap in the URL, so no additional override is needed here.
+ */