Skip to content

fix(content): resolve content file resources during prerender#2248

Open
benpsnyder wants to merge 10 commits intoanalogjs:alphafrom
benpsnyder:fix/2165-content-resource-prerender-hydration
Open

fix(content): resolve content file resources during prerender#2248
benpsnyder wants to merge 10 commits intoanalogjs:alphafrom
benpsnyder:fix/2165-content-resource-prerender-hydration

Conversation

@benpsnyder
Copy link
Copy Markdown
Contributor

@benpsnyder benpsnyder commented Apr 5, 2026

PR Checklist

Closes contentFileResource fails during prerendering hydration analogjs/analog#2165

Affected scope

  • Primary scope: content
  • Secondary scopes: none

Recommended merge strategy for maintainer [optional]

  • Squash merge
  • Rebase merge
  • Other

Commit preservation note [optional]

What is the new behavior?

contentFileResource() keeps the prerender fix without removing async content resolution.

When a content file loader override is registered through the public CONTENT_FILE_LOADER / injectContentFileLoader() / withContentFileLoader() surface, the resource now uses that loader to resolve the files map. When no loader override is present, it falls back to injectContentFilesMap() so prerendered markdown routes still avoid the initial No Content Found path.

That preserves the published override surface for custom loaders while keeping the blog app prerender path working.

Test plan

  • nx format:check
  • pnpm build
  • pnpm test
  • Manual verification

Manual verification performed:

  • pnpm exec vitest run --config packages/content/vite.config.ts packages/content/resources/src/content-file-resource.spec.ts
  • Verified contentFileResource() respects both a custom async CONTENT_FILE_LOADER override and the default withContentFileLoader() provider in targeted resource tests
  • pnpm exec vite build --config apps/blog-app/vite.config.ts
  • Verified dist/apps/blog-app/analog/public/blog/2022-12-27-my-first-post.html contains My First Post and rendered markdown instead of No Content Found
  • Served the prerendered output locally and confirmed the static route renders My First Post in the browser

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

The blocker on this PR was that the earlier implementation removed the async loader path. The current branch restores that compatibility by routing through the published loader hook first and only using the direct content files map fallback when no loader override is registered.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 5, 2026

Deploy Preview for analog-app ready!

Name Link
🔨 Latest commit f2a6f7d
🔍 Latest deploy log https://app.netlify.com/projects/analog-app/deploys/69de28933538500008f89843
😎 Deploy Preview https://deploy-preview-2248--analog-app.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 5, 2026

Deploy Preview for analog-blog ready!

Name Link
🔨 Latest commit f2a6f7d
🔍 Latest deploy log https://app.netlify.com/projects/analog-blog/deploys/69de2893a7a3ba000806b79c
😎 Deploy Preview https://deploy-preview-2248--analog-blog.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the scope:content Changes in @analogjs/content label Apr 5, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A Playwright test in apps/blog-app-e2e/tests/app.spec.ts was changed from test.fixme(...) to test(...), reactivating the prerendered markdown route test /blog/2022-12-27-my-first-post. In packages/content/resources/src/content-file-resource.spec.ts the DI token used in the test was switched from CONTENT_FILE_LOADER to CONTENT_FILES_TOKEN, and the injected value now supplies args.contentFiles directly. In packages/content/resources/src/content-file-resource.ts the code no longer constructs a loader promise via injectContentFileLoader() or converts it with from(...)/toSignal(...); it now injects injectContentFilesMap() and passes files: contentFilesMap directly to the resource params. An unused from import was removed.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title follows Conventional Commit style with the supported 'content' scope and clearly summarizes the main fix for resolving content file resources during prerender.
Description check ✅ Passed The PR description clearly explains the fix for issue #2165, detailing the new behavior where contentFileResource() supports both custom async loaders and the default content files map fallback for prerendering.

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


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.

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/content/resources/src/content-file-resource.ts`:
- Line 15: The resource currently bypasses the public loader hook by directly
calling injectContentFilesMap(); change content-file-resource.ts to first
attempt the published hook (injectContentFileLoader / CONTENT_FILE_LOADER /
withContentFileLoader) via dependency injection and, if a loader is provided,
call that loader to obtain the files map; only fall back to
injectContentFilesMap() when no loader override is present. Update the logic in
the function/class that currently uses injectContentFilesMap() so it respects
the injected loader symbol names (CONTENT_FILE_LOADER, injectContentFileLoader,
withContentFileLoader) to preserve the override surface.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 157dc76e-6de3-4c75-a12f-9103bb1a29fd

📥 Commits

Reviewing files that changed from the base of the PR and between 9d2855b and 2a82083.

📒 Files selected for processing (1)
  • packages/content/resources/src/content-file-resource.ts

Comment thread packages/content/resources/src/content-file-resource.ts
Copy link
Copy Markdown
Member

@brandonroberts brandonroberts left a comment

Choose a reason for hiding this comment

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

Blocked as this removes the ability to resolve content async

@brandonroberts brandonroberts added the blocked Blocked label Apr 13, 2026
@benpsnyder
Copy link
Copy Markdown
Contributor Author

Updated this branch to address the blocker from your review.

contentFileResource() no longer bypasses async content resolution. It now checks for CONTENT_FILE_LOADER first and calls injectContentFileLoader()() when a loader is provided, so custom overrides and the default withContentFileLoader() provider both continue to resolve the file map asynchronously. It only falls back to injectContentFilesMap() when no loader override is registered, which keeps the prerender fix for contentFileResource fails during prerendering hydration analogjs/analog#2165 without orphaning the public loader hook.

I also added targeted coverage for both paths:

  • custom async CONTENT_FILE_LOADER override
  • default withContentFileLoader() provider

The existing inline CodeRabbit thread is already resolved on the PR, so I think this should clear the blocker now.

@github-actions github-actions Bot added the scope:platform Changes in @analogjs/platform label Apr 13, 2026
@github-actions
Copy link
Copy Markdown

This PR touches multiple package scopes: content, platform.

Please confirm the changes are closely related. Squash merge is highly preferred. If you recommend a non-squash merge, add a brief note explaining why the commit boundaries matter and why this PR should bypass focused changes per package.

@github-actions github-actions Bot added the scope:repo Repository metadata and tooling label Apr 14, 2026
Comment thread pnpm-workspace.yaml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge conflicts scope:content Changes in @analogjs/content scope:platform Changes in @analogjs/platform scope:repo Repository metadata and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants