Skip to content

Commit 0cbac5f

Browse files
authored
feat: Implement Open Graph image resolution logic (#15335)
- Added a helper function to resolve Open Graph image URLs based on various conditions, including manual overrides and fallback mechanisms. - Integrated the new function into the metadata generation process to prioritize custom images, the first image from content, or a default image. - Introduced a new remark plugin to extract the first image from markdown content for use in Open Graph metadata. - Updated frontmatter type definitions to include an optional `og_image` field for custom Open Graph images.
1 parent 8ce3eda commit 0cbac5f

File tree

324 files changed

+1501
-483
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

324 files changed

+1501
-483
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ tsconfig.tsbuildinfo
9797
# Ignore generated files
9898
/public/md-exports/
9999
public/mdx-images/*
100+
public/og-images/*
101+
!public/og-images/README.md
100102

101103
# yalc
102104
.yalc

app/[[...path]]/page.tsx

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,41 @@ function formatCanonicalTag(tag: string) {
194194
return tag;
195195
}
196196

197+
// Helper function to resolve OG image URLs
198+
function resolveOgImageUrl(
199+
imageUrl: string | undefined,
200+
domain: string,
201+
pagePath: string[]
202+
): string | null {
203+
if (!imageUrl) {
204+
return null;
205+
}
206+
207+
// Remove hash fragments (e.g., #600x400 from remark-image-size)
208+
const cleanUrl = imageUrl.split('#')[0];
209+
210+
// External URLs - return as is
211+
if (cleanUrl.startsWith('http://') || cleanUrl.startsWith('https://')) {
212+
return cleanUrl;
213+
}
214+
215+
// Absolute paths (public folder)
216+
if (cleanUrl.startsWith('/')) {
217+
return `${domain}${cleanUrl}`;
218+
}
219+
220+
// Relative paths - resolve based on page path
221+
if (cleanUrl.startsWith('./')) {
222+
const relativePath = cleanUrl.slice(2); // Remove './'
223+
const pageDir = pagePath.join('/');
224+
return `${domain}/${pageDir}/${relativePath}`;
225+
}
226+
227+
// Default case: treat as relative to page
228+
const pageDir = pagePath.join('/');
229+
return `${domain}/${pageDir}/${cleanUrl}`;
230+
}
231+
197232
export async function generateMetadata(props: MetadataProps): Promise<Metadata> {
198233
const params = await props.params;
199234
const domain = isDeveloperDocs
@@ -208,12 +243,8 @@ export async function generateMetadata(props: MetadataProps): Promise<Metadata>
208243
let customCanonicalTag: string = '';
209244
let description =
210245
'Self-hosted and cloud-based application performance monitoring & error tracking that helps software teams see clearer, solve quicker, and learn continuously.';
211-
// show og image on the home page only
212-
const images =
213-
((await props.params).path ?? []).length === 0
214-
? [{url: `${previewDomain ?? domain}/og.png`, width: 1200, height: 630}]
215-
: [];
216246

247+
let ogImageUrl: string | null = null;
217248
let noindex: undefined | boolean = undefined;
218249

219250
const rootNode = await getDocsRootNode();
@@ -236,9 +267,25 @@ export async function generateMetadata(props: MetadataProps): Promise<Metadata>
236267
}
237268

238269
noindex = pageNode.frontmatter.noindex;
270+
271+
// Check for manual OG image override in frontmatter
272+
if (pageNode.frontmatter.og_image) {
273+
ogImageUrl = resolveOgImageUrl(
274+
pageNode.frontmatter.og_image,
275+
previewDomain ?? domain,
276+
params.path
277+
);
278+
}
239279
}
240280
}
241281

282+
// Default fallback
283+
if (!ogImageUrl) {
284+
ogImageUrl = `${previewDomain ?? domain}/og.png`;
285+
}
286+
287+
const images = [{url: ogImageUrl, width: 1200, height: 630}];
288+
242289
const canonical = customCanonicalTag
243290
? domain + customCanonicalTag
244291
: params.path

develop-docs/application-architecture/dynamic-sampling/architecture.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Architecture
33
sidebar_order: 3
4+
og_image: /og-images/application-architecture-dynamic-sampling-architecture.png
45
---
56

67
The architecture that powers Dynamic Sampling is composed of several components that work together to get the organization's sample rate closer to the target fidelity.

develop-docs/application-architecture/dynamic-sampling/fidelity-and-biases.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Fidelity and Biases
33
sidebar_order: 2
4+
og_image: /og-images/application-architecture-dynamic-sampling-fidelity-and-biases.png
45
---
56

67
Dynamic Sampling allows Sentry to automatically adjust the amount of data retained based on how valuable the data is to the user. This is technically achieved by applying a **sample rate** to every event, which is determined by a **set of rules** that are evaluated for each event.

develop-docs/application-architecture/dynamic-sampling/index.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
---
22
title: Dynamic Sampling
3-
description: Dynamic Sampling is a feature of the ingestion pipeline that allows Sentry to automatically adjust the amount of data retained based on the value of the data.
3+
description: >-
4+
Dynamic Sampling is a feature of the ingestion pipeline that allows Sentry to
5+
automatically adjust the amount of data retained based on the value of the
6+
data.
47
sidebar_order: 50
8+
og_image: /og-images/application-architecture-dynamic-sampling.png
59
---
610

711
From all the data received by the SDKs, Sentry is able to extract low-granularity information through metrics, while Dynamic Sampling makes the decision of whether to keep or drop data.

develop-docs/application-architecture/dynamic-sampling/the-big-picture.mdx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
---
22
title: The Big Picture
3-
description: The lifecycle of an event in Sentry is a complex process which involves many components. Dynamic Sampling is one of these components, and it is important to understand how it fits into the bigger picture.
3+
description: >-
4+
The lifecycle of an event in Sentry is a complex process which involves many
5+
components. Dynamic Sampling is one of these components, and it is important
6+
to understand how it fits into the bigger picture.
47
sidebar_order: 1
8+
og_image: /og-images/application-architecture-dynamic-sampling-the-big-picture.png
59
---
610

711
![Sequencing](./images/sequencing.png)

develop-docs/backend/application-domains/database-migrations/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Database Migrations
33
sidebar_order: 20
4+
og_image: /og-images/backend-application-domains-database-migrations.png
45
---
56

67
Django migrations are how we handle changes to the database in Sentry.

develop-docs/backend/application-domains/transaction-clustering/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Clustering URL Transactions
33
sidebar_order: 90
4+
og_image: /og-images/backend-application-domains-transaction-clustering.png
45
---
56

67
Sentry attempts to scrub high-cardinality identifiers from URL transactions

develop-docs/backend/issue-platform/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Issue Platform
33
sidebar_order: 30
4+
og_image: /og-images/backend-issue-platform.jpg
45
---
56

67
The Issue Platform allows developers to create new issue types from arbitrary data sources. If you have data about something that you want to track via an issue, you can build it on the issue platform. For example, building profiling issues on the issue platform allowed us to turn things like “JSON decoding on the main thread” into their own issue types.

develop-docs/backend/issue-platform/writing-detectors/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
title: Writing Detectors
33
sidebar_order: 10
4+
og_image: /og-images/backend-issue-platform-writing-detectors.png
45
---
56

67
Issue detectors identify application issues by examining one or more datasets collected by Sentry, and report detected issue occurrences via the <Link to="/backend/issue-platform/">Issue Platform</Link>. Detectors must fingerprint issues accurately and provide actionable information to developers.

0 commit comments

Comments
 (0)