Skip to content

Commit b803d8b

Browse files
authored
fix: fix image 500 error when moving dist directory in standalone Node (#15169)
* fix: fix image 500 error when moving dist directory in standalone Node * clean up old output directory
1 parent 7f449b7 commit b803d8b

4 files changed

Lines changed: 62 additions & 7 deletions

File tree

.changeset/shaggy-aliens-win.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@astrojs/node': patch
3+
'astro': patch
4+
---
5+
6+
fix: fix image 500 error when moving dist directory in standalone Node

packages/astro/src/assets/endpoint/node.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
// @ts-expect-error
2-
import { outDir } from 'astro:assets';
2+
import { outDir, serverDir } from 'astro:assets';
33
import { readFile } from 'node:fs/promises';
4+
import path from 'node:path';
45
import { fileURLToPath } from 'node:url';
56
import { isParentDirectory } from '@astrojs/internal-helpers/path';
67
import type { APIRoute } from '../../types/public/common.js';
78
import { handleImageRequest } from './shared.js';
89

910
async function loadLocalImage(src: string, url: URL) {
11+
const outDirURL = resolveOutDir();
1012
// If the _image segment isn't at the start of the path, we have a base
1113
const idx = url.pathname.indexOf('/_image');
1214
if (idx > 0) {
1315
// Remove the base path
1416
src = src.slice(idx);
1517
}
16-
if (!URL.canParse('.' + src, outDir)) {
18+
if (!URL.canParse('.' + src, outDirURL)) {
1719
return undefined;
1820
}
19-
const fileUrl = new URL('.' + src, outDir);
21+
const fileUrl = new URL('.' + src, outDirURL);
2022
if (fileUrl.protocol !== 'file:') {
2123
return undefined;
2224
}
23-
if (!isParentDirectory(fileURLToPath(outDir), fileURLToPath(fileUrl))) {
25+
if (!isParentDirectory(fileURLToPath(outDirURL), fileURLToPath(fileUrl))) {
2426
return undefined;
2527
}
2628

@@ -44,3 +46,21 @@ export const GET: APIRoute = async ({ request }) => {
4446
});
4547
}
4648
};
49+
50+
function resolveOutDir() {
51+
const serverDirPath = fileURLToPath(serverDir);
52+
const rel = path.relative(serverDirPath, fileURLToPath(outDir));
53+
54+
const serverFolder = path.basename(serverDirPath);
55+
let serverEntryFolderURL = path.dirname(import.meta.url);
56+
while (!serverEntryFolderURL.endsWith(serverFolder)) {
57+
serverEntryFolderURL = path.dirname(serverEntryFolderURL);
58+
}
59+
const serverEntryURL = serverEntryFolderURL + '/entry.mjs';
60+
const outDirURL = new URL(appendForwardSlash(rel), serverEntryURL);
61+
return outDirURL;
62+
}
63+
64+
function appendForwardSlash(pth: string) {
65+
return pth.endsWith('/') ? pth : pth + '/';
66+
}

packages/astro/src/assets/vite-plugin-assets.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ export default function assets({ fs, settings, sync, logger }: Options): vite.Pl
185185
: settings.config.outDir,
186186
),
187187
)});
188-
export const assetsDir = /* #__PURE__ */ new URL(${JSON.stringify(
189-
settings.config.build.assets,
190-
)}, outDir);
188+
export const serverDir = /* #__PURE__ */ new URL(${JSON.stringify(
189+
new URL(settings.config.build.server),
190+
)});
191191
export const getImage = async (options) => await getImageInternal(options, imageConfig);
192192
193193
export const getFontData = createGetFontData(fontsMod);

packages/integrations/node/test/image.test.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as assert from 'node:assert/strict';
2+
import { cp, rm } from 'node:fs/promises';
23
import { after, before, describe, it } from 'node:test';
34
import { inferRemoteSize } from 'astro/assets/utils/inferRemoteSize.js';
45
import * as cheerio from 'cheerio';
@@ -81,4 +82,32 @@ describe('Image endpoint', () => {
8182
assert.equal(res.status, 403, `Failed on href: ${href}`);
8283
}
8384
});
85+
86+
describe('the dist folder is moved', () => {
87+
const outputDir = new URL('./fixtures/image/output/', import.meta.url);
88+
89+
before(async () => {
90+
await devPreview.stop();
91+
await cp(fixture.config.outDir, new URL('./dist', outputDir), { recursive: true });
92+
await rm(fixture.config.outDir, { recursive: true });
93+
devPreview = await fixture.preview({ outDir: './output/dist' });
94+
});
95+
96+
after(async () => {
97+
await rm(outputDir, { recursive: true });
98+
});
99+
100+
it('it returns local images', async () => {
101+
const res = await fixture.fetch('/');
102+
assert.equal(res.status, 200);
103+
const html = await res.text();
104+
const $ = cheerio.load(html);
105+
106+
const img = $('img[alt=Penguins]').attr('src');
107+
const size = await inferRemoteSize(`http://localhost:4321${img}`);
108+
assert.equal(size.format, 'webp');
109+
assert.equal(size.width, 50);
110+
assert.equal(size.height, 33);
111+
});
112+
});
84113
});

0 commit comments

Comments
 (0)