Skip to content

fix(blog): resolve blog author avatars at build time#1879

Open
danielroe wants to merge 2 commits intomainfrom
perf/build-authors
Open

fix(blog): resolve blog author avatars at build time#1879
danielroe wants to merge 2 commits intomainfrom
perf/build-authors

Conversation

@danielroe
Copy link
Member

🔗 Linked issue

🧭 Context

📚 Description

this is a slight perf improvement, hopefully!

@vercel
Copy link

vercel bot commented Mar 3, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Mar 3, 2026 0:49am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Mar 3, 2026 0:49am
npmx-lunaria Ignored Ignored Mar 3, 2026 0:49am

Request Review

@codecov
Copy link

codecov bot commented Mar 3, 2026

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/AuthorList.vue 50.00% 1 Missing ⚠️
app/components/global/BlogPostWrapper.vue 75.00% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9c20cd and cd0d3bd.

📒 Files selected for processing (1)
  • test/nuxt/a11y.spec.ts

📝 Walkthrough

Walkthrough

This pull request moves author avatar/profile resolution to build time and introduces distinct schemas for raw and resolved data. It adds ResolvedAuthorSchema and RawBlogPostSchema, updates blog loading to batch-fetch Bluesky avatars and enrich author objects, and preloads posts for generation. Several Vue components (AuthorList, BlogPostListCard, OgImage/BlogPost, BlogPostWrapper) change props to accept ResolvedAuthor[] and adjust usage to the resolved authors shape. Tests were updated to include avatar and profileUrl fields in test author fixtures.

Possibly related PRs

Suggested reviewers

  • whitep4nth3r
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The pull request description aligns with the changeset, which resolves author avatars at build time rather than runtime, constituting a performance improvement as stated.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch perf/build-authors

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
Contributor

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/blog.ts (1)

88-91: ⚠️ Potential issue | 🔴 Critical

Guard date normalisation to prevent build-breaking RangeError.

new Date(...).toISOString() throws RangeError: Invalid time value on invalid dates, bypassing schema validation entirely and breaking the build. Invalid dates should fail validation gracefully instead of crashing the build process.

Suggested fix
-    if (frontmatter.date) {
-      const raw = frontmatter.date
-      frontmatter.date = new Date(raw instanceof Date ? raw : String(raw)).toISOString()
-    }
+    if (frontmatter.date) {
+      const parsedDate = frontmatter.date instanceof Date
+        ? frontmatter.date
+        : new Date(String(frontmatter.date))
+      if (!Number.isNaN(parsedDate.getTime())) {
+        frontmatter.date = parsedDate.toISOString()
+      }
+    }

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ea6f11 and b9c20cd.

📒 Files selected for processing (6)
  • app/components/AuthorList.vue
  • app/components/BlogPostListCard.vue
  • app/components/OgImage/BlogPost.vue
  • app/components/global/BlogPostWrapper.vue
  • modules/blog.ts
  • shared/schemas/blog.ts

Comment on lines +46 to +48
<div v-if="post?.authors" class="mb-12 max-w-prose mx-auto">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<AuthorList :authors="frontmatter.authors" variant="expanded" />
<AuthorList :authors="post.authors" variant="expanded" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Guard on author count, not just array existence.

post?.authors is truthy even when empty, so this section can render with no visible content.

Suggested fix
-    <div v-if="post?.authors" class="mb-12 max-w-prose mx-auto">
+    <div v-if="post?.authors?.length" class="mb-12 max-w-prose mx-auto">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div v-if="post?.authors" class="mb-12 max-w-prose mx-auto">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<AuthorList :authors="frontmatter.authors" variant="expanded" />
<AuthorList :authors="post.authors" variant="expanded" />
<div v-if="post?.authors?.length" class="mb-12 max-w-prose mx-auto">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<AuthorList :authors="post.authors" variant="expanded" />

Comment on lines +34 to +36
const response = await fetch(
`${BLUESKY_API}/xrpc/app.bsky.actor.getProfiles?${params.toString()}`,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify fetch call currently lacks timeout/abort signal wiring
rg -nP "getProfiles\?" modules/blog.ts -C5
rg -nP "AbortController|signal:" modules/blog.ts -C3

Repository: npmx-dev/npmx.dev

Length of output: 421


🏁 Script executed:

#!/bin/bash
# Get broader context around the fetch call to understand the function scope
sed -n '1,50p' modules/blog.ts

Repository: npmx-dev/npmx.dev

Length of output: 1658


🏁 Script executed:

#!/bin/bash
# Get the rest of the function and where it's called
sed -n '45,100p' modules/blog.ts

Repository: npmx-dev/npmx.dev

Length of output: 2038


🏁 Script executed:

#!/bin/bash
# Find where loadBlogPosts is called and if it's in module setup
sed -n '100,200p' modules/blog.ts

Repository: npmx-dev/npmx.dev

Length of output: 2657


Add an abort timeout for the Bluesky fetch call.

A hanging Bluesky request can stall the full build because this runs during module setup (line 141 in the defineNuxtModule.setup() function).

Suggested fix
-    const response = await fetch(
-      `${BLUESKY_API}/xrpc/app.bsky.actor.getProfiles?${params.toString()}`,
-    )
+    const controller = new AbortController()
+    const timeout = setTimeout(() => controller.abort(), 8000)
+    let response: Response
+    try {
+      response = await fetch(
+        `${BLUESKY_API}/xrpc/app.bsky.actor.getProfiles?${params.toString()}`,
+        { signal: controller.signal },
+      )
+    } finally {
+      clearTimeout(timeout)
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const response = await fetch(
`${BLUESKY_API}/xrpc/app.bsky.actor.getProfiles?${params.toString()}`,
)
const controller = new AbortController()
const timeout = setTimeout(() => controller.abort(), 8000)
let response: Response
try {
response = await fetch(
`${BLUESKY_API}/xrpc/app.bsky.actor.getProfiles?${params.toString()}`,
{ signal: controller.signal },
)
} finally {
clearTimeout(timeout)
}

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.

1 participant