Skip to content

Commit

Permalink
Actions stable release (#11843)
Browse files Browse the repository at this point in the history
* feat: baseline experimental actions

* feat(test): remove experimental config

* feat: remove getActionProps()

* feat: make actions file non-break

* feat: detect actions usage

* chore: changeset

* feat: improve actions usage check

* refactor: remove define action symbol now that we check server exp

* fix: remove old import

* chore: move actionsIntegration to top import

* fix: warn only when actions are used

* fix: srcDir check

* refactor: split out action plugins to simplify integration

* feat: new integration and plugins

* chore: update error hints

* fix(test): pass default src dir

* feat: add ActionNotFoundError

* fix: handle json parse errors in deserializer

* chore: unused import

* 500 -> 404

* New `astro:schema` module (#11810)

* feat: expose zod from astro:schema

* chore: changeset

* chore: update release strategy in changeset

* fix: move deprecated notice to type def

* fix: update config doc reference

* chore: remove z from astro:actions

* edit: changeset with minor release note remove

* wip: increase button click timeouts

* Revert "wip: increase button click timeouts"

This reverts commit a870bc2.

* chore: remove content collections disclaimer

* fix: undo biome change

* agh tabs

* agh newlines

* fix: bad docs merge

* wip: add back timeout extension

* fix(test): astro schema import

* refactor: move static output error to config done

* refactor: usesActions -> isActionsFilePresent

* fix: check whether startup and current value disagree

* chore: unused import

* edit: sell actions a little more

* changeset nit

---------

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
  • Loading branch information
bholmesdev and sarah11918 authored Aug 29, 2024
1 parent 8bab233 commit 5b4070e
Show file tree
Hide file tree
Showing 29 changed files with 361 additions and 418 deletions.
17 changes: 17 additions & 0 deletions .changeset/perfect-wasps-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'astro': minor
---

Exposes `z` from the new `astro:schema` module. This is the new recommended import source for all Zod utilities when using Astro Actions.

## Migration for Astro Actions users

`z` will no longer be exposed from `astro:actions`. To use `z` in your actions, import it from `astro:schema` instead:

```diff
import {
defineAction,
- z,
} from 'astro:actions';
+ import { z } from 'astro:schema';
```
38 changes: 38 additions & 0 deletions .changeset/spicy-suits-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
"astro": minor
---

The Astro Actions API introduced behind a flag in [v4.8.0](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md#480) is no longer experimental and is available for general use.

Astro Actions allow you to define and call backend functions with type-safety, performing data fetching, JSON parsing, and input validation for you.

Actions can be called from client-side components and HTML forms. This gives you to flexibility to build apps using any technology: React, Svelte, HTMX, or just plain Astro components. This example calls a newsletter action and renders the result using an Astro component:

```astro
---
// src/pages/newsletter.astro
import { actions } from 'astro:actions';
const result = Astro.getActionResult(actions.newsletter);
---
{result && !result.error && <p>Thanks for signing up!</p>}
<form method="POST" action={actions.newsletter}>
<input type="email" name="email" />
<button>#</button>
</form>
```

If you were previously using this feature, please remove the experimental flag from your Astro config:

```diff
import { defineConfig } from 'astro'

export default defineConfig({
- experimental: {
- actions: true,
- }
})
```

If you have been waiting for stabilization before using Actions, you can now do so.

For more information and usage examples, see our [brand new Actions guide](https://docs.astro.build/en/guides/actions).
4 changes: 4 additions & 0 deletions packages/astro/client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ declare module 'astro:components' {
export * from 'astro/components';
}

declare module 'astro:schema' {
export * from 'astro/zod';
}

type MD = import('./dist/@types/astro.js').MarkdownInstance<Record<string, any>>;
interface ExportedMarkdownModuleEntities {
frontmatter: MD['frontmatter'];
Expand Down
3 changes: 0 additions & 3 deletions packages/astro/e2e/fixtures/actions-blog/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@ export default defineConfig({
adapter: node({
mode: 'standalone',
}),
experimental: {
actions: true,
},
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { db, Comment, Likes, eq, sql } from 'astro:db';
import { ActionError, defineAction, z } from 'astro:actions';
import { ActionError, defineAction } from 'astro:actions';
import { z } from 'astro:schema';
import { getCollection } from 'astro:content';

export const server = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getActionProps, actions, isInputError } from 'astro:actions';
import { actions, isInputError } from 'astro:actions';
import { useState } from 'react';

export function PostComment({
Expand All @@ -17,6 +17,7 @@ export function PostComment({
<form
method="POST"
data-testid="client"
action={actions.blog.comment}
onSubmit={async (e) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
Expand All @@ -32,38 +33,37 @@ export function PostComment({
form.reset();
}}
>
{unexpectedError && <p data-error="unexpected" style={{ color: 'red' }}>{unexpectedError}</p>}
<input {...getActionProps(actions.blog.comment)} />
{unexpectedError && (
<p data-error="unexpected" style={{ color: 'red' }}>
{unexpectedError}
</p>
)}
<input type="hidden" name="postId" value={postId} />
<label htmlFor="author">
Author
</label>
<label htmlFor="author">Author</label>
<input id="author" type="text" name="author" placeholder="Your name" />
<textarea rows={10} name="body"></textarea>
{bodyError && (
<p data-error="body" style={{ color: 'red' }}>
{bodyError}
</p>
)}
<button type="submit">
Post
</button>
<button type="submit">Post</button>
</form>
<div data-testid="client-comments">
{comments.map((c) => (
<article
key={c.body}
style={{
border: '2px solid color-mix(in srgb, var(--accent), transparent 80%)',
padding: '0.3rem 1rem',
borderRadius: '0.3rem',
marginBlock: '0.3rem',
}}
>
<p>{c.body}</p>
<p>{c.author}</p>
</article>
))}
{comments.map((c) => (
<article
key={c.body}
style={{
border: '2px solid color-mix(in srgb, var(--accent), transparent 80%)',
padding: '0.3rem 1rem',
borderRadius: '0.3rem',
marginBlock: '0.3rem',
}}
>
<p>{c.body}</p>
<p>{c.author}</p>
</article>
))}
</div>
</>
);
Expand Down
3 changes: 0 additions & 3 deletions packages/astro/e2e/fixtures/actions-react-19/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@ export default defineConfig({
adapter: node({
mode: 'standalone',
}),
experimental: {
actions: true,
},
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { db, Likes, eq, sql } from 'astro:db';
import { defineAction, z, type SafeResult } from 'astro:actions';
import { defineAction, type SafeResult } from 'astro:actions';
import { z } from 'astro:schema';
import { experimental_getActionState } from '@astrojs/react/actions';

export const server = {
Expand Down
5 changes: 4 additions & 1 deletion packages/astro/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ process.stdout.isTTY = false;

export default defineConfig({
testMatch: 'e2e/*.test.js',
timeout: 40000,
timeout: 40_000,
expect: {
timeout: 6_000,
},
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
Expand Down
5 changes: 4 additions & 1 deletion packages/astro/playwright.firefox.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ process.stdout.isTTY = false;
export default defineConfig({
// TODO: add more tests like view transitions and audits, and fix them. Some of them are failing.
testMatch: ['e2e/css.test.js', 'e2e/prefetch.test.js', 'e2e/view-transitions.test.js'],
timeout: 40000,
timeout: 40_000,
expect: {
timeout: 6_000,
},
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
Expand Down
101 changes: 0 additions & 101 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1833,107 +1833,6 @@ export interface AstroUserConfig {
*/
directRenderScript?: boolean;

/**
* @docs
* @name experimental.actions
* @type {boolean}
* @default `false`
* @version 4.8.0
* @description
*
* Actions help you write type-safe backend functions you can call from anywhere. Enable server rendering [using the `output` property](https://docs.astro.build/en/basics/rendering-modes/#on-demand-rendered) and add the `actions` flag to the `experimental` object:
*
* ```js
* {
* output: 'hybrid', // or 'server'
* experimental: {
* actions: true,
* },
* }
* ```
*
* Declare all your actions in `src/actions/index.ts`. This file is the global actions handler.
*
* Define an action using the `defineAction()` utility from the `astro:actions` module. An action accepts the `handler` property to define your server-side request handler. If your action accepts arguments, apply the `input` property to validate parameters with Zod.
*
* This example defines two actions: `like` and `comment`. The `like` action accepts a JSON object with a `postId` string, while the `comment` action accepts [FormData](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects) with `postId`, `author`, and `body` strings. Each `handler` updates your database and return a type-safe response.
*
* ```ts
* // src/actions/index.ts
* import { defineAction, z } from "astro:actions";
*
* export const server = {
* like: defineAction({
* input: z.object({ postId: z.string() }),
* handler: async ({ postId }) => {
* // update likes in db
*
* return likes;
* },
* }),
* comment: defineAction({
* accept: 'form',
* input: z.object({
* postId: z.string(),
* author: z.string(),
* body: z.string(),
* }),
* handler: async ({ postId }) => {
* // insert comments in db
*
* return comment;
* },
* }),
* };
* ```
*
* Then, call an action from your client components using the `actions` object from `astro:actions`. You can pass a type-safe object when using JSON, or a [FormData](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects) object when using `accept: 'form'` in your action definition.
*
* This example calls the `like` and `comment` actions from a React component:
*
* ```tsx "actions"
* // src/components/blog.tsx
* import { actions } from "astro:actions";
* import { useState } from "react";
*
* export function Like({ postId }: { postId: string }) {
* const [likes, setLikes] = useState(0);
* return (
* <button
* onClick={async () => {
* const newLikes = await actions.like({ postId });
* setLikes(newLikes);
* }}
* >
* {likes} likes
* </button>
* );
* }
*
* export function Comment({ postId }: { postId: string }) {
* return (
* <form
* onSubmit={async (e) => {
* e.preventDefault();
* const formData = new FormData(e.target as HTMLFormElement);
* const result = await actions.blog.comment(formData);
* // handle result
* }}
* >
* <input type="hidden" name="postId" value={postId} />
* <label htmlFor="author">Author</label>
* <input id="author" type="text" name="author" />
* <textarea rows={10} name="body"></textarea>
* <button type="submit">Post</button>
* </form>
* );
* }
* ```
*
* For a complete overview, and to give feedback on this experimental API, see the [Actions RFC](https://github.com/withastro/roadmap/blob/actions/proposals/0046-actions.md).
*/
actions?: boolean;

/**
* @docs
* @name experimental.contentCollectionCache
Expand Down
Loading

0 comments on commit 5b4070e

Please # to comment.