Skip to content

Commit 30bc766

Browse files
committed
fix(og): derive og:image origin from incoming request, not env vars
On Netlify deploy previews, og:image was rendering as `https://tanstack.com/api/og/<lib>.png` — pointing at production rather than the preview origin — making the new takumi binary fix impossible to validate from the preview HTML. The previous attempt read `process.env.DEPLOY_PRIME_URL` etc. inside the SSR function, but those variables turn out to be unreliable (or absent) in our bundled function context, so the chain fell through to `URL`, which is the production hostname even on a deploy preview. Use `getRequest()` from `@tanstack/react-start/server` instead — the incoming Request URL is the source of truth for which origin served this page, and it always matches the deploy that's about to fetch the og:image. Verified locally that og:image now renders as `http://localhost:3000/api/og/<lib>.png`. - vite.config.ts: allow `src/utils/og.ts` to import `@tanstack/react-start/server`. Uses are gated by `import.meta.env.SSR` so the import is tree-shaken from the client bundle; allowlisting just lets the static import through the protection check. - og.ts: prefer `new URL(getRequest().url).origin` for the SSR origin, with the env-var chain kept as a fallback for non-request contexts.
1 parent ccd4a68 commit 30bc766

2 files changed

Lines changed: 19 additions & 3 deletions

File tree

src/utils/og.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getRequest } from '@tanstack/react-start/server'
12
import type { LibraryId } from '~/libraries'
23
import { canonicalUrl } from './seo'
34
import {
@@ -20,11 +21,21 @@ type OgImageOptions = {
2021
* og:image URLs MUST be reachable on the same deploy that emitted them
2122
* — social-card validators fetch the URL from the meta tag verbatim.
2223
*
23-
* On Netlify preview/branch deploys, `URL` is still the production URL,
24-
* but `DEPLOY_PRIME_URL` is the deploy's own origin. Prefer that.
24+
* The incoming request URL is the source of truth: on a Netlify deploy
25+
* preview the request hits `deploy-preview-N--tanstack.netlify.app`, so
26+
* the og:image must point there too. `process.env.DEPLOY_PRIME_URL` and
27+
* friends turn out to be unreliable inside the bundled SSR function, so
28+
* we read the origin from the live request instead.
2529
*/
2630
function getOgOrigin(): string {
2731
if (!import.meta.env.SSR) return DEFAULT_SITE_URL
32+
try {
33+
const request = getRequest()
34+
if (request?.url) return new URL(request.url).origin
35+
} catch {
36+
// getRequest() throws if called outside an SSR request context
37+
// (e.g. build-time prerender). Fall through to the env-var fallback.
38+
}
2839
const env = process.env
2940
const origin =
3041
env.DEPLOY_PRIME_URL || env.DEPLOY_URL || env.URL || env.SITE_URL

vite.config.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,12 @@ export default defineConfig({
226226
importProtection: {
227227
behavior: 'error',
228228
client: {
229-
files: ['**/*.server.*', '**/server/**'],
229+
// src/utils/og.ts imports getRequest from @tanstack/react-start/server
230+
// to derive the og:image origin from the live request — uses are
231+
// gated by `import.meta.env.SSR`, so Vite tree-shakes the import out
232+
// of the client bundle. Allowlist the file so the static import
233+
// doesn't trip the protection check during bundling.
234+
files: ['**/*.server.*', '**/server/**', '**/utils/og.ts'],
230235
specifiers: [
231236
'@tanstack/react-start/server',
232237
'uploadthing/server',

0 commit comments

Comments
 (0)