Skip to content

Replace full icons import from lucide-react with explicit icon whitelist in lib/source.ts #1241

@MODSetter

Description

@MODSetter

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:

  1. Re-run rg -i "^icon:" surfsense_web/content/docs and rg '"icon":' surfsense_web/content/docs to confirm the list is current
  2. 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)
  3. Open /docs and visually verify every sidebar group icon still renders
  4. Verify next build succeeds

Acceptance criteria

  • No import { icons } from "lucide-react" in the repo
  • All current doc icons still render
  • next build succeeds

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions