feat: Remix / React Router 7 integration (aeo.js/remix)#65
Conversation
aeo.js/remix follows the postBuild pattern: detects build/client (Vite builds) or public/ (classic compiler), scans app/routes flat-file and folder routes (pathless layouts and optional segments resolved, dynamic segments skipped), merges prerendered HTML content, and generates all AEO files into the static assets directory. getWidgetScript() provides the root-route widget snippet since Remix has no static index.html. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Docs PreviewPreview URL: https://feat-remix-plugin.aeojs.pages.dev This preview was deployed from the latest commit on this PR. |
- Give config.pages unconditional last-write priority in postBuild so user overrides are never silently dropped by auto-scanned entries that already have content. - Correct the getWidgetScript JSDoc example: the function returns a complete <script> string, so wrapping it in another <script> tag would double-nest it. - Add a regression test confirming config.pages entries beat prerendered HTML for the same pathname. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptileai review |
|
@greptileai review |
…pages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@greptile review |
| // config.pages entries unconditionally overwrite auto-scanned entries | ||
| for (const page of config.pages || []) { | ||
| pageMap.set(page.pathname, page); | ||
| } |
There was a problem hiding this comment.
config.pages override silently drops prerendered content
pageMap.set(page.pathname, page) replaces the entire entry — including any content extracted from prerendered HTML. A user who uses React Router's prerender option and provides a config.pages title/description override for the same route will silently lose the extracted text content, causing empty content in llms-full.txt and ai-index.json. The fix is to shallow-merge instead of replace: pageMap.set(page.pathname, { ...pageMap.get(page.pathname), ...page }). The existing test for this path only asserts on llms.txt (which doesn't include body content), so the content loss goes undetected.
| // config.pages entries unconditionally overwrite auto-scanned entries | |
| for (const page of config.pages || []) { | |
| pageMap.set(page.pathname, page); | |
| } | |
| // config.pages entries unconditionally overwrite auto-scanned entries | |
| for (const page of config.pages || []) { | |
| const existing = pageMap.get(page.pathname); | |
| pageMap.set(page.pathname, existing ? { ...existing, ...page } : page); | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/plugins/remix.ts
Line: 225-228
Comment:
**`config.pages` override silently drops prerendered `content`**
`pageMap.set(page.pathname, page)` replaces the entire entry — including any `content` extracted from prerendered HTML. A user who uses React Router's `prerender` option _and_ provides a `config.pages` title/description override for the same route will silently lose the extracted text content, causing empty content in `llms-full.txt` and `ai-index.json`. The fix is to shallow-merge instead of replace: `pageMap.set(page.pathname, { ...pageMap.get(page.pathname), ...page })`. The existing test for this path only asserts on `llms.txt` (which doesn't include body content), so the content loss goes undetected.
```suggestion
// config.pages entries unconditionally overwrite auto-scanned entries
for (const page of config.pages || []) {
const existing = pageMap.get(page.pathname);
pageMap.set(page.pathname, existing ? { ...existing, ...page } : page);
}
```
How can I resolve this? If you propose a fix, please make it concise.…tekit entries Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the Remix plugin —
FrameworkTypealready listedremix; this ships the integration.What
aeo.js/remixnew entry point following the postBuild pattern:postBuild()— detects the static assets dir (build/clientfor Vite-based Remix/RR7,public/for the classic compiler), scansapp/routesflat-file + folder routes, merges content from prerendered HTML (React Router'sprerenderoption), generates all AEO files into the assets dir._index, dot-delimited nesting, pathless layouts (_marketing.), optional segments (().), trailing-underscore layout opt-out, and skips dynamic segments ($slug) — exported asremixRouteToPathname()and unit-tested.generate()— source-only mode writing intopublic/.getWidgetScript()— root-route widget snippet (Remix has no static index.html to inject into).exportsmap wiringframeworks/remixguide + sidebar entry + README quick start & table rowVerification
tsc --noEmitclean, build succeeds🤖 Generated with Claude Code