diff --git a/.changeset/bright-keys-sell.md b/.changeset/bright-keys-sell.md new file mode 100644 index 0000000000..0222aaf51c --- /dev/null +++ b/.changeset/bright-keys-sell.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes a bug where content config was ignored if it was outside of content dir and has a parent dir with an underscore diff --git a/.changeset/config.json b/.changeset/config.json index 902828cfe8..7920f52b81 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,7 +4,7 @@ "commit": false, "linked": [], "access": "public", - "baseBranch": "origin/next", + "baseBranch": "next", "updateInternalDependencies": "patch", "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true diff --git a/.changeset/red-paws-juggle.md b/.changeset/red-paws-juggle.md new file mode 100644 index 0000000000..4ab5fb4eb5 --- /dev/null +++ b/.changeset/red-paws-juggle.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix SVG Component sprite references diff --git a/.changeset/sixty-fishes-flow.md b/.changeset/sixty-fishes-flow.md new file mode 100644 index 0000000000..eac560adcb --- /dev/null +++ b/.changeset/sixty-fishes-flow.md @@ -0,0 +1,6 @@ +--- +'@astrojs/react': minor +'astro': minor +--- + +Changes the generated URL query param from `_astroAction` to `_action` when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue. diff --git a/.github/workflows/snapshot-release.yml b/.github/workflows/snapshot-release.yml index 5a8179e808..ae8d3060fa 100644 --- a/.github/workflows/snapshot-release.yml +++ b/.github/workflows/snapshot-release.yml @@ -84,8 +84,6 @@ jobs: - name: Bump Package Versions id: changesets run: | - # Snapshots don't work in pre mode. See https://github.com/changesets/changesets/issues/1195 - pnpm exec changeset pre exit || true pnpm exec changeset status --output status.output.json 2>&1 # Snapshots don't work in pre mode. See https://github.com/changesets/changesets/issues/1195 pnpm exec changeset pre exit || true diff --git a/examples/basics/src/assets/astro.svg b/examples/basics/src/assets/astro.svg new file mode 100644 index 0000000000..8cf8fb0c7d --- /dev/null +++ b/examples/basics/src/assets/astro.svg @@ -0,0 +1 @@ + diff --git a/examples/basics/src/assets/background.svg b/examples/basics/src/assets/background.svg new file mode 100644 index 0000000000..4b2be0ac0e --- /dev/null +++ b/examples/basics/src/assets/background.svg @@ -0,0 +1 @@ + diff --git a/examples/basics/src/components/Welcome.astro b/examples/basics/src/components/Welcome.astro new file mode 100644 index 0000000000..d08955687f --- /dev/null +++ b/examples/basics/src/components/Welcome.astro @@ -0,0 +1,209 @@ +--- +import astroLogo from '../assets/astro.svg'; +import background from '../assets/background.svg'; +--- + +
+ +
+
+ Astro Homepage +

+ To get started, open the
src/pages
directory in your project. +

+ +
+
+ + + +

What's New in Astro 5.0?

+

+ From content layers to server islands, click to learn more about the new features and + improvements in Astro 5.0 +

+
+
+ + diff --git a/examples/basics/src/layouts/Layout.astro b/examples/basics/src/layouts/Layout.astro index a25b9e69d5..e455c61067 100644 --- a/examples/basics/src/layouts/Layout.astro +++ b/examples/basics/src/layouts/Layout.astro @@ -11,3 +11,12 @@ + + diff --git a/examples/basics/src/pages/index.astro b/examples/basics/src/pages/index.astro index a2bf4ee37b..c04f3602b5 100644 --- a/examples/basics/src/pages/index.astro +++ b/examples/basics/src/pages/index.astro @@ -1,8 +1,11 @@ --- -import { Welcome } from 'astro:components'; +import Welcome from '../components/Welcome.astro'; import Layout from '../layouts/Layout.astro'; + +// Welcome to Astro! Wondering what to do next? Check out the Astro documentation at https://docs.astro.build +// Don't want to use any of this? Delete everything in this file, the `assets`, `components`, and `layouts` directories, and start fresh. --- - + diff --git a/examples/server-islands/tsconfig.json b/examples/server-islands/tsconfig.json deleted file mode 100644 index 8bf91d3bb9..0000000000 --- a/examples/server-islands/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "astro/tsconfigs/strict", - "include": [".astro/types.d.ts", "**/*"], - "exclude": ["dist"] -} diff --git a/packages/astro/components/Welcome.astro b/packages/astro/components/Welcome.astro deleted file mode 100644 index 2f91eb5ddd..0000000000 --- a/packages/astro/components/Welcome.astro +++ /dev/null @@ -1,172 +0,0 @@ ---- -interface Props { - title?: string; -} - -const cards = [ - { - href: 'https://docs.astro.build/', - title: 'Documentation', - body: 'Learn how Astro works and explore the official API docs.', - }, - { - href: 'https://astro.build/integrations/', - title: 'Integrations', - body: 'Supercharge your project with new frameworks and libraries.', - }, - { - href: 'https://astro.build/themes/', - title: 'Themes', - body: 'Explore a galaxy of community-built starter themes.', - }, - { - href: 'https://astro.build/chat/', - title: 'Community', - body: 'Come say hi to our amazing Discord community. ❤️', - }, -]; - -const { title = 'Welcome to Astro' } = Astro.props; ---- - -
- -

{title}

-

- To get started, open the directory src/pages in your project.
- Code Challenge: Tweak the "Welcome to Astro" message above. -

- -
- - diff --git a/packages/astro/components/index.ts b/packages/astro/components/index.ts index 31a9bd5977..4107dadfa2 100644 --- a/packages/astro/components/index.ts +++ b/packages/astro/components/index.ts @@ -4,5 +4,3 @@ export { default as Code } from './Code.astro'; // @ts-ignore export { default as Debug } from './Debug.astro'; -// @ts-ignore -export { default as Welcome } from './Welcome.astro'; diff --git a/packages/astro/e2e/actions-blog.test.js b/packages/astro/e2e/actions-blog.test.js index 7d362334e3..84981f078e 100644 --- a/packages/astro/e2e/actions-blog.test.js +++ b/packages/astro/e2e/actions-blog.test.js @@ -162,7 +162,7 @@ test.describe('Astro Actions - Blog', () => { await page.goto(astro.resolveUrl('/sum')); const submitButton = page.getByTestId('submit'); await submitButton.click(); - await expect(page).toHaveURL(astro.resolveUrl('/sum?_astroAction=sum')); + await expect(page).toHaveURL(astro.resolveUrl('/sum?_action=sum')); const p = page.locator('p').nth(0); await expect(p).toContainText('Form result: {"data":3}'); }); diff --git a/packages/astro/src/actions/consts.ts b/packages/astro/src/actions/consts.ts index 35137df59a..88fafb8a31 100644 --- a/packages/astro/src/actions/consts.ts +++ b/packages/astro/src/actions/consts.ts @@ -6,7 +6,7 @@ export const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = '\0astro:internal-actions'; export const NOOP_ACTIONS = '\0noop-actions'; export const ACTION_QUERY_PARAMS = { - actionName: '_astroAction', + actionName: '_action', actionPayload: '_astroActionPayload', }; diff --git a/packages/astro/src/assets/runtime.ts b/packages/astro/src/assets/runtime.ts index e48a7139f4..b0f23e4e88 100644 --- a/packages/astro/src/assets/runtime.ts +++ b/packages/astro/src/assets/runtime.ts @@ -16,21 +16,13 @@ export interface SvgComponentProps { /** * Make sure these IDs are kept on the module-level so they're incremented on a per-page basis */ -const ids = new WeakMap(); -let counter = 0; +const countersByPage = new WeakMap(); export function createSvgComponent({ meta, attributes, children }: SvgComponentProps) { - const rendered = new WeakSet(); + const renderedIds = new WeakMap(); + const Component = createComponent((result, props) => { - let id; - if (ids.has(result)) { - id = ids.get(result)!; - } else { - counter += 1; - ids.set(result, counter); - id = counter; - } - id = `a:${id}`; + let counter = countersByPage.get(result) ?? 0; const { title: titleProp, @@ -41,12 +33,15 @@ export function createSvgComponent({ meta, attributes, children }: SvgComponentP const title = titleProp ? unescapeHTML(`${titleProp}`) : ''; if (mode === 'sprite') { - // On the first render, include the symbol definition + // On the first render, include the symbol definition and bump the counter let symbol: any = ''; - if (!rendered.has(result.response)) { + let id = renderedIds.get(result); + if (!id) { + countersByPage.set(result, ++counter); + id = `a:${counter}`; // We only need the viewBox on the symbol definition, we can drop it everywhere else symbol = unescapeHTML(`${children}`); - rendered.add(result.response); + renderedIds.set(result, id); } return render`${title}${symbol}`; diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index 1cdafa1907..16d703fc78 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -421,14 +421,14 @@ export function getEntryType( const { ext } = path.parse(entryPath); const fileUrl = pathToFileURL(entryPath); - if (hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir)) { + if (fileUrl.href === paths.config.url.href) { + return 'config'; + } else if (hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir)) { return 'ignored'; } else if (contentFileExts.includes(ext)) { return 'content'; } else if (dataFileExts.includes(ext)) { return 'data'; - } else if (fileUrl.href === paths.config.url.href) { - return 'config'; } else { return 'ignored'; } diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 1ebe3900d1..c0fef78a02 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -322,7 +322,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * * Deploy to your favorite server, serverless, or edge host with build adapters. Import one of our first-party adapters for [Netlify](https://docs.astro.build/en/guides/deploy/netlify/#adapter-for-ssr), [Vercel](https://docs.astro.build/en/guides/deploy/vercel/#adapter-for-ssr), and more to engage Astro SSR. * - * [See our Server-side Rendering guide](https://docs.astro.build/en/guides/server-side-rendering/) for more on SSR, and [our deployment guides](https://docs.astro.build/en/guides/deploy/) for a complete list of hosts. + * [See our On-demand Rendering guide](https://docs.astro.build/en/guides/on-demand-rendering/) for more on SSR, and [our deployment guides](https://docs.astro.build/en/guides/deploy/) for a complete list of hosts. * * ```js * import netlify from '@astrojs/netlify'; @@ -1710,7 +1710,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { }; /** - * @docs + * * @kind heading * @name Legacy Flags * @description @@ -1720,7 +1720,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ legacy?: { /** - * @docs + * * @name legacy.collections * @type {boolean} * @default `false` @@ -1757,13 +1757,12 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * export const collections = { blog }; * ``` * - */ collections?: boolean; }; /** - * @docs + * * @kind heading * @name Experimental Flags * @description @@ -1772,7 +1771,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ experimental?: { /** - * @docs + * * @name experimental.clientPrerender * @type {boolean} * @default `false` @@ -1808,7 +1807,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { clientPrerender?: boolean; /** - * @docs + * * @name experimental.contentIntellisense * @type {boolean} * @default `false` @@ -1832,7 +1831,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { contentIntellisense?: boolean; /** - * @docs + * * @name experimental.responsiveImages * @type {boolean} * @default `undefined` @@ -1950,6 +1949,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { responsiveImages?: boolean; /** + * * @docs * @name experimental.session * @type {SessionConfig} @@ -1994,6 +1994,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { session?: SessionConfig; /** + * * @name experimental.svg * @type {boolean|object} * @default `undefined` @@ -2028,7 +2029,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { */ svg?: { /** - * @docs + * * @name experimental.svg.mode * @type {string} * @default 'inline' diff --git a/packages/astro/test/actions.test.js b/packages/astro/test/actions.test.js index 257bf02846..d8da4e72e3 100644 --- a/packages/astro/test/actions.test.js +++ b/packages/astro/test/actions.test.js @@ -220,7 +220,7 @@ describe('Astro Actions', () => { }); it('Response middleware fallback - POST', async () => { - const req = new Request('http://example.com/user?_astroAction=getUser', { + const req = new Request('http://example.com/user?_action=getUser', { method: 'POST', body: new FormData(), headers: { @@ -237,7 +237,7 @@ describe('Astro Actions', () => { it('Response middleware fallback - cookie forwarding', async () => { const req = new Request( - 'http://example.com/user?_astroAction=getUser&actionCookieForwarding=true', + 'http://example.com/user?_action=getUser&actionCookieForwarding=true', { method: 'POST', body: new FormData(), @@ -255,7 +255,7 @@ describe('Astro Actions', () => { }); it('Respects custom errors - POST', async () => { - const req = new Request('http://example.com/user-or-throw?_astroAction=getUserOrThrow', { + const req = new Request('http://example.com/user-or-throw?_action=getUserOrThrow', { method: 'POST', body: new FormData(), headers: { @@ -273,7 +273,7 @@ describe('Astro Actions', () => { it('Respects custom errors - cookie forwarding', async () => { const req = new Request( - 'http://example.com/user-or-throw?_astroAction=getUserOrThrow&actionCookieForwarding=true', + 'http://example.com/user-or-throw?_action=getUserOrThrow&actionCookieForwarding=true', { method: 'POST', body: new FormData(), @@ -320,8 +320,8 @@ describe('Astro Actions', () => { assert.equal('safe' in data, true); }); - it('Ignores `_astroAction` name for GET requests', async () => { - const req = new Request('http://example.com/user-or-throw?_astroAction=getUserOrThrow', { + it('Ignores action name for GET requests', async () => { + const req = new Request('http://example.com/user-or-throw?_action=getUserOrThrow', { method: 'GET', }); const res = await app.render(req); diff --git a/packages/astro/test/core-image-svg.test.js b/packages/astro/test/core-image-svg.test.js index e346cb6a72..6b720b094b 100644 --- a/packages/astro/test/core-image-svg.test.js +++ b/packages/astro/test/core-image-svg.test.js @@ -322,8 +322,9 @@ describe('astro:assets - SVG Components', () => { assert.equal($symbol.length, 1); let $use = $('.one svg > use'); assert.equal($use.length, 2); - let defId = $('.one.def svg > use').attr('id'); - let useId = $('.one.use svg > use').attr('id'); + const defId = $('.one.def svg > symbol').attr('id'); + const useId = $('.one.use svg > use').attr('href').replace('#', ''); + assert.ok(defId); assert.equal(defId, useId); // Second SVG @@ -333,9 +334,10 @@ describe('astro:assets - SVG Components', () => { assert.equal($symbol.length, 1); $use = $('.two svg > use'); assert.equal($use.length, 2); - defId = $('.two.def svg > use').attr('id'); - useId = $('.two.use svg > use').attr('id'); - assert.equal(defId, useId); + const defId2 = $('.two.def svg > symbol').attr('id'); + const useId2 = $('.two.use svg > use').attr('href').replace('#', ''); + assert.ok(defId2); + assert.equal(defId2, useId2); // Third SVG $svg = $('.three svg'); @@ -344,6 +346,12 @@ describe('astro:assets - SVG Components', () => { assert.equal($symbol.length, 1); $use = $('.three svg > use'); assert.equal($use.length, 1); + const defId3 = $('.three.def svg > symbol').attr('id'); + assert.ok(defId3); + + // Assert IDs are different + assert.equal(new Set([defId, defId2, defId3]).size, 3); + assert.equal(new Set([useId, useId2]).size, 2); }); }); diff --git a/packages/integrations/react/server.js b/packages/integrations/react/server.js index 69b0a8e12c..9c3c309cc0 100644 --- a/packages/integrations/react/server.js +++ b/packages/integrations/react/server.js @@ -126,11 +126,7 @@ async function getFormState({ result }) { * This matches the endpoint path. * @example "/_actions/blog.like" */ - const actionName = - searchParams.get('_astroAction') ?? - /* Legacy. TODO: remove for stable */ formData - .get('_astroAction') - ?.toString(); + const actionName = searchParams.get('_action'); if (!actionKey || !actionName) return undefined; diff --git a/packages/integrations/react/src/actions.ts b/packages/integrations/react/src/actions.ts index a5ccb2f9a4..06ecd41489 100644 --- a/packages/integrations/react/src/actions.ts +++ b/packages/integrations/react/src/actions.ts @@ -26,7 +26,7 @@ export function experimental_withState(action: FormFn) { // Called by React when form state is passed from the server. // If the action names match, React returns this state from `useActionState()`. callback.$$IS_SIGNATURE_EQUAL = (incomingActionName: string) => { - const actionName = new URLSearchParams(action.toString()).get('_astroAction'); + const actionName = new URLSearchParams(action.toString()).get('_action'); return actionName === incomingActionName; }; @@ -46,7 +46,9 @@ export function experimental_withState(action: FormFn) { */ export async function experimental_getActionState({ request, -}: { request: Request }): Promise { +}: { + request: Request; +}): Promise { const contentType = request.headers.get('Content-Type'); if (!contentType || !isFormRequest(contentType)) { throw new AstroError(