Skip to content

Commit b697159

Browse files
committed
feat: Enhance Open Graph image resolution and caching logic
- Added directory existence check for mdx-images to prevent errors when accessing images. - Improved error handling and logging for image resolution failures. - Updated asset caching logic to handle Vercel deployment scenarios, ensuring images are correctly managed in read-only environments. - Enhanced overall robustness of the image resolution process by returning null when images are not found, allowing for fallback to default images.
1 parent 92fcc67 commit b697159

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ async function resolveOgImageUrl(
220220
// For relative paths, try to find the processed image in /mdx-images/
221221
// Images get hashed during build, so we need to find the hashed version
222222
if (cleanUrl.startsWith('./')) {
223-
const {readdir} = await import('fs/promises');
223+
const {readdir, access} = await import('fs/promises');
224224
const path = await import('path');
225225

226226
// Extract the base filename without path
@@ -230,6 +230,16 @@ async function resolveOgImageUrl(
230230
try {
231231
// Look for the hashed version in public/mdx-images/
232232
const mdxImagesDir = path.join(process.cwd(), 'public', 'mdx-images');
233+
234+
// Check if directory exists first
235+
try {
236+
await access(mdxImagesDir);
237+
} catch (accessError) {
238+
// eslint-disable-next-line no-console
239+
console.warn('mdx-images directory not accessible:', mdxImagesDir, accessError);
240+
return null; // Return null to fall back to default OG image
241+
}
242+
233243
const files = await readdir(mdxImagesDir);
234244

235245
// Find a file that starts with the same base name
@@ -238,14 +248,22 @@ async function resolveOgImageUrl(
238248
if (hashedFile) {
239249
return `${domain}/mdx-images/${hashedFile}`;
240250
}
251+
252+
// eslint-disable-next-line no-console
253+
console.warn(
254+
'No hashed image found for:',
255+
nameWithoutExt,
256+
'in files:',
257+
files.filter(f => f.includes(nameWithoutExt))
258+
);
241259
} catch (e) {
242-
// If we can't find the hashed version, fall through to default behavior
260+
// eslint-disable-next-line no-console
261+
console.error('Error finding hashed image:', e);
262+
return null; // Return null to fall back to default OG image
243263
}
244264

245-
// Fallback: resolve relative to page directory
246-
const relativePath = cleanUrl.slice(2);
247-
const pageDir = pagePath.join('/');
248-
return `${domain}/${pageDir}/${relativePath}`;
265+
// If we get here, we couldn't find the image - return null to use default
266+
return null;
249267
}
250268

251269
// Default case: treat as relative to page

src/mdx.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,22 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
530530
let cacheKey: string | null = null;
531531
let cacheFile: string | null = null;
532532
let assetsCacheDir: string | null = null;
533-
const outdir = path.join(root, 'public', 'mdx-images');
534-
await mkdir(outdir, {recursive: true});
533+
534+
// During Vercel deployment, use /tmp to avoid read-only file system errors
535+
// The actual images are already built and in public/mdx-images from the build step
536+
const isVercelRuntime = process.env.VERCEL || process.env.VERCEL_ENV;
537+
const outdir = isVercelRuntime
538+
? path.join('/tmp', 'mdx-images-' + md5(sourcePath).slice(0, 8))
539+
: path.join(root, 'public', 'mdx-images');
540+
541+
try {
542+
await mkdir(outdir, {recursive: true});
543+
} catch (e) {
544+
// If we can't create the directory (e.g., read-only filesystem during static generation),
545+
// continue anyway - images should already exist from build time
546+
// eslint-disable-next-line no-console
547+
console.warn('Could not create mdx-images directory:', outdir, (e as Error).message);
548+
}
535549

536550
// If the file contains content that depends on the Release Registry (such as an SDK's latest version), avoid using the cache for that file, i.e. always rebuild it.
537551
// This is because the content from the registry might have changed since the last time the file was cached.
@@ -541,7 +555,8 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
541555
source.includes('<PlatformSDKPackageName') ||
542556
source.includes('<LambdaLayerDetail');
543557

544-
if (process.env.CI) {
558+
// Check cache in CI or Vercel environments
559+
if (process.env.CI || isVercelRuntime) {
545560
if (skipCache) {
546561
// eslint-disable-next-line no-console
547562
console.info(
@@ -555,7 +570,10 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
555570
try {
556571
const [cached, _] = await Promise.all([
557572
readCacheFile<SlugFile>(cacheFile),
558-
cp(assetsCacheDir, outdir, {recursive: true}),
573+
// Only try to copy if the target is writable
574+
isVercelRuntime
575+
? Promise.resolve() // Skip copying on Vercel runtime - images already in public/
576+
: cp(assetsCacheDir, outdir, {recursive: true}),
559577
]);
560578
return cached;
561579
} catch (err) {
@@ -706,7 +724,15 @@ export async function getFileBySlug(slug: string): Promise<SlugFile> {
706724
};
707725

708726
if (assetsCacheDir && cacheFile && !skipCache) {
709-
await cp(assetsCacheDir, outdir, {recursive: true});
727+
// On Vercel runtime, skip copying since we're using /tmp which is ephemeral
728+
if (!isVercelRuntime) {
729+
try {
730+
await cp(assetsCacheDir, outdir, {recursive: true});
731+
} catch (e) {
732+
// eslint-disable-next-line no-console
733+
console.warn(`Failed to copy assets from cache to output dir:`, e);
734+
}
735+
}
710736
writeCacheFile(cacheFile, JSON.stringify(resultObj)).catch(e => {
711737
// eslint-disable-next-line no-console
712738
console.warn(`Failed to write MDX cache: ${cacheFile}`, e);

0 commit comments

Comments
 (0)