mirror of
https://github.com/withastro/astro.git
synced 2025-02-03 22:29:08 -05:00
Fix using optimized images with base
(#6643)
* fix(images): Fix images having the wrong path when using `base` * test(images): Add test for using images with base * test: add more tests * chore: changeset * fix: paths * refactor: feedback
This commit is contained in:
parent
25cd3e5749
commit
fc0ed9c53c
19 changed files with 232 additions and 8 deletions
5
.changeset/thick-penguins-turn.md
Normal file
5
.changeset/thick-penguins-turn.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix images not having the proper path when using `base`
|
|
@ -1,6 +1,8 @@
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
import { basename, join } from 'node:path/posix';
|
||||||
import type { StaticBuildOptions } from '../core/build/types.js';
|
import type { StaticBuildOptions } from '../core/build/types.js';
|
||||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
|
import { prependForwardSlash } from '../core/path.js';
|
||||||
import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
|
import { isLocalService, type ImageService, type LocalImageService } from './services/service.js';
|
||||||
import type { ImageMetadata, ImageTransform } from './types.js';
|
import type { ImageMetadata, ImageTransform } from './types.js';
|
||||||
|
|
||||||
|
@ -104,8 +106,19 @@ export async function generateImage(
|
||||||
clientRoot = buildOpts.settings.config.outDir;
|
clientRoot = buildOpts.settings.config.outDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileData = await fs.promises.readFile(new URL('.' + options.src.src, serverRoot));
|
// The original file's path (the `src` attribute of the ESM imported image passed by the user)
|
||||||
const resultData = await imageService.transform(fileData, { ...options, src: options.src.src });
|
const originalImagePath = options.src.src;
|
||||||
|
|
||||||
|
const fileData = await fs.promises.readFile(
|
||||||
|
new URL(
|
||||||
|
'.' +
|
||||||
|
prependForwardSlash(
|
||||||
|
join(buildOpts.settings.config.build.assets, basename(originalImagePath))
|
||||||
|
),
|
||||||
|
serverRoot
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const resultData = await imageService.transform(fileData, { ...options, src: originalImagePath });
|
||||||
|
|
||||||
const finalFileURL = new URL('.' + filepath, clientRoot);
|
const finalFileURL = new URL('.' + filepath, clientRoot);
|
||||||
const finalFolderURL = new URL('./', finalFileURL);
|
const finalFolderURL = new URL('./', finalFileURL);
|
||||||
|
|
|
@ -167,16 +167,12 @@ export default function assets({
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath = prependForwardSlash(
|
filePath = prependForwardSlash(
|
||||||
joinPaths(
|
joinPaths(settings.config.build.assets, propsToFilename(options))
|
||||||
settings.config.base,
|
|
||||||
settings.config.build.assets,
|
|
||||||
propsToFilename(options)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
globalThis.astroAsset.staticImages.set(options, filePath);
|
globalThis.astroAsset.staticImages.set(options, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filePath;
|
return prependForwardSlash(joinPaths(settings.config.base, filePath));
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async buildEnd() {
|
async buildEnd() {
|
||||||
|
|
|
@ -292,6 +292,59 @@ describe('astro:image', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('support base option correctly', () => {
|
||||||
|
before(async () => {
|
||||||
|
fixture = await loadFixture({
|
||||||
|
root: './fixtures/core-image-base/',
|
||||||
|
experimental: {
|
||||||
|
assets: true,
|
||||||
|
},
|
||||||
|
base: '/blog',
|
||||||
|
});
|
||||||
|
await fixture.build();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has base path prefix when using the Image component', async () => {
|
||||||
|
const html = await fixture.readFile('/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const src = $('#local img').attr('src');
|
||||||
|
expect(src.length).to.be.greaterThan(0);
|
||||||
|
expect(src.startsWith('/blog')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has base path prefix when using getImage', async () => {
|
||||||
|
const html = await fixture.readFile('/get-image/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const src = $('img').attr('src');
|
||||||
|
expect(src.length).to.be.greaterThan(0);
|
||||||
|
expect(src.startsWith('/blog')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has base path prefix when using image directly', async () => {
|
||||||
|
const html = await fixture.readFile('/direct/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const src = $('img').attr('src');
|
||||||
|
expect(src.length).to.be.greaterThan(0);
|
||||||
|
expect(src.startsWith('/blog')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has base path prefix in Markdown', async () => {
|
||||||
|
const html = await fixture.readFile('/post/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const src = $('img').attr('src');
|
||||||
|
expect(src.length).to.be.greaterThan(0);
|
||||||
|
expect(src.startsWith('/blog')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has base path prefix in Content Collection frontmatter', async () => {
|
||||||
|
const html = await fixture.readFile('/blog/one/index.html');
|
||||||
|
const $ = cheerio.load(html);
|
||||||
|
const src = $('img').attr('src');
|
||||||
|
expect(src.length).to.be.greaterThan(0);
|
||||||
|
expect(src.startsWith('/blog')).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('build ssg', () => {
|
describe('build ssg', () => {
|
||||||
before(async () => {
|
before(async () => {
|
||||||
fixture = await loadFixture({
|
fixture = await loadFixture({
|
||||||
|
|
11
packages/astro/test/fixtures/core-image-base/package.json
vendored
Normal file
11
packages/astro/test/fixtures/core-image-base/package.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "@test/core-image-ssg",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"astro": "workspace:*"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
"./service": "./src/service.ts"
|
||||||
|
}
|
||||||
|
}
|
BIN
packages/astro/test/fixtures/core-image-base/src/assets/penguin1.jpg
vendored
Normal file
BIN
packages/astro/test/fixtures/core-image-base/src/assets/penguin1.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
packages/astro/test/fixtures/core-image-base/src/assets/penguin2.jpg
vendored
Normal file
BIN
packages/astro/test/fixtures/core-image-base/src/assets/penguin2.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
10
packages/astro/test/fixtures/core-image-base/src/content/blog/one.md
vendored
Normal file
10
packages/astro/test/fixtures/core-image-base/src/content/blog/one.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
title: One
|
||||||
|
image: ~/assets/penguin2.jpg
|
||||||
|
cover:
|
||||||
|
image: ../../assets/penguin1.jpg
|
||||||
|
---
|
||||||
|
|
||||||
|
# A post
|
||||||
|
|
||||||
|
text here
|
15
packages/astro/test/fixtures/core-image-base/src/content/config.ts
vendored
Normal file
15
packages/astro/test/fixtures/core-image-base/src/content/config.ts
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { defineCollection, image, z } from "astro:content";
|
||||||
|
|
||||||
|
const blogCollection = defineCollection({
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
image: image(),
|
||||||
|
cover: z.object({
|
||||||
|
image: image()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = {
|
||||||
|
blog: blogCollection
|
||||||
|
};
|
5
packages/astro/test/fixtures/core-image-base/src/pages/alias.astro
vendored
Normal file
5
packages/astro/test/fixtures/core-image-base/src/pages/alias.astro
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
import image from "~/assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src={image.src} width={image.width} height={image.height} alt="A penguin!" />
|
3
packages/astro/test/fixtures/core-image-base/src/pages/aliasMarkdown.md
vendored
Normal file
3
packages/astro/test/fixtures/core-image-base/src/pages/aliasMarkdown.md
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
![A penguin](~/assets/penguin1.jpg)
|
||||||
|
|
||||||
|
A penguin
|
33
packages/astro/test/fixtures/core-image-base/src/pages/blog/[...slug].astro
vendored
Normal file
33
packages/astro/test/fixtures/core-image-base/src/pages/blog/[...slug].astro
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
import { getImage } from 'astro:assets';
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const blogEntries = await getCollection('blog');
|
||||||
|
return blogEntries.map(entry => ({
|
||||||
|
params: { slug: entry.slug }, props: { entry },
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { entry } = Astro.props;
|
||||||
|
const { Content } = await entry.render();
|
||||||
|
const myImage = await getImage(entry.data.image);
|
||||||
|
---
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Testing</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Testing</h1>
|
||||||
|
|
||||||
|
<div id="direct-image">
|
||||||
|
<img src={entry.data.image.src} width={entry.data.image.width} height={entry.data.image.height} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="nested-image">
|
||||||
|
<img src={entry.data.cover.image.src} width={entry.data.cover.image.width} height={entry.data.cover.image.height} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Content />
|
||||||
|
</body>
|
||||||
|
</html>
|
5
packages/astro/test/fixtures/core-image-base/src/pages/direct.astro
vendored
Normal file
5
packages/astro/test/fixtures/core-image-base/src/pages/direct.astro
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
import image from "~/assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src={image.src} width={image.width} height={image.height} alt="A penguin!" />
|
18
packages/astro/test/fixtures/core-image-base/src/pages/format.astro
vendored
Normal file
18
packages/astro/test/fixtures/core-image-base/src/pages/format.astro
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
import myImage from "../assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="no-format">
|
||||||
|
<Image src={myImage} alt="a penguin" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="format-avif">
|
||||||
|
<Image src={myImage} alt="a penguin" format="avif" />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
8
packages/astro/test/fixtures/core-image-base/src/pages/get-image.astro
vendored
Normal file
8
packages/astro/test/fixtures/core-image-base/src/pages/get-image.astro
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
|
import image from "../assets/penguin2.jpg";
|
||||||
|
|
||||||
|
const myImage = await getImage({ src: image, width: 207, height: 243, alt: 'a penguin' });
|
||||||
|
---
|
||||||
|
|
||||||
|
<img src={myImage.src} {...myImage.attributes} />
|
18
packages/astro/test/fixtures/core-image-base/src/pages/index.astro
vendored
Normal file
18
packages/astro/test/fixtures/core-image-base/src/pages/index.astro
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
import myImage from "../assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="local">
|
||||||
|
<Image src={myImage} alt="a penguin" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="remote">
|
||||||
|
<Image src="https://avatars.githubusercontent.com/u/622227?s=64" alt="fred" width="48" height="48" />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
3
packages/astro/test/fixtures/core-image-base/src/pages/post.md
vendored
Normal file
3
packages/astro/test/fixtures/core-image-base/src/pages/post.md
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
![My article cover](../assets/penguin1.jpg)
|
||||||
|
|
||||||
|
Image worked
|
22
packages/astro/test/fixtures/core-image-base/src/pages/quality.astro
vendored
Normal file
22
packages/astro/test/fixtures/core-image-base/src/pages/quality.astro
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
import myImage from "../assets/penguin1.jpg";
|
||||||
|
---
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="no-quality">
|
||||||
|
<Image src={myImage} alt="a penguin" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="quality-low">
|
||||||
|
<Image src={myImage} alt="a penguin" quality="low" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="quality-num">
|
||||||
|
<Image src={myImage} alt="a penguin" quality="70" />
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
|
@ -1869,6 +1869,12 @@ importers:
|
||||||
dependencies:
|
dependencies:
|
||||||
astro: link:../../..
|
astro: link:../../..
|
||||||
|
|
||||||
|
packages/astro/test/fixtures/core-image-base:
|
||||||
|
specifiers:
|
||||||
|
astro: workspace:*
|
||||||
|
dependencies:
|
||||||
|
astro: link:../../..
|
||||||
|
|
||||||
packages/astro/test/fixtures/core-image-ssg:
|
packages/astro/test/fixtures/core-image-ssg:
|
||||||
specifiers:
|
specifiers:
|
||||||
astro: workspace:*
|
astro: workspace:*
|
||||||
|
|
Loading…
Add table
Reference in a new issue