diff --git a/src/marketing/blogPlugin.test.ts b/src/marketing/blogPlugin.test.ts
new file mode 100644
index 00000000..daafac97
--- /dev/null
+++ b/src/marketing/blogPlugin.test.ts
@@ -0,0 +1,22 @@
+import { describe, expect, it } from 'vitest'
+import { makeBlogAssetUrlsMountSafe } from './blogPlugin'
+
+describe('makeBlogAssetUrlsMountSafe', () => {
+ it('keeps blog media under the current mount path', () => {
+ const html = [
+ '
',
+ '',
+ 'Watch the video',
+ 'Read the docs',
+ ].join('')
+
+ expect(makeBlogAssetUrlsMountSafe(html)).toBe(
+ [
+ '
',
+ '',
+ 'Watch the video',
+ 'Read the docs',
+ ].join(''),
+ )
+ })
+})
diff --git a/src/marketing/blogPlugin.ts b/src/marketing/blogPlugin.ts
index b6598e39..fae55990 100644
--- a/src/marketing/blogPlugin.ts
+++ b/src/marketing/blogPlugin.ts
@@ -44,6 +44,12 @@ function inlineSvgImages(html: string): string {
})
}
+// Blog pages are mounted at /developers/blog in production and /blog in
+// previews. Relative media URLs preserve the active mount path in both places.
+export function makeBlogAssetUrlsMountSafe(html: string): string {
+ return html.replace(/(\b(?:src|href)=["'])\/blog\//g, '$1./')
+}
+
const CATEGORY_SLUGS = ['network-upgrades', 'events', 'technical', 'case-studies']
// ALL-CAPS markdown files (AGENTS.md, DIAGRAMS.md, …) are documentation for
@@ -148,7 +154,7 @@ async function renderPost(filename: string): Promise {
)
}
- const html = inlineSvgImages(String(await processor.process(content)))
+ const html = makeBlogAssetUrlsMountSafe(inlineSvgImages(String(await processor.process(content))))
return {
slug,