Skip to content

feat: extract and preload page images#87

Merged
rsbh merged 8 commits into
mainfrom
worktree-encapsulated-booping-raccoon
May 19, 2026
Merged

feat: extract and preload page images#87
rsbh merged 8 commits into
mainfrom
worktree-encapsulated-booping-raccoon

Conversation

@rsbh
Copy link
Copy Markdown
Member

@rsbh rsbh commented May 19, 2026

Summary

  • Adds remark-collect-images plugin that extracts all image URLs (markdown, HTML, JSX, HAST) from MDX content after path resolution
  • Returns images[] in /api/page response for each page
  • Injects <link rel="preload" as="image"> in SSR HTML <head> for initial page load
  • Prefetches images via new Image() on client-side navigation before MDX renders

Test plan

  • Run bun run dev:examples:basic, verify pages with images have <link rel="preload" as="image"> in page source
  • Navigate between pages in browser, verify Network tab shows image requests starting before MDX content renders
  • Check /api/page?slug=<page-with-images> returns images array with resolved URLs
  • Verify pages without images return empty images: []
  • Verify external image URLs (https://) are preserved as-is
  • Verify relative image paths are resolved to /_content/... URLs

🤖 Generated with Claude Code

rsbh and others added 5 commits May 19, 2026 10:19
Extracts all image sources (markdown, HTML, JSX, HAST) into a
file.data.images array for downstream export. Runs after
remark-resolve-images so URLs are already resolved.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register remarkCollectImages after remarkResolveImages in Vite MDX
config, export 'images' from MDX modules, and add imagesGlob +
getPageImages helper in source.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Includes all resolved image URLs from page content in the API
response for downstream preloading.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds <link rel="preload" as="image"> tags for all page images
during server-side rendering for faster initial page load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After fetching page data from /api/page, preloads all images via
new Image() so they're cached by the browser before MDX renders.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added automatic image detection and collection across documentation pages. Image references are identified, deduplicated, and made available through updated page data and API responses.
  • Improvements

    • Implemented image preloading during server-side rendering. Images referenced in pages are now detected and preloaded via HTML link elements placed in the document head.

Walkthrough

Added end-to-end image preloading infrastructure by extending the MDX build pipeline to collect image URLs, configuring the source loader to inject metadata per page, including images in the API response, and implementing browser preload and SSR preload link emission.

Changes

Image preloading infrastructure

Layer / File(s) Summary
MDX types and build-time image collection
packages/chronicle/src/lib/mdx-utils.ts, packages/chronicle/src/lib/remark-resolve-images.ts
MdxNodeType constant added to identify MDX node types. Remark plugin collects resolved image URLs from MDAST, HTML, JSX, and HAST nodes, deduplicating and filtering empty and data: URIs, then records the unique list on file.data.images.
Vite and source loader integration
packages/chronicle/src/server/vite-config.ts, packages/chronicle/src/lib/source.ts
Vite MDX configuration now exports images alongside readingTime. Source loader adds eager import.meta.glob for images and injects _images into each page's data, with new getPageImages() helper to retrieve the array.
API response with image URLs
packages/chronicle/src/server/api/page.ts
Page API endpoint imports getPageImages and adds images field to the JSON response payload.
Client and SSR preloading
packages/chronicle/src/lib/page-context.tsx, packages/chronicle/src/server/entry-server.tsx
PageData interface extended with optional images field. PageProvider preloads image URLs by instantiating Image objects before loading MDX. SSR entry computes pageImages and emits <link rel="preload" as="image"> tags in the HTML head for each image.

Sequence Diagram

sequenceDiagram
    participant BuildTime as Build Time<br/>Remark Plugin
    participant Runtime as Runtime<br/>Source Loader
    participant API as /api/page<br/>Handler
    participant Client as Browser<br/>PageProvider
    participant SSR as SSR<br/>entry-server
    
    BuildTime->>BuildTime: collect image URLs<br/>from MDAST/HTML/JSX/HAST
    BuildTime->>Runtime: write file.data.images<br/>to vite manifest
    Runtime->>Runtime: load images metadata<br/>inject _images per page
    API->>API: getPageImages(page)<br/>build response
    Client->>API: fetch /api/page?slug
    API->>Client: {images: [urls], ...}
    Client->>Client: instantiate Image()<br/>preload URLs
    SSR->>SSR: getPageImages(page)<br/>compute pageImages
    SSR->>SSR: render <link rel=preload><br/>as=image href
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • raystack/chronicle#44: Extends the existing MDX export pipeline in vite-config.ts to include images alongside readingTime, directly building on prior reading-time infrastructure.
  • raystack/chronicle#46: Modifies remark-resolve-images.ts to process and rewrite image src values; this PR additionally collects the resolved URLs into file.data.images for metadata export.
  • raystack/chronicle#83: Refactors the same /api/page data loading flow in page-context.tsx with React Query; this PR extends that payload with images for preloading.

Suggested reviewers

  • rohilsurana
  • paanSinghCoder
  • rohanchkrabrty
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: extract and preload page images' clearly and accurately summarizes the main change: adding image extraction and preloading functionality.
Description check ✅ Passed The description provides comprehensive details about the image extraction, API response changes, SSR preloading, and client-side prefetching, all directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-encapsulated-booping-raccoon

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chronicle Ready Ready Preview, Comment May 19, 2026 6:11am

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Single tree traversal now both resolves and collects image URLs,
eliminating the separate remark-collect-images plugin.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread packages/chronicle/src/server/entry-server.tsx Outdated
Images are already available from the eager imagesGlob via page
data, so no need to load them again from ssrModules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/chronicle/src/lib/remark-resolve-images.ts (1)

7-7: ⚡ Quick win

Use the configured @/* alias for this import.

Line 7 should use the project alias instead of a relative path for consistency with repo standards.

♻️ Suggested change
-import { MdxNodeType } from './mdx-utils'
+import { MdxNodeType } from '`@/lib/mdx-utils`'

As per coding guidelines, **/*.{ts,tsx}: Use path alias @/*./src/* configured in tsconfig and vite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chronicle/src/lib/remark-resolve-images.ts` at line 7, Replace the
relative import of MdxNodeType with the project path alias: change the import of
MdxNodeType from './mdx-utils' to use the configured alias that maps src to @
(i.e., import from '`@/lib/mdx-utils`') so the file remark-resolve-images.ts
follows the repo's `@/`* import convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/chronicle/src/lib/remark-resolve-images.ts`:
- Line 7: Replace the relative import of MdxNodeType with the project path
alias: change the import of MdxNodeType from './mdx-utils' to use the configured
alias that maps src to @ (i.e., import from '`@/lib/mdx-utils`') so the file
remark-resolve-images.ts follows the repo's `@/`* import convention.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f0d79967-40d7-418c-88ff-9d3c7855d6a1

📥 Commits

Reviewing files that changed from the base of the PR and between 872b936 and e6f0677.

📒 Files selected for processing (7)
  • packages/chronicle/src/lib/mdx-utils.ts
  • packages/chronicle/src/lib/page-context.tsx
  • packages/chronicle/src/lib/remark-resolve-images.ts
  • packages/chronicle/src/lib/source.ts
  • packages/chronicle/src/server/api/page.ts
  • packages/chronicle/src/server/entry-server.tsx
  • packages/chronicle/src/server/vite-config.ts

@rsbh rsbh merged commit 7b44d3e into main May 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants