diff --git a/.changeset/bright-chefs-develop.md b/.changeset/bright-chefs-develop.md deleted file mode 100644 index b0078e085d25..000000000000 --- a/.changeset/bright-chefs-develop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@astrojs/markdoc": minor ---- - -Updates `@markdoc/markdoc` to v0.4 diff --git a/.changeset/brown-pens-type.md b/.changeset/brown-pens-type.md new file mode 100644 index 000000000000..cffcd37c227b --- /dev/null +++ b/.changeset/brown-pens-type.md @@ -0,0 +1,7 @@ +--- +"astro": patch +--- + +Prevent cache content from being left in dist folder + +When `contentCollectionsCache` is enabled temporary cached content is copied into the `outDir` for processing. This fixes it so that this content is cleaned out, along with the rest of the temporary build JS. diff --git a/.changeset/good-turtles-guess.md b/.changeset/good-turtles-guess.md new file mode 100644 index 000000000000..28edbffc0483 --- /dev/null +++ b/.changeset/good-turtles-guess.md @@ -0,0 +1,5 @@ +--- +"@astrojs/web-vitals": patch +--- + +Adds support for deprecating the web vitals DB table, so the integration can be removed if desired diff --git a/.changeset/gorgeous-dancers-return.md b/.changeset/gorgeous-dancers-return.md new file mode 100644 index 000000000000..86659c1c1297 --- /dev/null +++ b/.changeset/gorgeous-dancers-return.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Respect error status when handling Actions with a progressive fallback. diff --git a/.changeset/lorem-ipsum-dolor b/.changeset/lorem-ipsum-dolor deleted file mode 100644 index 15182e8f6cd5..000000000000 --- a/.changeset/lorem-ipsum-dolor +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Fixes static builds when `config.outDir` is located outside of the astro project diff --git a/.changeset/many-icons-kiss.md b/.changeset/many-icons-kiss.md new file mode 100644 index 000000000000..f89dca5edd71 --- /dev/null +++ b/.changeset/many-icons-kiss.md @@ -0,0 +1,5 @@ +--- +"@astrojs/web-vitals": minor +--- + +Upgrades the `web-vitals` dependency to v4 and stops collecting data for the deprecated FID (First Input Delay) metric. diff --git a/.changeset/new-mice-occur.md b/.changeset/new-mice-occur.md new file mode 100644 index 000000000000..266b54652c9d --- /dev/null +++ b/.changeset/new-mice-occur.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Change `slot` attribute of `IntrinsicAttributes` to match the definition of `HTMLAttributes`'s own `slot` attribute of type `string | undefined | null` diff --git a/.changeset/spotty-dots-beg.md b/.changeset/spotty-dots-beg.md deleted file mode 100644 index 91a7c8526adf..000000000000 --- a/.changeset/spotty-dots-beg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@astrojs/db": patch ---- - -Add `astro login` support from online editors like Stackblitz and GitHub Codespaces diff --git a/.changeset/sweet-coins-shop.md b/.changeset/sweet-coins-shop.md deleted file mode 100644 index 02d69af15c6e..000000000000 --- a/.changeset/sweet-coins-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"astro": patch ---- - -Prevent getCollection breaking in vitest diff --git a/.changeset/thick-wasps-know.md b/.changeset/thick-wasps-know.md deleted file mode 100644 index 855a9c7b72b8..000000000000 --- a/.changeset/thick-wasps-know.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@astrojs/markdoc": patch -"@astrojs/vercel": patch -"astro": patch ---- - -Updates `esbuild` dependency to v0.20. This should not affect projects in most cases. diff --git a/.changeset/thirty-walls-yell.md b/.changeset/thirty-walls-yell.md deleted file mode 100644 index 8e63d6e1cfeb..000000000000 --- a/.changeset/thirty-walls-yell.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"astro": patch ---- - -Fixes an issue where images in MD required a relative specifier (e.g. `./`) - -Now, you can use the standard `![](relative/img.png)` syntax in MD files for images colocated in the same folder: no relative specifier required! - -There is no need to update your project; your existing images will still continue to work. However, you may wish to remove any relative specifiers from these MD images as they are no longer necessary: - -```diff -- ![A cute dog](./dog.jpg) -+ ![A cute dog](dog.jpg) - -``` diff --git a/.changeset/weak-swans-sparkle.md b/.changeset/weak-swans-sparkle.md deleted file mode 100644 index ee99d8bc705b..000000000000 --- a/.changeset/weak-swans-sparkle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"astro": patch ---- - -Due to regression on mobile WebKit browsers, reverts a change made for JavaScript animations during view transitions. diff --git a/.changeset/wet-apples-accept.md b/.changeset/wet-apples-accept.md deleted file mode 100644 index 97420fbf3330..000000000000 --- a/.changeset/wet-apples-accept.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@astrojs/partytown": minor ---- - -Updates the `@builder.io/partytown` dependency to v0.10. This should not affect projects in most cases. diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 85a51017b8c4..49a76b9a5b3c 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/javascript-node:0-18 +FROM mcr.microsoft.com/devcontainers/javascript-node:1-18 # Install playwright RUN npm install -g @playwright/test diff --git a/.devcontainer/examples.Dockerfile b/.devcontainer/examples.Dockerfile index 2873106354dd..6ab758c823fd 100644 --- a/.devcontainer/examples.Dockerfile +++ b/.devcontainer/examples.Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/javascript-node:0-18 +FROM mcr.microsoft.com/devcontainers/javascript-node:1-18 # Install latest pnpm RUN npm install -g pnpm diff --git a/.editorconfig b/.editorconfig index 0bb4ad6ecde1..6c6c428353bd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,5 +11,5 @@ indent_style = tab insert_final_newline = true trim_trailing_whitespace = false -[{.*,*.md,*.json,*.toml,*.yml,}] +[{.*,*.md,*.json,*.toml,*.yml,*.json5}] indent_style = space diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 9a93502be550..f4291d43e5fe 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -4,10 +4,12 @@ "config:recommended", "schedule:weekly", "group:allNonMajor", - ":disablePeerDependencies", + ":disablePeerDependencies", + "regexManagers:biomeVersions", ], "labels": ["dependencies"], "rangeStrategy": "bump", + "ignorePaths": ["**/node_modules/**"], "ignoreDeps": [ // manually bumping deps "@biomejs/biome", diff --git a/.github/workflows/snapshot-release.yml b/.github/workflows/snapshot-release.yml index b067394e46df..bee678c962a8 100644 --- a/.github/workflows/snapshot-release.yml +++ b/.github/workflows/snapshot-release.yml @@ -25,10 +25,10 @@ jobs: issues: write pull-requests: write steps: - - name: "Check if user has admin access (only admins can publish snapshot releases)." + - name: "Check if user has write access" uses: "lannonbr/repo-permission-check-action@2.0.2" with: - permission: "admin" + permission: "write" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 82c2ac20d516..2783aac56b42 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ scripts/smoke/*-main/ scripts/memory/project/src/pages/ benchmark/projects/ benchmark/results/ +test-results/ *.log package-lock.json .turbo/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cc891d36986a..c74cd375fba6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,9 @@ We welcome contributions of any size and skill level. As an open source project, we believe in giving back to our contributors and are happy to help with guidance on PRs, technical writing, and turning any feature idea into a reality. -> [!Tip] > **For new contributors:** Take a look at [https://github.com/firstcontributions/first-contributions](https://github.com/firstcontributions/first-contributions) for helpful information on contributing +> [!Tip] +> +> **For new contributors:** Take a look at [https://github.com/firstcontributions/first-contributions](https://github.com/firstcontributions/first-contributions) for helpful information on contributing ## Quick Guide diff --git a/benchmark/make-project/README.md b/benchmark/make-project/README.md index 3199d1b7a747..9d1a421c9b6e 100644 --- a/benchmark/make-project/README.md +++ b/benchmark/make-project/README.md @@ -2,6 +2,6 @@ This `make-project` folder contains different files to programmatically create a new Astro project. They are created inside the `projects` folder and are gitignored. These projects are used by benchmarks for testing. -Each benchmark can specify the default project to run in its `defaultProject` export, but it can be overriden if `--project ` is passed through the CLI. +Each benchmark can specify the default project to run in its `defaultProject` export, but it can be overridden if `--project ` is passed through the CLI. You can duplicate `_template.js` to start a new project script. All shared utilities are kept in `_util.js`. diff --git a/biome.json b/biome.json index fd35328f8184..df61ec83b202 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json", + "$schema": "https://biomejs.dev/schemas/1.7.1/schema.json", "files": { "ignore": [ "vendor", diff --git a/eslint.config.js b/eslint.config.js index 33177f3c3706..47e2b501c63a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,7 +6,6 @@ import { FlatCompat } from '@eslint/eslintrc'; import tseslint from 'typescript-eslint'; // plugins -import prettierEslint from 'eslint-plugin-prettier'; import noOnlyTestsEslint from 'eslint-plugin-no-only-tests'; import regexpEslint from 'eslint-plugin-regexp'; const typescriptEslint = tseslint.plugin; @@ -45,7 +44,6 @@ export default [ ...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked, // mimic ESLintRC-style extends - ...compat.extends('prettier'), ...compat.extends('plugin:regexp/recommended'), { languageOptions: { @@ -57,7 +55,6 @@ export default [ }, plugins: { '@typescript-eslint': typescriptEslint, - prettier: prettierEslint, 'no-only-tests': noOnlyTestsEslint, regexp: regexpEslint, }, diff --git a/examples/basics/package.json b/examples/basics/package.json index 02522acb7a68..4239502142e9 100644 --- a/examples/basics/package.json +++ b/examples/basics/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/blog/package.json b/examples/blog/package.json index 072a6a331779..4a62bdaf7a6e 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.3.1", - "@astrojs/rss": "^4.0.5", + "@astrojs/mdx": "^3.0.0", + "@astrojs/rss": "^4.0.6", "@astrojs/sitemap": "^3.1.4", - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/blog/src/content/blog/markdown-style-guide.md b/examples/blog/src/content/blog/markdown-style-guide.md index 877ec2f4a155..cf02c4198f88 100644 --- a/examples/blog/src/content/blog/markdown-style-guide.md +++ b/examples/blog/src/content/blog/markdown-style-guide.md @@ -31,13 +31,13 @@ Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sap ## Images -#### Syntax +### Syntax ```markdown ![Alt text](./full/or/relative/path/of/image) ``` -#### Output +### Output ![blog placeholder](/blog-placeholder-about.jpg) @@ -77,7 +77,7 @@ The blockquote element represents content that is quoted from another source, op ## Tables -#### Syntax +### Syntax ```markdown | Italics | Bold | Code | @@ -85,7 +85,7 @@ The blockquote element represents content that is quoted from another source, op | _italics_ | **bold** | `code` | ``` -#### Output +### Output | Italics | Bold | Code | | --------- | -------- | ------ | @@ -93,9 +93,9 @@ The blockquote element represents content that is quoted from another source, op ## Code Blocks -#### Syntax +### Syntax -we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntac, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash +we can use 3 backticks ``` in new line and write snippet and close with 3 backticks on new line and to highlight language specific syntax, write one word of language name after first 3 backticks, for eg. html, javascript, css, markdown, typescript, txt, bash ````markdown ```html @@ -112,7 +112,7 @@ we can use 3 backticks ``` in new line and write snippet and close with 3 backti ``` ```` -Output +### Output ```html @@ -187,7 +187,7 @@ Output ## Other Elements β€” abbr, sub, sup, kbd, mark -#### Syntax +### Syntax ```markdown GIF is a bitmap image format. @@ -196,12 +196,12 @@ H2O Xn + Yn = Zn -Press CTRL+ALT+Delete to end the session. +Press CTRL + ALT + Delete to end the session. Most salamanders are nocturnal, and hunt for insects, worms, and other small creatures. ``` -#### Output +### Output GIF is a bitmap image format. @@ -209,6 +209,6 @@ H2O Xn + Yn = Zn -Press CTRL+ALT+Delete to end the session. +Press CTRL + ALT + Delete to end the session. Most salamanders are nocturnal, and hunt for insects, worms, and other small creatures. diff --git a/examples/blog/src/styles/global.css b/examples/blog/src/styles/global.css index fe9ecf0b894d..bbb0c30158e2 100644 --- a/examples/blog/src/styles/global.css +++ b/examples/blog/src/styles/global.css @@ -149,6 +149,6 @@ hr { clip: rect(1px, 1px, 1px, 1px); /* modern browsers, clip-path works inwards from each corner */ clip-path: inset(50%); - /* added line to stop words getting smushed together (as they go onto seperate lines and some screen readers do not understand line feeds as a space */ + /* added line to stop words getting smushed together (as they go onto separate lines and some screen readers do not understand line feeds as a space */ white-space: nowrap; } diff --git a/examples/component/package.json b/examples/component/package.json index bcfcb66ac8d8..a7d670b130bd 100644 --- a/examples/component/package.json +++ b/examples/component/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" }, "peerDependencies": { "astro": "^4.0.0" diff --git a/examples/framework-alpine/package.json b/examples/framework-alpine/package.json index f6639d87d714..5fc4ad314c43 100644 --- a/examples/framework-alpine/package.json +++ b/examples/framework-alpine/package.json @@ -12,8 +12,8 @@ }, "dependencies": { "@astrojs/alpinejs": "^0.4.0", - "@types/alpinejs": "^3.13.5", - "alpinejs": "^3.13.3", - "astro": "^4.6.3" + "@types/alpinejs": "^3.13.10", + "alpinejs": "^3.13.10", + "astro": "^4.8.6" } } diff --git a/examples/framework-lit/package.json b/examples/framework-lit/package.json index 3c70813b7588..6ace874cfacd 100644 --- a/examples/framework-lit/package.json +++ b/examples/framework-lit/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/lit": "^4.0.1", "@webcomponents/template-shadowroot": "^0.2.1", - "astro": "^4.6.3", - "lit": "^3.1.2" + "astro": "^4.8.6", + "lit": "^3.1.3" } } diff --git a/examples/framework-multiple/package.json b/examples/framework-multiple/package.json index b0fd48b55ba5..ae783490f901 100644 --- a/examples/framework-multiple/package.json +++ b/examples/framework-multiple/package.json @@ -11,19 +11,19 @@ "astro": "astro" }, "dependencies": { - "@astrojs/preact": "^3.2.0", - "@astrojs/react": "^3.3.0", - "@astrojs/solid-js": "^4.1.0", + "@astrojs/preact": "^3.3.0", + "@astrojs/react": "^3.3.4", + "@astrojs/solid-js": "^4.2.0", "@astrojs/svelte": "^5.4.0", - "@astrojs/vue": "^4.1.0", - "@types/react": "^18.2.37", - "@types/react-dom": "^18.2.15", - "astro": "^4.6.3", - "preact": "^10.19.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "solid-js": "^1.8.5", - "svelte": "^4.2.5", - "vue": "^3.3.8" + "@astrojs/vue": "^4.2.0", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "astro": "^4.8.6", + "preact": "^10.21.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "solid-js": "^1.8.17", + "svelte": "^4.2.16", + "vue": "^3.4.27" } } diff --git a/examples/framework-preact/package.json b/examples/framework-preact/package.json index 657eaf8bb5aa..073449973f74 100644 --- a/examples/framework-preact/package.json +++ b/examples/framework-preact/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/preact": "^3.2.0", - "@preact/signals": "^1.2.1", - "astro": "^4.6.3", - "preact": "^10.19.2" + "@astrojs/preact": "^3.3.0", + "@preact/signals": "^1.2.3", + "astro": "^4.8.6", + "preact": "^10.21.0" } } diff --git a/examples/framework-react/package.json b/examples/framework-react/package.json index b96a70e073f0..b95dd0aed448 100644 --- a/examples/framework-react/package.json +++ b/examples/framework-react/package.json @@ -11,11 +11,11 @@ "astro": "astro" }, "dependencies": { - "@astrojs/react": "^3.3.0", - "@types/react": "^18.2.37", - "@types/react-dom": "^18.2.15", - "astro": "^4.6.3", - "react": "^18.2.0", - "react-dom": "^18.2.0" + "@astrojs/react": "^3.3.4", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "astro": "^4.8.6", + "react": "^18.3.1", + "react-dom": "^18.3.1" } } diff --git a/examples/framework-solid/package.json b/examples/framework-solid/package.json index 410555d9f6bc..6cda93fe70f3 100644 --- a/examples/framework-solid/package.json +++ b/examples/framework-solid/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/solid-js": "^4.1.0", - "astro": "^4.6.3", - "solid-js": "^1.8.5" + "@astrojs/solid-js": "^4.2.0", + "astro": "^4.8.6", + "solid-js": "^1.8.17" } } diff --git a/examples/framework-svelte/package.json b/examples/framework-svelte/package.json index 9a37664b2ecb..44acfe6ff891 100644 --- a/examples/framework-svelte/package.json +++ b/examples/framework-svelte/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/svelte": "^5.4.0", - "astro": "^4.6.3", - "svelte": "^4.2.5" + "astro": "^4.8.6", + "svelte": "^4.2.16" } } diff --git a/examples/framework-vue/package.json b/examples/framework-vue/package.json index b7a1e49e9959..7416591216d8 100644 --- a/examples/framework-vue/package.json +++ b/examples/framework-vue/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/vue": "^4.1.0", - "astro": "^4.6.3", - "vue": "^3.3.8" + "@astrojs/vue": "^4.2.0", + "astro": "^4.8.6", + "vue": "^3.4.27" } } diff --git a/examples/hackernews/package.json b/examples/hackernews/package.json index a7ea4297ae75..cbcc5093b969 100644 --- a/examples/hackernews/package.json +++ b/examples/hackernews/package.json @@ -12,6 +12,6 @@ }, "dependencies": { "@astrojs/node": "^8.2.5", - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/hackernews/src/lib/api.ts b/examples/hackernews/src/lib/api.ts index 61fc2f9abc0f..49fd0c333a7f 100644 --- a/examples/hackernews/src/lib/api.ts +++ b/examples/hackernews/src/lib/api.ts @@ -14,7 +14,7 @@ export default async function fetchAPI(path: string) { } return JSON.parse(text); } catch (e) { - console.error(`Recevied from API: ${text}`); + console.error(`Received from API: ${text}`); console.error(e); return { error: e }; } diff --git a/examples/integration/package.json b/examples/integration/package.json index 7121e8c347b5..b1d157aefaaa 100644 --- a/examples/integration/package.json +++ b/examples/integration/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" }, "peerDependencies": { "astro": "^4.0.0" diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 1d84d858045d..b10daa77c4d1 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@astrojs/node": "^8.2.5", - "astro": "^4.6.3", + "astro": "^4.8.6", "html-minifier": "^4.0.0" }, "devDependencies": { diff --git a/examples/minimal/package.json b/examples/minimal/package.json index 8b3a8dfedbc4..1b9705a54a57 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/non-html-pages/package.json b/examples/non-html-pages/package.json index 884f8d7591af..2b61430ddbeb 100644 --- a/examples/non-html-pages/package.json +++ b/examples/non-html-pages/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/portfolio/package.json b/examples/portfolio/package.json index 3af8adde6a83..6a6dde857797 100644 --- a/examples/portfolio/package.json +++ b/examples/portfolio/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/ssr/package.json b/examples/ssr/package.json index 8ebd90fd163b..389d994bd86b 100644 --- a/examples/ssr/package.json +++ b/examples/ssr/package.json @@ -14,7 +14,7 @@ "dependencies": { "@astrojs/node": "^8.2.5", "@astrojs/svelte": "^5.4.0", - "astro": "^4.6.3", - "svelte": "^4.2.5" + "astro": "^4.8.6", + "svelte": "^4.2.16" } } diff --git a/examples/starlog/package.json b/examples/starlog/package.json index 0778ec8f8820..6649418f8d53 100644 --- a/examples/starlog/package.json +++ b/examples/starlog/package.json @@ -10,8 +10,8 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3", - "sass": "^1.69.5", - "sharp": "^0.32.6" + "astro": "^4.8.6", + "sass": "^1.77.1", + "sharp": "^0.33.3" } } diff --git a/examples/toolbar-app/.codesandbox/Dockerfile b/examples/toolbar-app/.codesandbox/Dockerfile new file mode 100644 index 000000000000..c3b5c81a121d --- /dev/null +++ b/examples/toolbar-app/.codesandbox/Dockerfile @@ -0,0 +1 @@ +FROM node:18-bullseye diff --git a/examples/toolbar-app/.gitignore b/examples/toolbar-app/.gitignore new file mode 100644 index 000000000000..abe03335e7bd --- /dev/null +++ b/examples/toolbar-app/.gitignore @@ -0,0 +1,21 @@ +# dependencies +node_modules/ + +# production build +dist + +# logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# environment variables +.env +.env.production + +# macOS-specific files +.DS_Store + +# jetbrains setting folder +.idea/ diff --git a/examples/toolbar-app/README.md b/examples/toolbar-app/README.md new file mode 100644 index 000000000000..8b879a01e54a --- /dev/null +++ b/examples/toolbar-app/README.md @@ -0,0 +1,40 @@ +# Astro Starter Kit: Toolbar App + +```sh +npm create astro@latest -- --template toolbar-app +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/toolbar-app) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/toolbar-app) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/toolbar-app/devcontainer.json) + +> πŸ§‘β€πŸš€ **Seasoned astronaut?** Delete this file. Have fun! + +## πŸš€ Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +```text +/ +β”œβ”€β”€ app.ts +β”œβ”€β”€ integration.ts +└── package.json +``` + +The logic of your app is in the appropriately named `app.ts` file. This is where the vast majority of your toolbar app logic will live. + +The `integration.ts` file is a simple Astro integration file that will be used to add your app into the toolbar. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :-------------- | :------------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Watch for changes and build your app automatically | +| `npm run build` | Build your app to `./dist/` | + +## πŸ‘€ Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/examples/toolbar-app/package.json b/examples/toolbar-app/package.json new file mode 100644 index 000000000000..9bde535a9fcb --- /dev/null +++ b/examples/toolbar-app/package.json @@ -0,0 +1,20 @@ +{ + "name": "@example/toolbar-app", + "type": "module", + "version": "0.0.1", + "peerDependencies": { + "astro": "^4.6.1" + }, + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "prepublish": "npm run build" + }, + "exports": { + ".": "./dist/integration.js", + "./app": "./dist/app.js" + }, + "devDependencies": { + "astro": "^4.8.6" + } +} diff --git a/examples/toolbar-app/src/app.ts b/examples/toolbar-app/src/app.ts new file mode 100644 index 000000000000..72bd4772d7ed --- /dev/null +++ b/examples/toolbar-app/src/app.ts @@ -0,0 +1,16 @@ +import { defineToolbarApp } from 'astro/toolbar'; + +// Guide: https://docs.astro.build/en/recipes/making-toolbar-apps/ +// API Reference: https://docs.astro.build/en/reference/dev-toolbar-app-reference/ +export default defineToolbarApp({ + init(canvas) { + const astroWindow = document.createElement('astro-dev-toolbar-window'); + + const text = document.createElement('p'); + text.textContent = 'Hello, Astro!'; + + astroWindow.append(text); + + canvas.append(astroWindow); + }, +}); diff --git a/examples/toolbar-app/src/integration.ts b/examples/toolbar-app/src/integration.ts new file mode 100644 index 000000000000..81597cf6eed8 --- /dev/null +++ b/examples/toolbar-app/src/integration.ts @@ -0,0 +1,17 @@ +import { fileURLToPath } from 'node:url'; +import type { AstroIntegration } from 'astro'; + +// API Reference: https://docs.astro.build/en/reference/integrations-reference/ +export default { + name: 'my-astro-integration', + hooks: { + 'astro:config:setup': ({ addDevToolbarApp }) => { + addDevToolbarApp({ + id: "my-toolbar-app", + name: "My Toolbar App", + icon: "πŸš€", + entrypoint: fileURLToPath(new URL('./app.js', import.meta.url)) + }); + }, + }, +} satisfies AstroIntegration; diff --git a/examples/toolbar-app/tsconfig.json b/examples/toolbar-app/tsconfig.json new file mode 100644 index 000000000000..b3e754ea04d9 --- /dev/null +++ b/examples/toolbar-app/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "astro/tsconfigs/base", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + } +} diff --git a/examples/view-transitions/package.json b/examples/view-transitions/package.json index 61865cdee016..fdce88640ef4 100644 --- a/examples/view-transitions/package.json +++ b/examples/view-transitions/package.json @@ -12,6 +12,6 @@ "devDependencies": { "@astrojs/tailwind": "^5.1.0", "@astrojs/node": "^8.2.5", - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/view-transitions/src/scripts/spa-navigation.js b/examples/view-transitions/src/scripts/spa-navigation.js index ceaf3a955cb2..bb96bce7b0c9 100644 --- a/examples/view-transitions/src/scripts/spa-navigation.js +++ b/examples/view-transitions/src/scripts/spa-navigation.js @@ -8,7 +8,7 @@ import { } from './utils'; // View Transitions support cross-document navigations. -// Should compare performace. +// Should compare performance. // https://github.com/WICG/view-transitions/blob/main/explainer.md#cross-document-same-origin-transitions // https://github.com/WICG/view-transitions/blob/main/explainer.md#script-events function shouldDisableSpa() { diff --git a/examples/with-markdoc/package.json b/examples/with-markdoc/package.json index 085a5b1b9305..363cd09f3f22 100644 --- a/examples/with-markdoc/package.json +++ b/examples/with-markdoc/package.json @@ -11,7 +11,7 @@ "astro": "astro" }, "dependencies": { - "@astrojs/markdoc": "^0.10.0", - "astro": "^4.6.3" + "@astrojs/markdoc": "^0.11.0", + "astro": "^4.8.6" } } diff --git a/examples/with-markdown-plugins/package.json b/examples/with-markdown-plugins/package.json index 095b2e5d69c2..361841cf2a08 100644 --- a/examples/with-markdown-plugins/package.json +++ b/examples/with-markdown-plugins/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/markdown-remark": "^5.1.0", - "astro": "^4.6.3", + "astro": "^4.8.6", "hast-util-select": "^6.0.2", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", diff --git a/examples/with-markdown-shiki/package.json b/examples/with-markdown-shiki/package.json index e06edaee9fe8..e60779b73a9b 100644 --- a/examples/with-markdown-shiki/package.json +++ b/examples/with-markdown-shiki/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.6.3" + "astro": "^4.8.6" } } diff --git a/examples/with-mdx/package.json b/examples/with-mdx/package.json index 056c1ad1aa7f..710e16284178 100644 --- a/examples/with-mdx/package.json +++ b/examples/with-mdx/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.3.1", - "@astrojs/preact": "^3.2.0", - "astro": "^4.6.3", - "preact": "^10.19.2" + "@astrojs/mdx": "^3.0.0", + "@astrojs/preact": "^3.3.0", + "astro": "^4.8.6", + "preact": "^10.21.0" } } diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json index 4c3093f01df0..f722f5dd4d30 100644 --- a/examples/with-nanostores/package.json +++ b/examples/with-nanostores/package.json @@ -11,10 +11,10 @@ "astro": "astro" }, "dependencies": { - "@astrojs/preact": "^3.2.0", - "@nanostores/preact": "^0.5.0", - "astro": "^4.6.3", - "nanostores": "^0.9.5", - "preact": "^10.19.2" + "@astrojs/preact": "^3.3.0", + "@nanostores/preact": "^0.5.1", + "astro": "^4.8.6", + "nanostores": "^0.10.3", + "preact": "^10.21.0" } } diff --git a/examples/with-nanostores/src/components/FigurineDescription.astro b/examples/with-nanostores/src/components/FigurineDescription.astro index d99481258793..1294b1510039 100644 --- a/examples/with-nanostores/src/components/FigurineDescription.astro +++ b/examples/with-nanostores/src/components/FigurineDescription.astro @@ -5,7 +5,7 @@ fully-poseable action figurine comes equipped with:

diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json index b0322860f62f..2e2bdeac1a28 100644 --- a/examples/with-tailwindcss/package.json +++ b/examples/with-tailwindcss/package.json @@ -11,13 +11,13 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.3.1", + "@astrojs/mdx": "^3.0.0", "@astrojs/tailwind": "^5.1.0", - "@types/canvas-confetti": "^1.6.3", - "astro": "^4.6.3", - "autoprefixer": "^10.4.15", - "canvas-confetti": "^1.9.1", - "postcss": "^8.4.28", - "tailwindcss": "^3.3.5" + "@types/canvas-confetti": "^1.6.4", + "astro": "^4.8.6", + "autoprefixer": "^10.4.19", + "canvas-confetti": "^1.9.3", + "postcss": "^8.4.38", + "tailwindcss": "^3.4.3" } } diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json index 989f1a301a27..e0e285794cd6 100644 --- a/examples/with-vitest/package.json +++ b/examples/with-vitest/package.json @@ -12,7 +12,7 @@ "test": "vitest" }, "dependencies": { - "astro": "^4.6.3", - "vitest": "^1.5.0" + "astro": "^4.8.6", + "vitest": "^1.6.0" } } diff --git a/package.json b/package.json index 9443b3e62359..75fbad30ddac 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,8 @@ "test:smoke:docs": "turbo run build --filter=docs", "test:check-examples": "node ./scripts/smoke/check.js", "test:vite-ci": "turbo run test --filter=astro", - "test:e2e": "cd packages/astro && pnpm playwright install chromium && pnpm run test:e2e", - "test:e2e:match": "cd packages/astro && pnpm playwright install chromium && pnpm run test:e2e:match", + "test:e2e": "cd packages/astro && pnpm playwright install chromium firefox && pnpm run test:e2e", + "test:e2e:match": "cd packages/astro && pnpm playwright install chromium firefox && pnpm run test:e2e:match", "test:e2e:hosts": "turbo run test:hosted", "benchmark": "astro-benchmark", "lint": "eslint . --report-unused-disable-directives", @@ -52,17 +52,15 @@ "astro-benchmark": "workspace:*" }, "devDependencies": { - "@astrojs/check": "^0.5.10", - "@biomejs/biome": "1.6.4", + "@astrojs/check": "^0.6.0", + "@biomejs/biome": "1.7.1", "@changesets/changelog-github": "^0.5.0", "@changesets/cli": "^2.27.1", "@eslint/eslintrc": "^3.0.2", "@types/node": "^18.17.8", - "esbuild": "^0.20.2", - "eslint": "^9.1.0", - "eslint-config-prettier": "^9.1.0", + "esbuild": "^0.21.2", + "eslint": "^9.2.0", "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-regexp": "^2.5.0", "globby": "^14.0.1", "only-allow": "^1.2.1", @@ -70,9 +68,9 @@ "prettier": "^3.2.5", "prettier-plugin-astro": "^0.13.0", "tiny-glob": "^0.2.9", - "turbo": "^1.13.2", + "turbo": "^1.13.3", "typescript": "~5.4.5", - "typescript-eslint": "^7.7.0" + "typescript-eslint": "^7.8.0" }, "pnpm": { "packageExtensions": { diff --git a/packages/astro-prism/package.json b/packages/astro-prism/package.json index 0a10a764e146..94a4be348de5 100644 --- a/packages/astro-prism/package.json +++ b/packages/astro-prism/package.json @@ -35,7 +35,7 @@ "prismjs": "^1.29.0" }, "devDependencies": { - "@types/prismjs": "1.26.3", + "@types/prismjs": "1.26.4", "astro-scripts": "workspace:*" }, "engines": { diff --git a/packages/astro-rss/CHANGELOG.md b/packages/astro-rss/CHANGELOG.md index 9a02f7b9241a..7d715a523d74 100644 --- a/packages/astro-rss/CHANGELOG.md +++ b/packages/astro-rss/CHANGELOG.md @@ -1,5 +1,11 @@ # @astrojs/rss +## 4.0.6 + +### Patch Changes + +- [#11050](https://github.com/withastro/astro/pull/11050) [`841df1f`](https://github.com/withastro/astro/commit/841df1f1b192f39849509cda49b7243940cc30f9) Thanks [@mingjunlu](https://github.com/mingjunlu)! - Fixes an issue where trailing slash is not removed even if the `trailingSlash` option is set to `false`. + ## 4.0.5 ### Patch Changes diff --git a/packages/astro-rss/package.json b/packages/astro-rss/package.json index 0a85f99c6140..d18cc707ea12 100644 --- a/packages/astro-rss/package.json +++ b/packages/astro-rss/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/rss", "description": "Add RSS feeds to your Astro projects", - "version": "4.0.5", + "version": "4.0.6", "type": "module", "types": "./dist/index.d.ts", "author": "withastro", diff --git a/packages/astro-rss/src/index.ts b/packages/astro-rss/src/index.ts index b3e0253d2ce7..f2cb37c86bc9 100644 --- a/packages/astro-rss/src/index.ts +++ b/packages/astro-rss/src/index.ts @@ -202,7 +202,7 @@ async function generateRSS(rssOptions: ValidatedRSSOptions): Promise { root.rss.channel = { title: rssOptions.title, description: rssOptions.description, - link: createCanonicalURL(site, rssOptions.trailingSlash, undefined).href, + link: createCanonicalURL(site, rssOptions.trailingSlash, undefined), }; if (typeof rssOptions.customData === 'string') Object.assign( @@ -220,7 +220,7 @@ async function generateRSS(rssOptions: ValidatedRSSOptions): Promise { // If the item's link is already a valid URL, don't mess with it. const itemLink = isValidURL(result.link) ? result.link - : createCanonicalURL(result.link, rssOptions.trailingSlash, site).href; + : createCanonicalURL(result.link, rssOptions.trailingSlash, site); item.link = itemLink; item.guid = { '#text': itemLink, '@_isPermaLink': 'true' }; } @@ -246,7 +246,7 @@ async function generateRSS(rssOptions: ValidatedRSSOptions): Promise { if (typeof result.commentsUrl === 'string') { item.comments = isValidURL(result.commentsUrl) ? result.commentsUrl - : createCanonicalURL(result.commentsUrl, rssOptions.trailingSlash, site).href; + : createCanonicalURL(result.commentsUrl, rssOptions.trailingSlash, site); } if (result.source) { item.source = parser.parse( @@ -256,7 +256,7 @@ async function generateRSS(rssOptions: ValidatedRSSOptions): Promise { if (result.enclosure) { const enclosureURL = isValidURL(result.enclosure.url) ? result.enclosure.url - : createCanonicalURL(result.enclosure.url, rssOptions.trailingSlash, site).href; + : createCanonicalURL(result.enclosure.url, rssOptions.trailingSlash, site); item.enclosure = parser.parse( `` ).enclosure; diff --git a/packages/astro-rss/src/util.ts b/packages/astro-rss/src/util.ts index 1e49b3d77521..16db5b587191 100644 --- a/packages/astro-rss/src/util.ts +++ b/packages/astro-rss/src/util.ts @@ -6,18 +6,21 @@ export function createCanonicalURL( url: string, trailingSlash?: RSSOptions['trailingSlash'], base?: string -): URL { +): string { let pathname = url.replace(/\/index.html$/, ''); // index.html is not canonical - if (trailingSlash === false) { - // remove the trailing slash - pathname = pathname.replace(/\/*$/, ''); - } else if (!getUrlExtension(url)) { + if (!getUrlExtension(url)) { // add trailing slash if there’s no extension or `trailingSlash` is true pathname = pathname.replace(/\/*$/, '/'); } pathname = pathname.replace(/\/+/g, '/'); // remove duplicate slashes (URL() won’t) - return new URL(pathname, base); + + const canonicalUrl = new URL(pathname, base).href; + if (trailingSlash === false) { + // remove the trailing slash + return canonicalUrl.replace(/\/*$/, ''); + } + return canonicalUrl; } /** Check if a URL is already valid */ diff --git a/packages/astro-rss/test/rss.test.js b/packages/astro-rss/test/rss.test.js index 764cc1301b32..547b75b4e634 100644 --- a/packages/astro-rss/test/rss.test.js +++ b/packages/astro-rss/test/rss.test.js @@ -176,7 +176,7 @@ describe('getRssString', () => { trailingSlash: false, }); - assert.ok(str.includes('https://example.com/<')); + assert.ok(str.includes('https://example.com<')); assert.ok(str.includes('https://example.com/php<')); }); diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md index 2cf022a65824..f111e97e018c 100644 --- a/packages/astro/CHANGELOG.md +++ b/packages/astro/CHANGELOG.md @@ -1,5 +1,372 @@ # astro +## 4.8.6 + +### Patch Changes + +- [#11084](https://github.com/withastro/astro/pull/11084) [`9637014`](https://github.com/withastro/astro/commit/9637014b1495a5a41cb384c7de4de410348f4cc0) Thanks [@bluwy](https://github.com/bluwy)! - Fixes regression when handling hoisted scripts from content collections + +## 4.8.5 + +### Patch Changes + +- [#11065](https://github.com/withastro/astro/pull/11065) [`1f988ed`](https://github.com/withastro/astro/commit/1f988ed10f4737b5333c9978115ee531786eb539) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a bug in the Astro rewrite logic, where rewriting the index with parameters - `next("/?foo=bar")` - didn't work as expected. + +- [#10924](https://github.com/withastro/astro/pull/10924) [`3a0c02a`](https://github.com/withastro/astro/commit/3a0c02ae0357c267881b30454b5320075378894b) Thanks [@Its-Just-Nans](https://github.com/Its-Just-Nans)! - Handle image-size errors by displaying a clearer message + +- [#11058](https://github.com/withastro/astro/pull/11058) [`749a7ac`](https://github.com/withastro/astro/commit/749a7ac967146952450a4173dcb6a5494755460c) Thanks [@matthewp](https://github.com/matthewp)! - Fix streaming in Node.js fast path + +- [#11052](https://github.com/withastro/astro/pull/11052) [`a05ca38`](https://github.com/withastro/astro/commit/a05ca38c2cf327ae9130ee1c139a0e510b9da50a) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Fixes a case where rewriting would conflict with the actions internal middleware + +- [#11062](https://github.com/withastro/astro/pull/11062) [`16f12e4`](https://github.com/withastro/astro/commit/16f12e426e5869721313bb771e2ec5b821c5452e) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a bug where `astro build` didn't create custom `404.html` and `500.html` when a certain combination of i18n options was applied + +- [#10965](https://github.com/withastro/astro/pull/10965) [`a8f0372`](https://github.com/withastro/astro/commit/a8f0372ea71479ef80c58e74201dea6a5a2b2ae4) Thanks [@Elias-Chairi](https://github.com/Elias-Chairi)! - Update generator.ts to allow %23 (#) in dynamic urls + +- [#11069](https://github.com/withastro/astro/pull/11069) [`240a70a`](https://github.com/withastro/astro/commit/240a70a29f8e11d161da021845c208f982d64e5c) Thanks [@ematipico](https://github.com/ematipico)! - Improves debug logging for on-demand pages + +## 4.8.4 + +### Patch Changes + +- [#11026](https://github.com/withastro/astro/pull/11026) [`8dfb1a2`](https://github.com/withastro/astro/commit/8dfb1a23cc5996c410f7e33211d132dac36c9f77) Thanks [@bluwy](https://github.com/bluwy)! - Skips rendering script tags if it's inlined and empty when `experimental.directRenderScript` is enabled + +- [#11043](https://github.com/withastro/astro/pull/11043) [`d0d1710`](https://github.com/withastro/astro/commit/d0d1710439ec281518b17d03126b5d9cd008a102) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fixes minor type issues in actions component example + +- [#10999](https://github.com/withastro/astro/pull/10999) [`5f353e3`](https://github.com/withastro/astro/commit/5f353e39b2b9fb15e6c9d193b5b5101457fef002) Thanks [@bluwy](https://github.com/bluwy)! - The prefetch feature is updated to better support different browsers and different cache headers setup, including: + + 1. All prefetch strategies will now always try to use `` if supported, or will fall back to `fetch()`. + 2. The `prefetch()` programmatic API's `with` option is deprecated in favour of an automatic approach that will also try to use `` element in the `` component so scoped styling can be applied to the `` element + +## 4.8.0 + +### Minor Changes + +- [#10935](https://github.com/withastro/astro/pull/10935) [`ddd8e49`](https://github.com/withastro/astro/commit/ddd8e49d1a179bec82310fb471f822a1567a6610) Thanks [@bluwy](https://github.com/bluwy)! - Exports `astro/jsx/rehype.js` with utilities to generate an Astro metadata object + +- [#10625](https://github.com/withastro/astro/pull/10625) [`698c2d9`](https://github.com/withastro/astro/commit/698c2d9bb51e20b38de405b6076fd6488ddb5c2b) Thanks [@goulvenclech](https://github.com/goulvenclech)! - Adds the ability for multiple pages to use the same component as an `entrypoint` when building an Astro integration. This change is purely internal, and aligns the build process with the behaviour in the development server. + +- [#10906](https://github.com/withastro/astro/pull/10906) [`7bbd664`](https://github.com/withastro/astro/commit/7bbd66459dd29a338ac1dfae0e4c984cb08f73b3) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds a new radio checkbox component to the dev toolbar UI library (`astro-dev-toolbar-radio-checkbox`) + +- [#10963](https://github.com/withastro/astro/pull/10963) [`61f47a6`](https://github.com/withastro/astro/commit/61f47a684235a049cbfc4f2cbb5edff3befeced7) Thanks [@delucis](https://github.com/delucis)! - Adds support for passing an inline Astro configuration object to `getViteConfig()` + + If you are using `getViteConfig()` to configure the Vitest test runner, you can now pass a second argument to control how Astro is configured. This makes it possible to configure unit tests with different Astro options when using [Vitest’s workspaces](https://vitest.dev/guide/workspace.html) feature. + + ```js + // vitest.config.ts + import { getViteConfig } from 'astro/config'; + + export default getViteConfig( + /* Vite configuration */ + { test: {} }, + /* Astro configuration */ + { + site: 'https://example.com', + trailingSlash: 'never', + } + ); + ``` + +- [#10867](https://github.com/withastro/astro/pull/10867) [`47877a7`](https://github.com/withastro/astro/commit/47877a75404ccc8786bbea2171015fb088dc01a1) Thanks [@ematipico](https://github.com/ematipico)! - Adds experimental rewriting in Astro with a new `rewrite()` function and the middleware `next()` function. + + The feature is available via an experimental flag in `astro.config.mjs`: + + ```js + export default defineConfig({ + experimental: { + rewriting: true, + }, + }); + ``` + + When enabled, you can use `rewrite()` to **render** another page without changing the URL of the browser in Astro pages and endpoints. + + ```astro + --- + // src/pages/dashboard.astro + if (!Astro.props.allowed) { + return Astro.rewrite('/'); + } + --- + ``` + + ```js + // src/pages/api.js + export function GET(ctx) { + if (!ctx.locals.allowed) { + return ctx.rewrite('/'); + } + } + ``` + + The middleware `next()` function now accepts a parameter with the same type as the `rewrite()` function. For example, with `next("/")`, you can call the next middleware function with a new `Request`. + + ```js + // src/middleware.js + export function onRequest(ctx, next) { + if (!ctx.cookies.get('allowed')) { + return next('/'); // new signature + } + return next(); + } + ``` + + > **NOTE**: please [read the RFC](https://github.com/withastro/roadmap/blob/feat/reroute/proposals/0047-rerouting.md) to understand the current expectations of the new APIs. + +- [#10858](https://github.com/withastro/astro/pull/10858) [`c0c509b`](https://github.com/withastro/astro/commit/c0c509b6bf3f55562d22297fdcc2b3e57969734d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Adds experimental support for the Actions API. Actions let you define type-safe endpoints you can query from client components with progressive enhancement built in. + + 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. These accept 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(), + + 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: + + ```tsx "actions" + // src/components/blog.tsx + import { actions } from 'astro:actions'; + import { useState } from 'preact/hooks'; + + export function Like({ postId }: { postId: string }) { + const [likes, setLikes] = useState(0); + return ( + + ); + } + + export function Comment({ postId }: { postId: string }) { + return ( +
{ + e.preventDefault(); + const formData = new FormData(e.target); + const result = await actions.blog.comment(formData); + // handle result + }} + > + + + + + +
+ ); + } + ``` + + 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). + +- [#10906](https://github.com/withastro/astro/pull/10906) [`7bbd664`](https://github.com/withastro/astro/commit/7bbd66459dd29a338ac1dfae0e4c984cb08f73b3) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds a new `buttonBorderRadius` property to the `astro-dev-toolbar-button` component for the dev toolbar component library. This property can be useful to make a fully rounded button with an icon in the center. + +### Patch Changes + +- [#10977](https://github.com/withastro/astro/pull/10977) [`59571e8`](https://github.com/withastro/astro/commit/59571e8812ec637f5ea61be6c6adc0f45212d176) Thanks [@BryceRussell](https://github.com/BryceRussell)! - Improve error message when accessing `clientAddress` on prerendered routes + +- [#10935](https://github.com/withastro/astro/pull/10935) [`ddd8e49`](https://github.com/withastro/astro/commit/ddd8e49d1a179bec82310fb471f822a1567a6610) Thanks [@bluwy](https://github.com/bluwy)! - Improves the error message when failed to render MDX components + +- [#10917](https://github.com/withastro/astro/pull/10917) [`3412535`](https://github.com/withastro/astro/commit/3412535be4a0ec94cea18c5d186b7ffbd6f8209c) Thanks [@jakobhellermann](https://github.com/jakobhellermann)! - Fixes a case where the local server would crash when the host also contained the port, eg. with `X-Forwarded-Host: hostname:8080` and `X-Forwarded-Port: 8080` headers + +- [#10959](https://github.com/withastro/astro/pull/10959) [`685fc22`](https://github.com/withastro/astro/commit/685fc22bc6247be69a34c3f6945dec058c19fd71) Thanks [@bluwy](https://github.com/bluwy)! - Refactors internal handling of styles and scripts for content collections to improve build performance + +- [#10889](https://github.com/withastro/astro/pull/10889) [`4d905cc`](https://github.com/withastro/astro/commit/4d905ccef663f728fc981181f5bb9f1d157184ff) Thanks [@matthewp](https://github.com/matthewp)! - Preserve content modules properly in cache + +- [#10955](https://github.com/withastro/astro/pull/10955) [`2978287`](https://github.com/withastro/astro/commit/2978287f92dbd135f5c3efc6a037ea1756064d35) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Handles `AstroUserError`s thrown while syncing content collections and exports `BaseSchema` and `CollectionConfig` types + +## 4.7.1 + +### Patch Changes + +- [#10911](https://github.com/withastro/astro/pull/10911) [`a86dc9d`](https://github.com/withastro/astro/commit/a86dc9d269fc4409c458cfa05dcfaeee12bade2f) Thanks [@bluwy](https://github.com/bluwy)! - Skips adding CSS dependencies of CSS Vite modules as style tags in the HTML + +- [#10900](https://github.com/withastro/astro/pull/10900) [`36bb3b6`](https://github.com/withastro/astro/commit/36bb3b6025eb51f6e027a76a514cc7ebb29deb10) Thanks [@martrapp](https://github.com/martrapp)! - Detects overlapping navigation and view transitions and automatically aborts all but the most recent one. + +- [#10933](https://github.com/withastro/astro/pull/10933) [`007d17f`](https://github.com/withastro/astro/commit/007d17fee072955d4acb846a06d9eb666e908ef6) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes `app.toggleState` not working correctly + +- [#10931](https://github.com/withastro/astro/pull/10931) [`4ce5ced`](https://github.com/withastro/astro/commit/4ce5ced44d490f4c6df771995aef14e11910ec57) Thanks [@ktym4a](https://github.com/ktym4a)! - Fixes `toggleNotification()`'s parameter type for the notification level not using the proper levels + +## 4.7.0 + +### Minor Changes + +- [#10665](https://github.com/withastro/astro/pull/10665) [`7b4f284`](https://github.com/withastro/astro/commit/7b4f2840203fe220758934f1366485f788727f0d) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds new utilities to ease the creation of toolbar apps including `defineToolbarApp` to make it easier to define your toolbar app and `app` and `server` helpers for easier communication between the toolbar and the server. These new utilities abstract away some of the boilerplate code that is common in toolbar apps, and lower the barrier of entry for app authors. + + For example, instead of creating an event listener for the `app-toggled` event and manually typing the value in the callback, you can now use the `onAppToggled` method. Additionally, communicating with the server does not require knowing any of the Vite APIs anymore, as a new `server` object is passed to the `init` function that contains easy to use methods for communicating with the server. + + ```diff + import { defineToolbarApp } from "astro/toolbar"; + + export default defineToolbarApp({ + init(canvas, app, server) { + + - app.addEventListener("app-toggled", (e) => { + - console.log(`App is now ${state ? "enabled" : "disabled"}`);. + - }); + + + app.onToggled(({ state }) => { + + console.log(`App is now ${state ? "enabled" : "disabled"}`); + + }); + + - if (import.meta.hot) { + - import.meta.hot.send("my-app:my-client-event", { message: "world" }); + - } + + + server.send("my-app:my-client-event", { message: "world" }) + + - if (import.meta.hot) { + - import.meta.hot.on("my-server-event", (data: {message: string}) => { + - console.log(data.message); + - }); + - } + + + server.on<{ message: string }>("my-server-event", (data) => { + + console.log(data.message); // data is typed using the type parameter + + }); + }, + }) + ``` + + Server helpers are also available on the server side, for use in your integrations, through the new `toolbar` object: + + ```ts + "astro:server:setup": ({ toolbar }) => { + toolbar.on<{ message: string }>("my-app:my-client-event", (data) => { + console.log(data.message); + toolbar.send("my-server-event", { message: "hello" }); + }); + } + ``` + + This is a backwards compatible change and your your existing dev toolbar apps will continue to function. However, we encourage you to build your apps with the new helpers, following the [updated Dev Toolbar API documentation](https://docs.astro.build/en/reference/dev-toolbar-app-reference/). + +- [#10734](https://github.com/withastro/astro/pull/10734) [`6fc4c0e`](https://github.com/withastro/astro/commit/6fc4c0e420da7629b4cfc28ee7efce1d614447be) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Astro will now automatically check for updates when you run the dev server. If a new version is available, a message will appear in the terminal with instructions on how to update. Updates will be checked once per 10 days, and the message will only appear if the project is multiple versions behind the latest release. + + This behavior can be disabled by running `astro preferences disable checkUpdates` or setting the `ASTRO_DISABLE_UPDATE_CHECK` environment variable to `false`. + +- [#10762](https://github.com/withastro/astro/pull/10762) [`43ead8f`](https://github.com/withastro/astro/commit/43ead8fbd5112823118060175c7a4a22522cc325) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Enables type checking for JavaScript files when using the `strictest` TS config. This ensures consistency with Astro's other TS configs, and fixes type checking for integrations like Astro DB when using an `astro.config.mjs`. + + If you are currently using the `strictest` preset and would like to still disable `.js` files, set `allowJS: false` in your `tsconfig.json`. + +### Patch Changes + +- [#10861](https://github.com/withastro/astro/pull/10861) [`b673bc8`](https://github.com/withastro/astro/commit/b673bc850593d5af25793d0358c00797477fa373) Thanks [@mingjunlu](https://github.com/mingjunlu)! - Fixes an issue where `astro build` writes type declaration files to `outDir` when it's outside of root directory. + +- [#10684](https://github.com/withastro/astro/pull/10684) [`8b59d5d`](https://github.com/withastro/astro/commit/8b59d5d078ff40576b8cbee432279c6ad044a1a9) Thanks [@PeterDraex](https://github.com/PeterDraex)! - Update sharp to 0.33 to fix issue with Alpine Linux + +## 4.6.4 + +### Patch Changes + +- [#10846](https://github.com/withastro/astro/pull/10846) [`3294f7a`](https://github.com/withastro/astro/commit/3294f7a343e036d2ad9ac8d5f792ad0d4f43a399) Thanks [@matthewp](https://github.com/matthewp)! - Prevent getCollection breaking in vitest + +- [#10856](https://github.com/withastro/astro/pull/10856) [`30cf82a`](https://github.com/withastro/astro/commit/30cf82ac3e970a6a3c0f07db1340dd7152d1c35d) Thanks [@robertvanhoesel](https://github.com/robertvanhoesel)! - Prevents inputs with a name attribute of action or method to break ViewTransitions' form submission + +- [#10833](https://github.com/withastro/astro/pull/10833) [`8d5f3e8`](https://github.com/withastro/astro/commit/8d5f3e8656027023f9fda51c66b0213ffe16d3a5) Thanks [@renovate](https://github.com/apps/renovate)! - Updates `esbuild` dependency to v0.20. This should not affect projects in most cases. + +- [#10801](https://github.com/withastro/astro/pull/10801) [`204b782`](https://github.com/withastro/astro/commit/204b7820e6de22d97fa2a7b988180c42155c8387) Thanks [@rishi-raj-jain](https://github.com/rishi-raj-jain)! - Fixes an issue where images in MD required a relative specifier (e.g. `./`) + + Now, you can use the standard `![](relative/img.png)` syntax in MD files for images colocated in the same folder: no relative specifier required! + + There is no need to update your project; your existing images will still continue to work. However, you may wish to remove any relative specifiers from these MD images as they are no longer necessary: + + ```diff + - ![A cute dog](./dog.jpg) + + ![A cute dog](dog.jpg) + + ``` + +- [#10841](https://github.com/withastro/astro/pull/10841) [`a2df344`](https://github.com/withastro/astro/commit/a2df344bff15647c2bfb3f49e3f7b66aa069d6f4) Thanks [@martrapp](https://github.com/martrapp)! - Due to regression on mobile WebKit browsers, reverts a change made for JavaScript animations during view transitions. + ## 4.6.3 ### Patch Changes diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts index 7c2846efc076..a20baa508611 100644 --- a/packages/astro/astro-jsx.d.ts +++ b/packages/astro/astro-jsx.d.ts @@ -22,7 +22,7 @@ declare namespace astroHTML.JSX { extends AstroBuiltinProps, AstroBuiltinAttributes, AstroClientDirectives { - slot?: string; + slot?: string | undefined | null; children?: Children; } @@ -605,6 +605,7 @@ declare namespace astroHTML.JSX { href?: string | URL | undefined | null; hreflang?: string | undefined | null; media?: string | undefined | null; + name?: string | undefined | null; ping?: string | undefined | null; rel?: string | undefined | null; target?: HTMLAttributeAnchorTarget | undefined | null; @@ -649,6 +650,7 @@ declare namespace astroHTML.JSX { type?: 'submit' | 'reset' | 'button' | undefined | null; value?: string | string[] | number | undefined | null; popovertarget?: string | undefined | null; + popovertargetaction?: 'hide' | 'show' | 'toggle' | undefined | null; } interface CanvasHTMLAttributes extends HTMLAttributes { @@ -815,6 +817,7 @@ declare namespace astroHTML.JSX { value?: string | string[] | number | undefined | null; width?: number | string | undefined | null; popovertarget?: string | undefined | null; + popovertargetaction?: 'hide' | 'show' | 'toggle' | undefined | null; } interface KeygenHTMLAttributes extends HTMLAttributes { diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index 9128e9dd0ce7..3083247cfc0f 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -1,5 +1,6 @@ /// /// +/// // eslint-disable-next-line @typescript-eslint/no-namespace declare namespace App { @@ -11,7 +12,7 @@ interface ImportMetaEnv { /** * The prefix for Astro-generated asset links if the build.assetsPrefix config option is set. This can be used to create asset links not handled by Astro. */ - readonly ASSETS_PREFIX: string; + readonly ASSETS_PREFIX: string | Record; /** * This is set to the site option specified in your project’s Astro config file. */ diff --git a/packages/astro/components/Picture.astro b/packages/astro/components/Picture.astro index 3984a53e96cb..1b4f67e5d2e8 100644 --- a/packages/astro/components/Picture.astro +++ b/packages/astro/components/Picture.astro @@ -27,6 +27,21 @@ if (props.alt === undefined || props.alt === null) { throw new AstroError(AstroErrorData.ImageMissingAlt); } +// Picture attribute inherit scoped styles from class and attributes +const scopedStyleClass = props.class?.match(/\bastro-\w{8}\b/)?.[0]; +if (scopedStyleClass) { + if (pictureAttributes.class) { + pictureAttributes.class = `${pictureAttributes.class} ${scopedStyleClass}`; + } else { + pictureAttributes.class = scopedStyleClass; + } +} +for (const key in props) { + if (key.startsWith('data-astro-cid')) { + pictureAttributes[key] = props[key]; + } +} + const originalSrc = await resolveSrc(props.src); const optimizedImages: GetImageResult[] = await Promise.all( formats.map( diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index c33d9a3f5f2f..84a68d61e6f9 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -108,9 +108,16 @@ const { fallback = 'animate' } = Astro.props; const form = el as HTMLFormElement; const submitter = ev.submitter; const formData = new FormData(form, submitter); + // form.action and form.method can point to an or + // in which case should fallback to the form attribute + const formAction = + typeof form.action === 'string' ? form.action : form.getAttribute('action'); + const formMethod = + typeof form.method === 'string' ? form.method : form.getAttribute('method'); // Use the form action, if defined, otherwise fallback to current path. - let action = submitter?.getAttribute('formaction') ?? form.action ?? location.pathname; - const method = submitter?.getAttribute('formmethod') ?? form.method; + let action = submitter?.getAttribute('formaction') ?? formAction ?? location.pathname; + // Use the form method, if defined, otherwise fallback to "get" + const method = submitter?.getAttribute('formmethod') ?? formMethod ?? 'get'; // the "dialog" method is a special keyword used within elements // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method diff --git a/packages/astro/config.d.ts b/packages/astro/config.d.ts index b859f0b055fc..47bf6ed61908 100644 --- a/packages/astro/config.d.ts +++ b/packages/astro/config.d.ts @@ -1,6 +1,7 @@ type ViteUserConfig = import('vite').UserConfig; type ViteUserConfigFn = import('vite').UserConfigFn; type AstroUserConfig = import('./dist/@types/astro.js').AstroUserConfig; +type AstroInlineConfig = import('./dist/@types/astro.js').AstroInlineConfig; type ImageServiceConfig = import('./dist/@types/astro.js').ImageServiceConfig; type SharpImageServiceConfig = import('./dist/assets/services/sharp.js').SharpImageServiceConfig; @@ -13,7 +14,10 @@ export function defineConfig(config: AstroUserConfig): AstroUserConfig; /** * Use Astro to generate a fully resolved Vite config */ -export function getViteConfig(config: ViteUserConfig): ViteUserConfigFn; +export function getViteConfig( + config: ViteUserConfig, + inlineAstroConfig?: AstroInlineConfig +): ViteUserConfigFn; /** * Return the configuration needed to use the Sharp-based image service diff --git a/packages/astro/content-module.template.mjs b/packages/astro/content-module.template.mjs index 35c6a55c9b2a..f246678a25ec 100644 --- a/packages/astro/content-module.template.mjs +++ b/packages/astro/content-module.template.mjs @@ -48,10 +48,12 @@ const collectionToRenderEntryMap = createCollectionToGlobResultMap({ contentDir, }); +const cacheEntriesByCollection = new Map(); export const getCollection = createGetCollection({ contentCollectionToEntryMap, dataCollectionToEntryMap, getRenderEntryImport: createGlobLookup(collectionToRenderEntryMap), + cacheEntriesByCollection, }); export const getEntryBySlug = createGetEntryBySlug({ diff --git a/packages/astro/e2e/actions-blog.test.js b/packages/astro/e2e/actions-blog.test.js new file mode 100644 index 000000000000..d7032dded51f --- /dev/null +++ b/packages/astro/e2e/actions-blog.test.js @@ -0,0 +1,112 @@ +import { expect } from '@playwright/test'; +import { testFactory } from './test-utils.js'; + +const test = testFactory({ root: './fixtures/actions-blog/' }); + +let devServer; + +test.beforeAll(async ({ astro }) => { + devServer = await astro.startDevServer(); +}); + +test.afterAll(async () => { + await devServer.stop(); +}); + +test.describe('Astro Actions - Blog', () => { + test('Like action', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/')); + + const likeButton = page.getByLabel('Like'); + await expect(likeButton, 'like button starts with 10 likes').toContainText('10'); + await likeButton.click(); + await expect(likeButton, 'like button should increment likes').toContainText('11'); + }); + + test('Comment action - validation error', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/')); + + const form = page.getByTestId('client'); + const authorInput = form.locator('input[name="author"]'); + const bodyInput = form.locator('textarea[name="body"]'); + + await authorInput.fill('Ben'); + await bodyInput.fill('Too short'); + + const submitButton = form.getByRole('button'); + await submitButton.click(); + + await expect(form.locator('p[data-error="body"]')).toBeVisible(); + }); + + test('Comment action - progressive fallback validation error', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/')); + + const form = page.getByTestId('progressive-fallback'); + const authorInput = form.locator('input[name="author"]'); + const bodyInput = form.locator('textarea[name="body"]'); + + await authorInput.fill('Ben'); + await bodyInput.fill('Too short'); + + const submitButton = form.getByRole('button'); + await submitButton.click(); + + await expect(form.locator('p[data-error="body"]')).toBeVisible(); + }); + + test('Comment action - progressive fallback success', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/')); + + const form = page.getByTestId('progressive-fallback'); + const authorInput = form.locator('input[name="author"]'); + const bodyInput = form.locator('textarea[name="body"]'); + + const body = 'Fallback - This should be long enough.'; + await authorInput.fill('Ben'); + await bodyInput.fill(body); + + const submitButton = form.getByRole('button'); + await submitButton.click(); + + const comments = page.getByTestId('server-comments'); + await expect(comments).toBeVisible(); + await expect(comments).toContainText(body); + }); + + test('Comment action - custom error', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/?commentPostIdOverride=bogus')); + + const form = page.getByTestId('client'); + const authorInput = form.locator('input[name="author"]'); + const bodyInput = form.locator('textarea[name="body"]'); + await authorInput.fill('Ben'); + await bodyInput.fill('This should be long enough.'); + + const submitButton = form.getByRole('button'); + await submitButton.click(); + + const unexpectedError = form.locator('p[data-error="unexpected"]'); + await expect(unexpectedError).toBeVisible(); + await expect(unexpectedError).toContainText('NOT_FOUND: Post not found'); + }); + + test('Comment action - success', async ({ page, astro }) => { + await page.goto(astro.resolveUrl('/blog/first-post/')); + + const form = page.getByTestId('client'); + const authorInput = form.locator('input[name="author"]'); + const bodyInput = form.locator('textarea[name="body"]'); + + const body = 'Client: This should be long enough.'; + await authorInput.fill('Ben'); + await bodyInput.fill(body); + + const submitButton = form.getByRole('button'); + await submitButton.click(); + + const comments = page.getByTestId('client-comments'); + await expect(comments).toBeVisible(); + await expect(comments).toContainText(body); + }); +}); diff --git a/packages/astro/e2e/dev-toolbar.test.js b/packages/astro/e2e/dev-toolbar.test.js index e7989b78befb..1002b2183046 100644 --- a/packages/astro/e2e/dev-toolbar.test.js +++ b/packages/astro/e2e/dev-toolbar.test.js @@ -146,7 +146,7 @@ test.describe('Dev Toolbar', () => { await expect(xrayWindow.locator('astro-dev-toolbar-icon[icon=lightbulb]')).toBeVisible(); }); - test('audit shows higlights and tooltips', async ({ page, astro }) => { + test('audit shows highlights and tooltips', async ({ page, astro }) => { await page.goto(astro.resolveUrl('/')); const toolbar = page.locator('astro-dev-toolbar'); @@ -304,6 +304,8 @@ test.describe('Dev Toolbar', () => { await expect(myAppWindow).toHaveCount(1); await expect(myAppWindow).toBeVisible(); + await expect(myAppWindow).toContainText('Hello from the server!'); + // Toggle app off await appButton.click(); await expect(myAppWindow).not.toBeVisible(); diff --git a/packages/astro/e2e/fixtures/actions-blog/astro.config.mjs b/packages/astro/e2e/fixtures/actions-blog/astro.config.mjs new file mode 100644 index 000000000000..acbed1768b3c --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/astro.config.mjs @@ -0,0 +1,17 @@ +import { defineConfig } from 'astro/config'; +import db from '@astrojs/db'; +import react from '@astrojs/react'; +import node from '@astrojs/node'; + +// https://astro.build/config +export default defineConfig({ + site: 'https://example.com', + integrations: [db(), react()], + output: 'hybrid', + adapter: node({ + mode: 'standalone', + }), + experimental: { + actions: true, + }, +}); diff --git a/packages/astro/e2e/fixtures/actions-blog/db/config.ts b/packages/astro/e2e/fixtures/actions-blog/db/config.ts new file mode 100644 index 000000000000..da005471e10c --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/db/config.ts @@ -0,0 +1,21 @@ +import { column, defineDb, defineTable } from "astro:db"; + +const Comment = defineTable({ + columns: { + postId: column.text(), + author: column.text(), + body: column.text(), + }, +}); + +const Likes = defineTable({ + columns: { + postId: column.text(), + likes: column.number(), + }, +}); + +// https://astro.build/db/config +export default defineDb({ + tables: { Comment, Likes }, +}); diff --git a/packages/astro/e2e/fixtures/actions-blog/db/seed.ts b/packages/astro/e2e/fixtures/actions-blog/db/seed.ts new file mode 100644 index 000000000000..11dc55f7fe00 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/db/seed.ts @@ -0,0 +1,15 @@ +import { db, Likes, Comment } from "astro:db"; + +// https://astro.build/db/seed +export default async function seed() { + await db.insert(Likes).values({ + postId: "first-post.md", + likes: 10, + }); + + await db.insert(Comment).values({ + postId: "first-post.md", + author: "Alice", + body: "Great post!", + }); +} diff --git a/packages/astro/e2e/fixtures/actions-blog/package.json b/packages/astro/e2e/fixtures/actions-blog/package.json new file mode 100644 index 000000000000..cf36f23266f5 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/package.json @@ -0,0 +1,24 @@ +{ + "name": "@e2e/astro-actions-basics", + "type": "module", + "version": "0.0.1", + "scripts": { + "dev": "astro dev", + "start": "astro dev", + "build": "astro check && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/check": "^0.6.0", + "@astrojs/db": "workspace:*", + "@astrojs/node": "workspace:*", + "@astrojs/react": "workspace:*", + "@types/react": "^18.3.2", + "@types/react-dom": "^18.3.0", + "astro": "workspace:*", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "typescript": "^5.4.5" + } +} diff --git a/packages/astro/e2e/fixtures/actions-blog/src/actions/index.ts b/packages/astro/e2e/fixtures/actions-blog/src/actions/index.ts new file mode 100644 index 000000000000..036cc087fdca --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/actions/index.ts @@ -0,0 +1,53 @@ +import { db, Comment, Likes, eq, sql } from 'astro:db'; +import { ActionError, defineAction, z } from 'astro:actions'; +import { getCollection } from 'astro:content'; + +export const server = { + blog: { + like: defineAction({ + input: z.object({ postId: z.string() }), + handler: async ({ postId }) => { + await new Promise((r) => setTimeout(r, 200)); + + const { likes } = await db + .update(Likes) + .set({ + likes: sql`likes + 1`, + }) + .where(eq(Likes.postId, postId)) + .returning() + .get(); + + return likes; + }, + }), + + comment: defineAction({ + accept: 'form', + input: z.object({ + postId: z.string(), + author: z.string(), + body: z.string().min(10), + }), + handler: async ({ postId, author, body }) => { + if (!(await getCollection('blog')).find(b => b.id === postId)) { + throw new ActionError({ + code: 'NOT_FOUND', + message: 'Post not found', + }); + } + + const comment = await db + .insert(Comment) + .values({ + postId, + body, + author, + }) + .returning() + .get(); + return comment; + }, + }), + }, +}; diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/BaseHead.astro b/packages/astro/e2e/fixtures/actions-blog/src/components/BaseHead.astro new file mode 100644 index 000000000000..5a2114003d5d --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/BaseHead.astro @@ -0,0 +1,43 @@ +--- +// Import the global.css file here so that it is included on +// all pages through the use of the component. +import '../styles/global.css'; + +interface Props { + title: string; + description: string; + image?: string; +} + +const canonicalURL = new URL(Astro.url.pathname, Astro.site); + +const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props; +--- + + + + + + + + + + + +{title} + + + + + + + + + + + + + + + + diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/Footer.astro b/packages/astro/e2e/fixtures/actions-blog/src/components/Footer.astro new file mode 100644 index 000000000000..96c2fce91208 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/Footer.astro @@ -0,0 +1,62 @@ +--- +const today = new Date(); +--- + + + diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/FormattedDate.astro b/packages/astro/e2e/fixtures/actions-blog/src/components/FormattedDate.astro new file mode 100644 index 000000000000..1bcce73a2b67 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/FormattedDate.astro @@ -0,0 +1,17 @@ +--- +interface Props { + date: Date; +} + +const { date } = Astro.props; +--- + + diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/Header.astro b/packages/astro/e2e/fixtures/actions-blog/src/components/Header.astro new file mode 100644 index 000000000000..71b8cdc55c58 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/Header.astro @@ -0,0 +1,83 @@ +--- +import HeaderLink from './HeaderLink.astro'; +import { SITE_TITLE } from '../consts'; +--- + +
+ +
+ diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/HeaderLink.astro b/packages/astro/e2e/fixtures/actions-blog/src/components/HeaderLink.astro new file mode 100644 index 000000000000..bb600fb65ac3 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/HeaderLink.astro @@ -0,0 +1,25 @@ +--- +import type { HTMLAttributes } from 'astro/types'; + +type Props = HTMLAttributes<'a'>; + +const { href, class: className, ...props } = Astro.props; + +const { pathname } = Astro.url; +const subpath = pathname.match(/[^\/]+/g); +const isActive = href === pathname || href === '/' + subpath?.[0]; +--- + + + + + diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx b/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx new file mode 100644 index 000000000000..7d4e6a53d161 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/Like.tsx @@ -0,0 +1,22 @@ +import { actions } from 'astro:actions'; +import { useState } from 'react'; + +export function Like({ postId, initial }: { postId: string; initial: number }) { + const [likes, setLikes] = useState(initial); + const [pending, setPending] = useState(false); + + return ( + + ); +} diff --git a/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx b/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx new file mode 100644 index 000000000000..f73d152e12bf --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/components/PostComment.tsx @@ -0,0 +1,70 @@ +import { getActionProps, actions, isInputError } from 'astro:actions'; +import { useState } from 'react'; + +export function PostComment({ + postId, + serverBodyError, +}: { + postId: string; + serverBodyError?: string; +}) { + const [comments, setComments] = useState<{ author: string; body: string }[]>([]); + const [bodyError, setBodyError] = useState(serverBodyError); + const [unexpectedError, setUnexpectedError] = useState(undefined); + + return ( + <> +
{ + e.preventDefault(); + const form = e.target as HTMLFormElement; + const formData = new FormData(form); + const { data, error } = await actions.blog.comment.safe(formData); + if (isInputError(error)) { + return setBodyError(error.fields.body?.join(' ')); + } else if (error) { + return setUnexpectedError(`${error.code}: ${error.message}`); + } + setBodyError(undefined); + setComments((c) => [data, ...c]); + form.reset(); + }} + > + {unexpectedError &&

{unexpectedError}

} + + + + + + {bodyError && ( +

+ {bodyError} +

+ )} + +
+
+ {comments.map((c) => ( +
+

{c.body}

+

{c.author}

+
+ ))} +
+ + ); +} diff --git a/packages/astro/e2e/fixtures/actions-blog/src/consts.ts b/packages/astro/e2e/fixtures/actions-blog/src/consts.ts new file mode 100644 index 000000000000..0df8a61f4cf7 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/consts.ts @@ -0,0 +1,5 @@ +// Place any global data in this file. +// You can import this data from anywhere in your site by using the `import` keyword. + +export const SITE_TITLE = 'Astro Blog'; +export const SITE_DESCRIPTION = 'Welcome to my website!'; diff --git a/packages/astro/e2e/fixtures/actions-blog/src/content/blog/first-post.md b/packages/astro/e2e/fixtures/actions-blog/src/content/blog/first-post.md new file mode 100644 index 000000000000..ee51f1541097 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/content/blog/first-post.md @@ -0,0 +1,15 @@ +--- +title: 'First post' +description: 'Lorem ipsum dolor sit amet' +pubDate: 'Jul 08 2022' +--- + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet. + +Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc. Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra massa massa ultricies mi. + +Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim. + +Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id cursus metus aliquam eleifend mi. + +Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar proin gravida. Egestas integer eget aliquet nibh praesent tristique magna. diff --git a/packages/astro/e2e/fixtures/actions-blog/src/content/config.ts b/packages/astro/e2e/fixtures/actions-blog/src/content/config.ts new file mode 100644 index 000000000000..667a31cc7391 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/content/config.ts @@ -0,0 +1,16 @@ +import { defineCollection, z } from 'astro:content'; + +const blog = defineCollection({ + type: 'content', + // Type-check frontmatter using a schema + schema: z.object({ + title: z.string(), + description: z.string(), + // Transform string to Date object + pubDate: z.coerce.date(), + updatedDate: z.coerce.date().optional(), + heroImage: z.string().optional(), + }), +}); + +export const collections = { blog }; diff --git a/packages/astro/e2e/fixtures/actions-blog/src/layouts/BlogPost.astro b/packages/astro/e2e/fixtures/actions-blog/src/layouts/BlogPost.astro new file mode 100644 index 000000000000..e67b2b30f859 --- /dev/null +++ b/packages/astro/e2e/fixtures/actions-blog/src/layouts/BlogPost.astro @@ -0,0 +1,85 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import BaseHead from '../components/BaseHead.astro'; +import Header from '../components/Header.astro'; +import Footer from '../components/Footer.astro'; +import FormattedDate from '../components/FormattedDate.astro'; + +type Props = CollectionEntry<'blog'>['data']; + +const { title, description, pubDate, updatedDate, heroImage } = Astro.props; +--- + + + + + + + + +
+
+
+
+ {heroImage && } +
+
+
+
+ + { + updatedDate && ( +
+ Last updated on +
+ ) + } +
+

{title}

+
+
+ +
+
+
+