Skip to content

Commit 14bb968

Browse files
authored
fix(shell-docs): suppress docs-render snippet warnings + fix ComponentExamples render (CopilotKit#4992)
## Summary Three changes to `src/lib/docs-render.tsx` that together eliminate the `[docs-render] snippet missing for component X` log noise on prod AND fix a hard SSR error on `/quickstart` caused by a missing `ComponentExamples` registration. ## Changes **1. Suppress warnings for components the MDX imports** (existing scope of this PR). `inlineSnippets()` runs after `stripLeadingImports()` removes the MDX's `import` lines, so the regex can't tell a `<PascalCase />` reference apart from a real React component imported into the file. Every imported component triggered a false-positive `snippet missing` warning. The page still rendered correctly via `docsComponents`; only the log was wrong. Capture imports before stripping, then short-circuit the warning when the regex hits one of those names. **2. Add `ComponentExamples` to `SNIPPET_MAP`** (new). `copilot-ui.mdx` imports `ComponentExamples` from `@/snippets/component-examples.mdx` and renders it. When `copilot-ui.mdx` is recursively inlined into a parent MDX (e.g. via `<CopilotUI />`), the import line is stripped and the inliner finds no `SNIPPET_MAP` entry for `ComponentExamples`. The bare JSX survives the inliner and `next-mdx-remote` throws `Expected component ComponentExamples to be defined` at SSR. The error is caught in a partial-render error boundary so the page returns 200, but a chunk of content is missing from the rendered output. Add `ComponentExamples: "component-examples.mdx"` to `SNIPPET_MAP` so the recursive inliner resolves it the same way it resolves `CopilotUI`. One line, fixes both the SSR error and the cosmetic warning. (Note: the `gatherImportedComponentNames` shortcut from change 1 doesn't help here because it captures imports from the OUTER MDX, not from recursively-inlined snippet bodies. That deeper structural limitation can be addressed later; the `SNIPPET_MAP` entry resolves the immediate failure.) **3. Skip icon-prefix bare references** (new). Lucide `Square*` icons (`SquareTerminal`, `SquareChartGantt`) and `react-icons` `Fa*` / `Si*` / `Pi*` families are bare-referenced in many MDX files — no explicit import, resolved at render time via the registry's emoji stubs in `docsComponents`. The existing `endsWith("Icon")` filter doesn't catch these PascalCase + library-prefix shapes. Add a regex check next to it: `/^(Fa|Si|Pi|Square)[A-Z]/`. ## Components covered after changes 1-3 The import-aware filter catches every `import { X } from "..."` reference (current set: AgentCoreCommandTabs, CodePanel, CodeShowcase, Frame, IframeSwitcher, ImageAndCode, LinkToCopilotCloud, NewLookAndFeelPreview, StartProviders). The icon-prefix filter catches `FaArrowUp`, `FaWrench`, `SquareTerminal`, `SquareChartGantt`, and future icon-library additions matching the prefix shape. `ComponentExamples` is registered in `SNIPPET_MAP` so the inliner resolves it instead of warning. Remaining bare references that don't match any of the above (e.g. `CloudCopilotKit`) still warn — these are runtime React components registered in `docsComponents` but not imported in the MDX. The right cleanup for those is to add explicit `import { CloudCopilotKit } from "..."` lines in the MDX, which the import-aware filter then catches automatically. Out of scope for this PR. ## Adjacent observation (not fixed) While diagnosing change 2, found that the underlying `new-look-and-feel.tsx` component file referenced by `troubleshooting/migrate-to-1.8.2.mdx` doesn't exist on disk. The MDX registry stubs the name with `<div>{children}</div>`, so the preview area in that page renders empty. This PR doesn't address the empty-preview behavior; the snippet-missing log noise is purely cosmetic. ## Test plan - [x] Diff is additive only; runtime render path unchanged. - [ ] Local: build shell-docs, hit `/built-in-agent/quickstart` + `/crewai-crews/quickstart` + `/built-in-agent/agentic-protocols/mcp` + `/built-in-agent/shared-state/predictive-state-updates` + `/built-in-agent/troubleshooting/migrate-to-1.8.2`. Confirm zero `[docs-render] snippet missing` and zero `Expected component ComponentExamples to be defined` warnings in the dev server log. - [ ] Local: confirm the ComponentExamples Tabs block actually renders on `/crewai-crews/quickstart` (was silently missing pre-fix). - [ ] Post-deploy: re-check Railway logs for the warning + error class over a sample of page loads.
2 parents b672090 + d0741b4 commit 14bb968

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

showcase/shell-docs/src/lib/docs-render.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,7 @@ export const SNIPPET_MAP: Record<string, string> = {
806806
MigrateTo: "shared/troubleshooting/migrate-to-v2.mdx",
807807
MigrateToV: "shared/troubleshooting/migrate-to-v2.mdx",
808808
CopilotUI: "copilot-ui.mdx",
809+
ComponentExamples: "component-examples.mdx",
809810
LandingCodeShowcase: "landing-code-showcase.mdx",
810811
UseAgentSnippet: "use-agent.mdx",
811812
InstallSDKSnippet: "install-sdk.mdx",
@@ -1013,11 +1014,40 @@ function isInsideCodeFence(content: string, offset: number): boolean {
10131014
return inlineToggles % 2 === 1;
10141015
}
10151016

1017+
/**
1018+
* Names that look like JSX components (PascalCase) imported into the MDX
1019+
* via `import { ... }` or `import Foo` from any path. Used by the
1020+
* inliner to distinguish real React components (resolved at render time
1021+
* via the docsComponents registry) from snippet references that should
1022+
* map to entries in SNIPPET_MAP. Without this, every imported component
1023+
* usage logs a false-positive "snippet missing" warning because
1024+
* stripLeadingImports() removes the import lines before the regex scan.
1025+
*/
1026+
function gatherImportedComponentNames(source: string): Set<string> {
1027+
const names = new Set<string>();
1028+
const importRegex =
1029+
/^import\s+(?:type\s+)?(?:\{([^}]+)\}|(\w+))\s+from\s+["'][^"']+["']\s*;?\s*$/gm;
1030+
let m: RegExpExecArray | null;
1031+
while ((m = importRegex.exec(source)) !== null) {
1032+
if (m[1]) {
1033+
for (const part of m[1].split(",")) {
1034+
const renamed = part.trim().split(/\s+as\s+/);
1035+
const name = renamed[renamed.length - 1].trim();
1036+
if (/^[A-Z]\w*$/.test(name)) names.add(name);
1037+
}
1038+
} else if (m[2] && /^[A-Z]\w*$/.test(m[2])) {
1039+
names.add(m[2]);
1040+
}
1041+
}
1042+
return names;
1043+
}
1044+
10161045
export function inlineSnippets(
10171046
content: string,
10181047
slugPath: string = "",
10191048
seen: Set<string> = new Set(),
10201049
): string {
1050+
const importedComponentNames = gatherImportedComponentNames(content);
10211051
let result = stripLeadingImports(content);
10221052

10231053
result = result.replace(
@@ -1070,6 +1100,26 @@ export function inlineSnippets(
10701100
if (componentName.endsWith("Icon")) {
10711101
return match;
10721102
}
1103+
// Icon-library components also hit the inliner as bare JSX
1104+
// references (no explicit import — the registry provides them
1105+
// via docsComponents at render time). Lucide square-prefixed
1106+
// icons (SquareTerminal, SquareChartGantt, etc.), react-icons
1107+
// fa/si/pi prefixes, and similar PascalCase + icon-library
1108+
// shapes don't match the trailing-Icon filter above. Skip
1109+
// them by name shape so the inliner doesn't log a warning for
1110+
// every icon usage.
1111+
if (/^(Fa|Si|Pi|Square)[A-Z]/.test(componentName)) {
1112+
return match;
1113+
}
1114+
// Skip components the MDX explicitly imports. They're real React
1115+
// components rendered through the docsComponents registry at
1116+
// request time, not snippet references. stripLeadingImports()
1117+
// above removes the import line; gatherImportedComponentNames()
1118+
// preserved the set so the inliner can tell these apart from
1119+
// genuine missing-snippet cases.
1120+
if (importedComponentNames.has(componentName)) {
1121+
return match;
1122+
}
10731123
// Log so docs authors see a clean signal when a <Component />
10741124
// reference can't be mapped to a snippet file (previously the
10751125
// component just silently rendered nothing). Matches inside code

0 commit comments

Comments
 (0)