Description
surfsense_web/lib/source.ts imports the entire icons registry from lucide-react to resolve icon names from docs MDX frontmatter. This pulls the full Lucide icon set into the docs chunk.
Current code (entire file):
// surfsense_web/lib/source.ts
import { loader } from "fumadocs-core/source";
import { icons } from "lucide-react";
import { createElement } from "react";
import { docs } from "@/.source/server";
export const source = loader({
baseUrl: "/docs",
source: docs.toFumadocsSource(),
icon(icon) {
if (icon && icon in icons) return createElement(icons[icon as keyof typeof icons]);
},
});
Why this matters:
icons is a barrel object containing all Lucide icons. Even though next.config.ts enables optimizePackageImports: ["lucide-react", ...], the optimizer cannot tree-shake when you dynamically access icons[key] — every icon ends up in the docs chunk.
- An audit of
surfsense_web/content/docs/**/*.mdx and **/meta.json frontmatter shows only 9 distinct icon names are actually used: Heart, Download, ClipboardCheck, Wrench, FlaskConical, BookOpen, Compass, Unplug, Container.
What to do
Replace the full-registry import with an explicit whitelist:
import { loader } from "fumadocs-core/source";
import {
BookOpen,
ClipboardCheck,
Compass,
Container,
Download,
FlaskConical,
Heart,
Unplug,
Wrench,
type LucideIcon,
} from "lucide-react";
import { createElement } from "react";
import { docs } from "@/.source/server";
const iconMap: Record<string, LucideIcon> = {
BookOpen,
ClipboardCheck,
Compass,
Container,
Download,
FlaskConical,
Heart,
Unplug,
Wrench,
};
export const source = loader({
baseUrl: "/docs",
source: docs.toFumadocsSource(),
icon(icon) {
if (icon && icon in iconMap) return createElement(iconMap[icon]);
},
});
Before merging:
- Re-run
rg -i "^icon:" surfsense_web/content/docs and rg '"icon":' surfsense_web/content/docs to confirm the list is current
- Add any newly-discovered icon names to
iconMap (and update the CONTRIBUTING note that adding a new icon in docs frontmatter requires adding it to iconMap)
- Open
/docs and visually verify every sidebar group icon still renders
- Verify
next build succeeds
Acceptance criteria
- No
import { icons } from "lucide-react" in the repo
- All current doc icons still render
next build succeeds
Description
surfsense_web/lib/source.tsimports the entireiconsregistry fromlucide-reactto resolve icon names from docs MDX frontmatter. This pulls the full Lucide icon set into the docs chunk.Current code (entire file):
Why this matters:
iconsis a barrel object containing all Lucide icons. Even thoughnext.config.tsenablesoptimizePackageImports: ["lucide-react", ...], the optimizer cannot tree-shake when you dynamically accessicons[key]— every icon ends up in the docs chunk.surfsense_web/content/docs/**/*.mdxand**/meta.jsonfrontmatter shows only 9 distinct icon names are actually used:Heart,Download,ClipboardCheck,Wrench,FlaskConical,BookOpen,Compass,Unplug,Container.What to do
Replace the full-registry import with an explicit whitelist:
Before merging:
rg -i "^icon:" surfsense_web/content/docsandrg '"icon":' surfsense_web/content/docsto confirm the list is currenticonMap(and update the CONTRIBUTING note that adding a new icon in docs frontmatter requires adding it toiconMap)/docsand visually verify every sidebar group icon still rendersnext buildsucceedsAcceptance criteria
import { icons } from "lucide-react"in the reponext buildsucceeds