返回博客

Empty translated blog posts with manifest-based deployment

2025-10-072 min read

The Problem

After deploying to Cloudflare, translated blog posts (Spanish, German, French, etc.) randomly loaded with empty content. Sometimes they worked fine, sometimes not. The page rendered, but the content was missing.

What is a Manifest File?

My blog posts are stored as JSON files in the codebase, not in a database. This lets me write content in my editor and track everything in Git. Simple.

A manifest file is a pre-generated JSON file that contains all blog post data. Cloudflare Workers don't have access to a traditional filesystem at runtime, they can only use files bundled during the build. So instead of reading individual blog post files at runtime, the build process creates a single manifest with all posts.

The manifest is generated at build time and included in the deployment. At runtime, the code reads from this manifest instead of the filesystem.

The Cause

My manifest structure looks like this:

{
"slug": "my-post",
"translatedSlugs": {
"en": "my-post",
"es": "mi-publicacion"
},
"localized": {
"es": { "title": "...", "content": "..." },
"de": { "title": "...", "content": "..." }
}
}

Notice: English is NOT in the localized object. English content lives at the base level.

My getPostByTranslatedSlug function was doing this:

// Get the post with English locale to access translatedSlugs
const post = getPostBySlug(slug, 'en');

// Check if translatedSlugs match...
if (post.translatedSlugs[someLocale] === translatedSlug) {
return getPostBySlug(slug, requestedLocale);
}

When I called getPostBySlug(slug, 'en'), it tried to access manifest.localized.en which doesn't exist, so it returned empty content.

The Fix

Instead of calling getPostBySlug(slug, 'en'), I changed it to use getAllPosts() which returns all posts with base metadata including translatedSlugs:

export function getPostByTranslatedSlug(translatedSlug: string, locale: string): BlogPost | null {
// Get all posts to access base metadata
const allPosts = getAllPosts();

for (const post of allPosts) {
if (post.translatedSlugs) {
for (const [lang, slugValue] of Object.entries(post.translatedSlugs)) {
if (slugValue === translatedSlug) {
// Found it! Now get the localized version
return getPostBySlug(post.slug, locale);
}
}
}
}
return null;
}

Is Using a Manifest File a Good Practice?

It depends on your deployment target:

For Cloudflare Workers / Edge platforms: Yes, it's necessary. These platforms don't have access to a traditional filesystem, so you need to bundle all data at build time.

For traditional Node.js servers (Vercel, AWS, etc.): Not required. You can read from the filesystem at runtime, which is simpler and doesn't require a build step to generate the manifest.

The tradeoff: manifest files add complexity to your build process and can cause bugs like this one if not structured carefully. But they enable deployment to edge platforms which are faster and cheaper.

Lesson Learned

When using a manifest for static exports:

  • Don't assume the base locale exists in localized
  • Base metadata (like translatedSlugs) lives at the root level
  • Only non-base locales are in localized

保持更新

在您的收件箱中获取最新的文章和见解。

Unsubscribe anytime. No spam, ever.