Skip to content

fix(metadata): encode metadata social image URLs - #3070

Open
NriotHrreion wants to merge 1 commit into
cloudflare:mainfrom
NriotHrreion:fix/issue-3066-og-urls-not-encoded
Open

fix(metadata): encode metadata social image URLs#3070
NriotHrreion wants to merge 1 commit into
cloudflare:mainfrom
NriotHrreion:fix/issue-3066-og-urls-not-encoded

Conversation

@NriotHrreion

Copy link
Copy Markdown
Contributor

Closes #3066

Overview

Next.js percent-encodes og and twitter image URLs during metadata resolution, while vinext could emit absolute string URLs unchanged when they contained spaces or other characters requiring encoding. This produced invalid metadata URLs and could cause social crawlers or link-preview generators to fail when fetching CMS-provided images.

This PR restores Next.js-compatible URL serialization for social image metadata.

What changed

In packages/vinext/src/shims/metadata.tsx, resolveSocialImageUrl() uses resolveMetadataUrl() to resolve social image URLs.

if (
typeof imageUrl === "string" &&
!isAbsoluteOrProtocolRelativeUrl(imageUrl) &&
(!metadataBase || metadataRoute)
) {
return resolveMetadataUrl(imageUrl, getSocialImageMetadataBaseFallback(metadataBase));
}
return resolveMetadataUrl(imageUrl, metadataBase);

However, resolveMetadataUrl() will return the original URL if there is no metadataBase provided.

function resolveMetadataUrl(
url: string | URL,
metadataBase: URL | null | undefined,
trailingSlash?: boolean,
): string {
const value = stringifyUrl(url);
if (!metadataBase) {
return value;
}

So just pass the social image URL into new URL(), and the URL will be encoded automatically. If new URL() fails, this means it may be a relative URL, then just pass it to the resolveMetadataUrl().

try {
  return new URL(imageUrl).href;
} catch {
  // Relative social image URLs are composed with metadataBase below.
}
// ...

Testing

  • pnpm test tests/features.test.ts

@pkg-pr-new

pkg-pr-new Bot commented Aug 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3070
npm i https://pkg.pr.new/create-vinext-app@3070
npm i https://pkg.pr.new/@vinext/types@3070
npm i https://pkg.pr.new/vinext@3070

commit: 05b9172

@github-actions

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 05b9172 against base 20fdac4 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 141.4 KB 141.4 KB ⚫ -0.0%
Client entry size (gzip) vinext 128.8 KB 128.8 KB ⚫ -0.0%
Dev server cold start vinext 3.13 s 3.10 s ⚫ -0.8%
Production build time vinext 3.39 s 3.36 s ⚫ -1.1%
RSC entry closure size (gzip) vinext 115.6 KB 115.6 KB ⚫ +0.0%
Server bundle size (gzip) vinext 196.8 KB 196.8 KB ⚫ +0.0%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

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.

Metadata: og:image / twitter:image URLs are not percent-encoded

1 participant