0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

fix(dev): cosider base when special-casing /_image (#10274)

* fix(dev): cosider `base` when special-casing `/_image`

* add changeset

* adjust tests

* Apply suggestions from code review

* add test
This commit is contained in:
Arsh 2024-03-01 00:08:01 +05:30 committed by GitHub
parent 3757a212c0
commit e556151603
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 53 additions and 21 deletions

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
Fixes a regression introduced in v4.4.5 where image optimization did not work in dev mode when a base was configured.

View file

@ -4,6 +4,7 @@ let formData: FormData | undefined;
if(Astro.request.method === 'POST') {
formData = await Astro.request.formData();
}
export const prerender = false
---
<Layout>
{

View file

@ -471,7 +471,7 @@ async function generatePath(
route: RouteData
) {
const { mod } = gopts;
const { config, logger, options, serverLike } = pipeline;
const { config, logger, options } = pipeline;
logger.debug('build', `Generating: ${pathname}`);
// This adds the page name to the array so it can be shown as part of stats.
@ -502,10 +502,11 @@ async function generatePath(
);
const request = createRequest({
base: config.base,
url,
headers: new Headers(),
logger,
ssr: serverLike,
staticLike: true,
});
const renderContext = RenderContext.create({ pipeline, pathname, request, routeData: route });

View file

@ -1,54 +1,67 @@
import type { IncomingHttpHeaders } from 'node:http';
import type { Logger } from './logger/core.js';
import { appendForwardSlash, prependForwardSlash } from './path.js';
type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData;
export interface CreateRequestOptions {
base: string;
url: URL | string;
clientAddress?: string | undefined;
headers: HeaderType;
method?: string;
body?: RequestBody | undefined;
logger: Logger;
ssr: boolean;
locals?: object | undefined;
removeParams?: boolean;
/**
* Whether the request is being created for a static build or for a prerendered page within a hybrid/SSR build, or for emulating one of those in dev mode.
*
* When `true`, the request will not include search parameters or body, and warn when headers are accessed.
*
* @default false
*/
staticLike?: boolean;
}
const clientAddressSymbol = Symbol.for('astro.clientAddress');
const clientLocalsSymbol = Symbol.for('astro.locals');
export function createRequest({
base,
url,
headers,
clientAddress,
method = 'GET',
body = undefined,
logger,
ssr,
locals,
removeParams = false,
staticLike = false
}: CreateRequestOptions): Request {
let headersObj =
// headers are made available on the created request only if the request is for a page that will be on-demand rendered
const headersObj =
staticLike ? undefined :
headers instanceof Headers
? headers
: new Headers(Object.entries(headers as Record<string, any>));
if (typeof url === 'string') url = new URL(url);
const imageEndpoint = prependForwardSlash(appendForwardSlash(base)) + '_image';
// HACK! astro:assets uses query params for the injected route in `dev`
if (removeParams && url.pathname !== '/_image') {
if (staticLike && url.pathname !== imageEndpoint) {
url.search = '';
}
const request = new Request(url, {
method: method,
headers: headersObj,
body,
// body is made available only if the request is for a page that will be on-demand rendered
body: staticLike ? null : body,
});
if (!ssr) {
if (staticLike) {
// Warn when accessing headers in SSG mode
const _headers = request.headers;
const headersDesc = Object.getOwnPropertyDescriptor(request, 'headers') || {};
@ -63,6 +76,7 @@ export function createRequest({
},
});
} else if (clientAddress) {
// clientAddress is stored to be read by RenderContext, only if the request is for a page that will be on-demand rendered
Reflect.set(request, clientAddressSymbol, clientAddress);
}

View file

@ -10,7 +10,6 @@ import { createRequest } from '../core/request.js';
import { matchAllRoutes } from '../core/routing/index.js';
import { normalizeTheLocale } from '../i18n/index.js';
import { getSortedPreloadedMatches } from '../prerender/routing.js';
import { isServerLikeOutput } from '../prerender/utils.js';
import type { DevPipeline } from './pipeline.js';
import { handle404Response, writeSSRResult, writeWebResponse } from './response.js';
@ -146,8 +145,6 @@ export async function handleRoute({
return handle404Response(origin, incomingRequest, incomingResponse);
}
const buildingToSSR = isServerLikeOutput(config);
let request: Request;
let renderContext: RenderContext;
let mod: ComponentInstance | undefined = undefined;
@ -183,10 +180,12 @@ export async function handleRoute({
return handle404Response(origin, incomingRequest, incomingResponse);
}
request = createRequest({
base: config.base,
url,
headers: buildingToSSR ? incomingRequest.headers : new Headers(),
headers: incomingRequest.headers,
logger,
ssr: buildingToSSR,
// no route found, so we assume the default for rendering the 404 page
staticLike: config.output === "static" || config.output === "hybrid",
});
route = {
component: '',
@ -221,15 +220,14 @@ export async function handleRoute({
// Allows adapters to pass in locals in dev mode.
const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
request = createRequest({
base: config.base,
url,
// Headers are only available when using SSR.
headers: buildingToSSR ? incomingRequest.headers : new Headers(),
headers: incomingRequest.headers,
method: incomingRequest.method,
body,
logger,
ssr: buildingToSSR,
clientAddress: buildingToSSR ? incomingRequest.socket.remoteAddress : undefined,
removeParams: buildingToSSR === false || route.prerender,
clientAddress: incomingRequest.socket.remoteAddress,
staticLike: config.output === "static" || route.prerender,
});
// Set user specified headers to response object.

View file

@ -1041,12 +1041,14 @@ describe('astro:image', () => {
});
describe('dev ssr', () => {
/** @type {import('./test-utils').DevServer} */
let devServer;
before(async () => {
fixture = await loadFixture({
root: './fixtures/core-image-ssr/',
output: 'server',
adapter: testAdapter(),
base: 'some-base',
image: {
service: testImageService(),
},
@ -1058,6 +1060,15 @@ describe('astro:image', () => {
await devServer.stop();
});
it('serves the image at /_image', async () => {
const params = new URLSearchParams;
params.set("href", "/src/assets/penguin1.jpg?origWidth=207&origHeight=243&origFormat=jpg");
params.set("f", "webp");
const response = await fixture.fetch("/some-base/_image?" + String(params));
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'image/webp');
});
it('does not interfere with query params', async () => {
let res = await fixture.fetch('/api?src=image.png');
const html = await res.text();

View file

@ -77,7 +77,9 @@ export default function (
name: 'my-ssr-adapter',
serverEntrypoint: '@my-ssr',
exports: ['manifest', 'createApp'],
supportedAstroFeatures: {},
supportedAstroFeatures: {
serverOutput: "stable"
},
...extendAdapter,
});
},