Skip to content

Conversation

@alexdln
Copy link
Contributor

@alexdln alexdln commented Feb 4, 2026

What

Stars weren't showing up in OG images. This made previews look sad

The problem was that we weren't actually waiting for stars to load, as they're lazy.

Downloads worked because there was an await loadVersion below, which essentially just took longer, and that was enough.

Fix

I added a condition that if it is one of the standard scanners, it will wait for a full render on the server and only then return a response.

Test

To test we can override the agent (Chrome docs) for something like:

facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)

Closes #932

@vercel
Copy link

vercel bot commented Feb 4, 2026

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

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 4, 2026 1:39pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 4, 2026 1:39pm
npmx-lunaria Ignored Ignored Feb 4, 2026 1:39pm

Request Review

@codecov
Copy link

codecov bot commented Feb 4, 2026

Codecov Report

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

Files with missing lines Patch % Lines
app/pages/package/[...package].vue 0.00% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

The PR moves the package OG image definition to the top of the page and changes its data source to packageName and requestedVersion, removing downloads/stars/license inputs and the usePackageDownloads('last-week') hook. The OgImage component (app/components/OgImage/Package.vue) now resolves the exact version server‑side, fetches package, repo and downloads data, converts 4xx version resolution errors to 404, constructs monorepo repository URLs with joinURL, and triggers data refreshes on mount. A new declaration module app/components/OgImage/Package.d.vue.ts was added.

Suggested reviewers

  • danielroe
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description accurately describes the problem (stars not appearing in OG images due to lazy loading), the fix (waiting for full server render for crawlers), and testing approach.
Linked Issues check ✅ Passed The PR addresses issue #932 by modifying the OG image component to wait for full server-side rendering when responding to crawler user agents, ensuring lazy-loaded stars are included in generated images.
Out of Scope Changes check ✅ Passed Changes are focused on fixing star rendering in OG images by refactoring data fetching and server-side rendering logic; all modifications directly support the stated objective.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 1

🧹 Nitpick comments (1)
app/pages/package/[...package].vue (1)

461-463: Redundant case normalisation.

The regex already uses the /i flag for case-insensitive matching, making .toLowerCase() unnecessary.

♻️ Suggested simplification
-  const agent = event?.node.req.headers['user-agent']?.toLowerCase() || ''
-  const crawlerRegex =
-    /(facebookexternalhit|bluesky|twitterbot|linkedinbot|discordbot|slackbot|telegrambot|whatsapp|vkshare|skypeuripreview|googlebot|bingbot|yandexbot|baiduspider|duckduckbot|crawler|spider|bot|preview)/i
+  const agent = event?.node.req.headers['user-agent'] || ''
+  const crawlerRegex =
+    /(facebookexternalhit|bluesky|twitterbot|linkedinbot|discordbot|slackbot|telegrambot|whatsapp|vkshare|skypeuripreview|googlebot|bingbot|yandexbot|baiduspider|duckduckbot|crawler|spider|bot|preview)/i

@alexdln
Copy link
Contributor Author

alexdln commented Feb 4, 2026

Found a specific case: if the user visited this page themselves and visited it before the crawler, we'll cache the user's version (without wait). Generally, this link isn't very accessible to users, and they shouldn't visit it, but it's still topic to talk about

Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

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

How about instead we move this logic into the Package ogImage component itself and perform the fetch there, awaiting the data?

@alexdln
Copy link
Contributor Author

alexdln commented Feb 4, 2026

@danielroe How confident are we in caching and memoization? Couldn't this results that the OG crawler will load data from the main page to obtain the title and description, and the same requests will be sent from this component in parallel?

And how critical is this probability 🤔

@danielroe
Copy link
Member

it would deduplicate.

@alexdln
Copy link
Contributor Author

alexdln commented Feb 4, 2026

It looks much better now, thanks

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

🧹 Nitpick comments (2)
app/components/OgImage/Package.vue (2)

52-57: Consider handling undefined stars gracefully.

If stars.value is undefined or null, Intl.NumberFormat.format() will produce "NaN". Consider providing a fallback value.

♻️ Proposed improvement
 const formattedStars = computed(() =>
   Intl.NumberFormat('en', {
     notation: 'compact',
     maximumFractionDigits: 1,
-  }).format(stars.value),
+  }).format(stars.value ?? 0),
 )

122-123: Consider defensive access for downloads.downloads.

Whilst v-if="downloads" guards against a null downloads object, if the API response structure ever changes or downloads.downloads is undefined, this could display incorrectly. Consider using optional chaining or a fallback.

♻️ Proposed improvement
-        <span v-if="downloads">
-          <span>• {{ $n(downloads.downloads) }} </span>
+        <span v-if="downloads?.downloads != null">
+          <span>• {{ $n(downloads.downloads) }} </span>

@alexdln
Copy link
Contributor Author

alexdln commented Feb 4, 2026

Oops, sorry I missed that. Is there anything I can do to catch these errors locally?

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: 1

🧹 Nitpick comments (1)
app/components/OgImage/Package.vue (1)

51-56: Consider guarding against undefined stars value.

If stars.value is undefined or null before the repo metadata loads, Intl.NumberFormat.format() will return "NaN". Consider providing a fallback.

💡 Suggested improvement
 const formattedStars = computed(() =>
   Intl.NumberFormat('en', {
     notation: 'compact',
     maximumFractionDigits: 1,
-  }).format(stars.value),
+  }).format(stars.value ?? 0),
 )

Comment on lines +1 to +3
const _default: any

export default _default
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

Fix invalid TypeScript declaration syntax.

The const declaration without initialisation is a syntax error. For declaration files (.d.ts / .d.vue.ts), use the declare keyword. Additionally, consider providing a more specific type than any for better type safety.

🛠️ Proposed fix
-const _default: any
-
-export default _default
+declare const _default: import('vue').DefineComponent<{
+  name: string
+  version: string
+  primaryColor?: string
+}>
+
+export default _default

Alternatively, if a minimal fix is preferred:

-const _default: any
+declare const _default: any
📝 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 _default: any
export default _default
declare const _default: any
export default _default
🧰 Tools
🪛 Biome (2.3.13)

[error] 1-1: Const declarations must have an initialized value.

This variable needs to be initialized.

(parse)

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.

fix: Stars are not showing in OG preview

2 participants