Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 577d051

Browse filesBrowse files
matthewpclaude
andauthored
Fix bare images used in JSON content collections (#14590)
* fix(content): normalize bare filenames in content layer image() helper Fixes #14456 The image() helper in content layer collections now normalizes bare filenames (e.g., "cover.jpg") to relative paths (e.g., "./cover.jpg") to ensure consistent resolution behavior with markdown frontmatter. Without this normalization, bare filenames were passed directly to Vite's resolver, which treated them as package imports rather than relative file references, causing resolution failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * test(content): add test for bare filename images in JSON collections Adds a test case to verify that bare filenames (e.g., "cover.jpg") work correctly in JSON content layer collections with the image() helper, ensuring they are resolved the same way as in markdown frontmatter. The test includes: - New rockets.json fixture with bare filename and relative path images - Test assertions for both bare filename and relative path resolution - Updated collections.json.js to include the new collection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * chore: add changeset for image path resolution fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix(content): exclude aliases and parent paths from normalization Updates the bare filename normalization to properly skip: - Alias paths starting with ~ (e.g., ~/assets/image.jpg) - Alias paths starting with @ (e.g., @images/image.jpg) - Parent directory paths starting with ../ (e.g., ../image.jpg) This prevents breaking existing alias resolution while still normalizing true bare filenames like "cover.jpg" to "./cover.jpg". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent d5bdbc0 commit 577d051
Copy full SHA for 577d051

7 files changed

+67-4Lines changed: 67 additions & 4 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎.changeset/neat-images-resolve.md‎

Copy file name to clipboard
+5Lines changed: 5 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes image path resolution in content layer collections to support bare filenames. The `image()` helper now normalizes bare filenames like `"cover.jpg"` to relative paths `"./cover.jpg"` for consistent resolution behavior between markdown frontmatter and JSON content collections.
Collapse file

‎packages/astro/src/content/utils.ts‎

Copy file name to clipboardExpand all lines: packages/astro/src/content/utils.ts
+21-2Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,27 @@ export async function getEntryDataAndImages<
184184
schema = schema({
185185
image: () =>
186186
z.string().transform((val) => {
187-
imageImports.add(val);
188-
return `${IMAGE_IMPORT_PREFIX}${val}`;
187+
// Normalize bare filenames to relative paths for consistent resolution
188+
// This ensures bare filenames like "cover.jpg" work the same way as in markdown frontmatter
189+
// Skip normalization for:
190+
// - Relative paths (./foo, ../foo)
191+
// - Absolute paths (/foo)
192+
// - URLs (http://...)
193+
// - Aliases (~/, @/, etc.)
194+
let normalizedPath = val;
195+
if (
196+
val &&
197+
!val.startsWith('./') &&
198+
!val.startsWith('../') &&
199+
!val.startsWith('/') &&
200+
!val.startsWith('~') &&
201+
!val.startsWith('@') &&
202+
!val.includes('://')
203+
) {
204+
normalizedPath = `./${val}`;
205+
}
206+
imageImports.add(normalizedPath);
207+
return `${IMAGE_IMPORT_PREFIX}${normalizedPath}`;
189208
}),
190209
});
191210
}
Collapse file

‎packages/astro/test/content-layer.test.js‎

Copy file name to clipboardExpand all lines: packages/astro/test/content-layer.test.js
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ describe('Content Layer', () => {
281281
assert.ok(json.images[1].data.image.startsWith('https://'));
282282
});
283283

284+
it('loads images with bare filenames in JSON', async () => {
285+
assert.ok(json.rockets[0].data.image.src.startsWith('/_astro'));
286+
assert.equal(json.rockets[0].data.image.format, 'jpg');
287+
});
288+
289+
it('loads images with relative paths in JSON', async () => {
290+
assert.ok(json.rockets[1].data.image.src.startsWith('/_astro'));
291+
assert.equal(json.rockets[1].data.image.format, 'jpg');
292+
});
293+
284294
it('renders images from frontmatter', async () => {
285295
assert.ok($('img[alt="Lunar Module"]').attr('src').startsWith('/_astro'));
286296
});
Collapse file

‎packages/astro/test/fixtures/content-layer/src/content.config.ts‎

Copy file name to clipboardExpand all lines: packages/astro/test/fixtures/content-layer/src/content.config.ts
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,17 @@ const songs = defineCollection({
253253
}),
254254
});
255255

256+
const rockets = defineCollection({
257+
loader: file('src/data/rockets.json'),
258+
schema: ({ image }) =>
259+
z.object({
260+
id: z.string(),
261+
name: z.string(),
262+
manufacturer: z.string(),
263+
image: image(),
264+
}),
265+
});
266+
256267
export const collections = {
257268
blog,
258269
dogs,
@@ -270,6 +281,7 @@ export const collections = {
270281
songs,
271282
probes,
272283
rodents,
284+
rockets,
273285
notADirectory,
274286
nothingMatches
275287
};
Collapse file
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"id": "falcon-9",
4+
"name": "Falcon 9",
5+
"manufacturer": "SpaceX",
6+
"image": "shuttle.jpg"
7+
},
8+
{
9+
"id": "saturn-v",
10+
"name": "Saturn V",
11+
"manufacturer": "NASA",
12+
"image": "./shuttle.jpg"
13+
}
14+
]
Collapse file
170 KB
  • Display the source diff
  • Display the rich diff
Loading
Collapse file

‎packages/astro/test/fixtures/content-layer/src/pages/collections.json.js‎

Copy file name to clipboardExpand all lines: packages/astro/test/fixtures/content-layer/src/pages/collections.json.js
+5-2Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ export async function GET() {
3434
const nestedJsonLoader = await getCollection('birds');
3535

3636
const csvLoader = await getCollection('plants');
37-
37+
38+
const rockets = await getCollection('rockets');
39+
3840
const numbers = await getCollection('numbers');
3941

4042
const numbersYaml = await getCollection('numbersYaml');
@@ -55,7 +57,8 @@ export async function GET() {
5557
numbers,
5658
numbersYaml,
5759
numbersToml,
58-
images,
60+
images,
61+
rockets,
5962
probes,
6063
yamlLoader,
6164
tomlLoader,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.