0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-24 23:21:57 -05:00

[Actions] Fix middleware warning static mode (#11794)

* fix: remove static usage warning with isPrendered flag

* fix(test): cookie is empty for prerendered routes in dev

* chore: add test route

* chore: changeset
This commit is contained in:
Ben Holmes 2024-08-20 14:41:44 -04:00 committed by GitHub
parent 7e2f142a5a
commit 3691a626fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 81 additions and 26 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes unexpected warning log when using Actions on "hybrid" rendered projects.

View file

@ -17,14 +17,13 @@ export async function getStaticPaths() {
}));
}
type Props = CollectionEntry<'blog'>;
const post = await getEntry('blog', Astro.params.slug)!;
const { Content } = await post.render();
if (Astro.url.searchParams.has('like')) {
await Astro.callAction(actions.blog.like.orThrow, {postId: post.id});
await Astro.callAction(actions.blog.like.orThrow, { postId: post.id });
}
const comment = Astro.getActionResult(actions.blog.comment);
@ -57,17 +56,17 @@ const commentPostIdOverride = Astro.url.searchParams.get('commentPostIdOverride'
/>
<form method="POST" data-testid="progressive-fallback" action={actions.blog.comment.queryString}>
<input type="hidden" name="postId" value={post.id} />
<label for="fallback-author">
Author
</label>
<input id="fallback-author" type="text" name="author" required />
<label for="fallback-body" class="sr-only">
Comment
</label>
<label for="fallback-author"> Author </label>
<input id="fallback-author" type="text" name="author" required />
<label for="fallback-body" class="sr-only"> Comment </label>
<textarea id="fallback-body" rows={10} name="body" required></textarea>
{isInputError(comment?.error) && comment.error.fields.body && (
<p class="error" data-error="body">{comment.error.fields.body.toString()}</p>
)}
{
isInputError(comment?.error) && comment.error.fields.body && (
<p class="error" data-error="body">
{comment.error.fields.body.toString()}
</p>
)
}
<button type="submit">Post Comment</button>
</form>
<div data-testid="server-comments">

View file

@ -22,8 +22,18 @@ export type Locals = {
};
export const onRequest = defineMiddleware(async (context, next) => {
if ((context as any)._isPrerendered) {
if (context.request.method === 'POST') {
// eslint-disable-next-line no-console
console.warn(
yellow('[astro:actions]'),
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".',
);
}
return next();
}
const locals = context.locals as Locals;
const { request } = context;
// Actions middleware may have run already after a path rewrite.
// See https://github.com/withastro/roadmap/blob/feat/reroute/proposals/0047-rerouting.md#ctxrewrite
// `_actionPayload` is the same for every page,
@ -38,16 +48,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
return renderResult({ context, next, ...actionPayload });
}
// Heuristic: If body is null, Astro might've reset this for prerendering.
if (import.meta.env.DEV && request.method === 'POST' && request.body === null) {
// eslint-disable-next-line no-console
console.warn(
yellow('[astro:actions]'),
'POST requests should not be sent to prerendered pages. If you\'re using Actions, disable prerendering with `export const prerender = "false".',
);
return next();
}
const actionName = context.url.searchParams.get(ACTION_QUERY_PARAMS.actionName);
if (context.request.method === 'POST' && actionName) {
@ -92,7 +92,11 @@ async function handlePost({
context,
next,
actionName,
}: { context: APIContext; next: MiddlewareNext; actionName: string }) {
}: {
context: APIContext;
next: MiddlewareNext;
actionName: string;
}) {
const { request } = context;
const baseAction = await getAction(actionName);

View file

@ -114,6 +114,8 @@ export class RenderContext {
const { cookies, middleware, pipeline } = this;
const { logger, serverLike, streaming } = pipeline;
const isPrerendered = !serverLike || this.routeData.prerender;
const props =
Object.keys(this.props).length > 0
? this.props
@ -125,7 +127,7 @@ export class RenderContext {
logger,
serverLike,
});
const apiContext = this.createAPIContext(props);
const apiContext = this.createAPIContext(props, isPrerendered);
this.counter++;
if (this.counter === 4) {
@ -212,12 +214,17 @@ export class RenderContext {
return response;
}
createAPIContext(props: APIContext['props']): APIContext {
createAPIContext(props: APIContext['props'], isPrerendered: boolean): APIContext {
const context = this.createActionAPIContext();
return Object.assign(context, {
props,
getActionResult: createGetActionResult(context.locals),
callAction: createCallAction(context),
// Used internally by Actions middleware.
// TODO: discuss exposing this information from APIContext.
// middleware runs on prerendered routes in the dev server,
// so this is useful information to have.
_isPrerendered: isPrerendered,
});
}

View file

@ -4,6 +4,7 @@ import * as cheerio from 'cheerio';
import * as devalue from 'devalue';
import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
import { serializeActionResult } from '../dist/actions/runtime/virtual/shared.js';
describe('Astro Actions', () => {
let fixture;
@ -25,6 +26,28 @@ describe('Astro Actions', () => {
await devServer.stop();
});
it('Does not process middleware cookie for prerendered routes', async () => {
const cookie = new URLSearchParams();
cookie.append(
'_astroActionPayload',
JSON.stringify({
actionName: 'subscribe',
actionResult: serializeActionResult({
data: { channel: 'bholmesdev', subscribeButtonState: 'smashed' },
error: undefined,
}),
}),
);
const res = await fixture.fetch('/subscribe-prerendered', {
headers: {
Cookie: cookie.toString(),
},
});
const html = await res.text();
const $ = cheerio.load(html);
assert.equal($('body').text().trim(), 'No cookie found.');
});
it('Exposes subscribe action', async () => {
const res = await fixture.fetch('/_actions/subscribe', {
method: 'POST',

View file

@ -0,0 +1,17 @@
---
import { actions } from 'astro:actions';
export const prerender = true;
const result = Astro.getActionResult(actions.subscribe);
---
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>{result?.data?.subscribeButtonState ?? 'No cookie found.'}</body>
</html>