Repository navigation
feat(pages): resolve crawler meta URLs against the request - #821
Merged
Merged
Conversation
Social crawlers and link previews only read an absolute URL, and a page cannot know its own origin. Resolve a relative `content` against the request URL for og:image, og:video, og:audio and their variants, og:url and twitter:image, after the head layers merge. Prerendered pages keep the value relative: the build runs on a placeholder origin, and baking that origin into the HTML would break every real deployment.
Collaborator
Author
|
👁️🗨️ Review this pull request with grouped, summarized diffs at: raw result💭 analyzed by {
"headSha": "88ea008f099f83b4bc510b7c348719f9094c3b76",
"result": {
"overallSummary": "Social crawlers and link previews only read absolute URLs, but `void.config.ts` cannot know the deployment origin. This PR resolves relative values for the crawler-only meta tags (`og:image`/`video`/`audio` plus `:url`/`:secure_url`, `og:url`, `twitter:image`) against the request URL after the head layers merge, leaving absolute, protocol-relative and all other values untouched. Prerenders deliberately keep relative values because they render on a placeholder origin.",
"groups": [
{
"key": "crawler-url-absolutize",
"label": "Absolutize crawler meta URLs",
"summary": "Adds `absolutizeHead` in `head.ts`, applied after `resolveHead` at every page render entry point, so a relative `og:image` and friends become absolute without the app knowing its origin. Only the listed keys are touched, values already absolute or malformed are kept verbatim, and prerenders pass `undefined` to stay relative.",
"category": "core",
"filePaths": [
"packages/void/src/pages/head.ts",
"packages/void/src/pages/protocol.ts"
],
"critical": true,
"fileNotes": [
{
"path": "packages/void/src/pages/head.ts",
"text": "The base is the request URL, so a bare relative value like `og-image.jpg` resolves against the page's directory, not the site root; only root-relative `/...` values always point at the origin. A new array copy is only made on the first resolved entry, otherwise the input is returned unchanged."
},
{
"path": "packages/void/src/pages/protocol.ts",
"text": "The error-boundary path (`renderPageFailure`) plus `runPageGet` and `runPageMutation` all funnel through the new `resolveRequestHead`, so server-rendered HTML and the page data sent to the client always carry the same absolute values."
}
]
},
{
"key": "tests",
"label": "Unit tests",
"summary": "Covers the new `absolutizeHead`: each required key, `twitter:image` matched by `name`, pass-through for absolute/protocol-relative/unrelated values, the `undefined` head and prerender cases, and malformed input.",
"category": "tests",
"filePaths": [
"packages/void/test/unit/pages-head.test.ts"
]
},
{
"key": "docs",
"label": "Docs",
"summary": "Documents which meta tags get resolved, shows a config example, and warns that prerendered pages keep relative values.",
"category": "docs",
"filePaths": [
"docs/guide/pages-routing/head.md"
]
}
],
"schemaVersion": 1,
"source": "llm",
"generatedAt": "2026-11-13T22:10:08.661Z",
"model": "openai-compatible/opencode-go/deepseek-v4.1-flash",
"locale": "en"
}
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #807
Description
Social crawlers only read an absolute
og:image, andvoid.config.tscannot know the site's origin. After the head layers merge, a relativecontentis now resolved against the request URL forog:image,og:video,og:audioand their:url/:secure_urlvariants,og:url, andtwitter:image. Absolute, protocol-relative, and every other meta tag are left as written. Config, middleware, and page values resolve the same way, and page data carries the same absolute value so client navigation matches.Prerendering keeps the values relative. It renders on a placeholder origin, so baking that origin into the built HTML would break every real deployment.
Test
With
og:image: '/og-image.jpg'invoid.config.tsand a builtplayground/vue-pagesundervp preview:<meta property="og:image" content="/og-image.jpg"><meta property="og:image" content="http://localhost:4174/og-image.jpg">, anddescription: '/not-a-url'unchanged