mirror of
https://github.com/withastro/astro.git
synced 2025-01-06 22:10:10 -05:00
Merge branch 'feat/reroute' into feat/reroute-ssr
This commit is contained in:
commit
4c6c61fec2
259 changed files with 1614 additions and 600 deletions
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"astro": patch
|
||||
---
|
||||
|
||||
Fixes `astro add` sometimes modifying `baseUrl` unintentionally
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"@astrojs/mdx": patch
|
||||
---
|
||||
|
||||
Removes internal MDX processor on `buildEnd` to free up memory
|
5
.changeset/weak-swans-sparkle.md
Normal file
5
.changeset/weak-swans-sparkle.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"astro": patch
|
||||
---
|
||||
|
||||
Due to regression on mobile WebKit browsers, reverts a change made for JavaScript animations during view transitions.
|
28
.github/renovate.json5
vendored
Normal file
28
.github/renovate.json5
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended",
|
||||
"schedule:weekly",
|
||||
"group:allNonMajor",
|
||||
":disablePeerDependencies",
|
||||
],
|
||||
"labels": ["dependencies"],
|
||||
"rangeStrategy": "bump",
|
||||
"ignoreDeps": [
|
||||
// manually bumping deps
|
||||
"@biomejs/biome",
|
||||
"@types/node",
|
||||
"sharp",
|
||||
|
||||
// manually bumping workflow actions
|
||||
"actions/labeler",
|
||||
|
||||
// ignore "engines" update
|
||||
"node",
|
||||
"npm",
|
||||
"pnpm",
|
||||
|
||||
// follow vite deps version
|
||||
"postcss-load-config",
|
||||
],
|
||||
}
|
13
.github/workflows/nightly.yml
vendored
13
.github/workflows/nightly.yml
vendored
|
@ -1,13 +0,0 @@
|
|||
name: Nightly
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Run every Monday at 12:00 UTC
|
||||
- cron: "0 12 * * 1"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
lockfile:
|
||||
if: github.repository_owner == 'withastro'
|
||||
uses: withastro/automation/.github/workflows/lockfile.yml@main
|
||||
secrets: inherit
|
|
@ -19,3 +19,12 @@ benchmark/results/
|
|||
|
||||
# Files
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Formatted by Biome
|
||||
**/*.json
|
||||
**/*.js
|
||||
**/*.ts
|
||||
**/*.tsx
|
||||
**/*.jsx
|
||||
**/*.mjs
|
||||
**/*.cjs
|
||||
|
|
46
biome.json
46
biome.json
|
@ -1,16 +1,48 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
|
||||
"files": {
|
||||
"include": ["test/**", "e2e/**", "packages/**"],
|
||||
"ignore": ["vendor", "dist/**"]
|
||||
"ignore": [
|
||||
"vendor",
|
||||
"**/dist/**",
|
||||
"**/smoke/**",
|
||||
"**/fixtures/**",
|
||||
"**/vendor/**",
|
||||
"**/.vercel/**"
|
||||
],
|
||||
"include": ["test/**", "e2e/**", "packages/**"]
|
||||
},
|
||||
"formatter": {
|
||||
"indentStyle": "tab",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 100,
|
||||
"ignore": [
|
||||
"benchmark/projects/",
|
||||
"benchmark/results/",
|
||||
".changeset",
|
||||
"pnpm-lock.yaml",
|
||||
"package.json",
|
||||
"*.astro"
|
||||
]
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": false
|
||||
"linter": { "enabled": false },
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"trailingComma": "es5",
|
||||
"quoteStyle": "single",
|
||||
"semicolons": "always"
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": false
|
||||
"json": {
|
||||
"parser": {
|
||||
"allowComments": true,
|
||||
"allowTrailingCommas": true
|
||||
},
|
||||
"formatter": {
|
||||
"indentStyle": "space",
|
||||
"trailingCommas": "none"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.3.0",
|
||||
"@astrojs/mdx": "^2.3.1",
|
||||
"@astrojs/rss": "^4.0.5",
|
||||
"@astrojs/sitemap": "^3.1.2",
|
||||
"astro": "^4.6.1"
|
||||
"@astrojs/sitemap": "^3.1.4",
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
|||
<li>Edit this page in <code>src/pages/index.astro</code></li>
|
||||
<li>Edit the site header items in <code>src/components/Header.astro</code></li>
|
||||
<li>Add your name to the footer in <code>src/components/Footer.astro</code></li>
|
||||
<li>Check out the included blog posts in <code>src/pages/blog/</code></li>
|
||||
<li>Check out the included blog posts in <code>src/content/blog/</code></li>
|
||||
<li>Customize the blog post page layout in <code>src/layouts/BlogPost.astro</code></li>
|
||||
</ul>
|
||||
<p>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^4.0.0"
|
||||
|
|
|
@ -14,6 +14,6 @@
|
|||
"@astrojs/alpinejs": "^0.4.0",
|
||||
"@types/alpinejs": "^3.13.5",
|
||||
"alpinejs": "^3.13.3",
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/lit": "^4.0.1",
|
||||
"@webcomponents/template-shadowroot": "^0.2.1",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"lit": "^3.1.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"@astrojs/vue": "^4.1.0",
|
||||
"@types/react": "^18.2.37",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"preact": "^10.19.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/preact": "^3.2.0",
|
||||
"@preact/signals": "^1.2.1",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"preact": "^10.19.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"@astrojs/react": "^3.3.0",
|
||||
"@types/react": "^18.2.37",
|
||||
"@types/react-dom": "^18.2.15",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/solid-js": "^4.1.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"solid-js": "^1.8.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/svelte": "^5.4.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"svelte": "^4.2.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/vue": "^4.1.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"vue": "^3.3.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^8.2.5",
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"scripts": {},
|
||||
"devDependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^4.0.0"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^8.2.5",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"html-minifier": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/node": "^8.2.5",
|
||||
"@astrojs/svelte": "^5.4.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"svelte": "^4.2.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"sass": "^1.69.5",
|
||||
"sharp": "^0.32.6"
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
"devDependencies": {
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astrojs/node": "^8.2.5",
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/markdoc": "^0.10.0",
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/markdown-remark": "^5.1.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"hast-util-select": "^6.0.2",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1"
|
||||
"astro": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.3.0",
|
||||
"@astrojs/mdx": "^2.3.1",
|
||||
"@astrojs/preact": "^3.2.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"preact": "^10.19.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/preact": "^3.2.0",
|
||||
"@nanostores/preact": "^0.5.0",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"nanostores": "^0.9.5",
|
||||
"preact": "^10.19.2"
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.3.0",
|
||||
"@astrojs/mdx": "^2.3.1",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@types/canvas-confetti": "^1.6.3",
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"canvas-confetti": "^1.9.1",
|
||||
"postcss": "^8.4.28",
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"astro": "^4.6.1",
|
||||
"astro": "^4.6.3",
|
||||
"vitest": "^1.3.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
"dev": "turbo run dev --concurrency=40 --parallel --filter=astro --filter=create-astro --filter=\"@astrojs/*\" --filter=\"@benchmark/*\"",
|
||||
"format": "pnpm run format:code && pnpm run format:imports",
|
||||
"format:ci": "pnpm run format:code:ci && pnpm run format:imports:ci",
|
||||
"format:code": "prettier -w \"**/*\" --ignore-unknown --cache",
|
||||
"format:code:ci": "prettier -w \"**/*\" --ignore-unknown --cache --check",
|
||||
"format:code": "biome format ./ --write && prettier -w \"**/*\" --ignore-unknown --cache",
|
||||
"format:code:ci": "biome format ./ && prettier -w \"**/*\" --ignore-unknown --cache --check",
|
||||
"format:imports": "biome check --apply .",
|
||||
"format:imports:ci": "biome ci .",
|
||||
"test": "turbo run test --concurrency=1 --filter=astro --filter=create-astro --filter=\"@astrojs/*\"",
|
||||
|
@ -53,7 +53,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "^0.5.8",
|
||||
"@biomejs/biome": "1.5.3",
|
||||
"@biomejs/biome": "1.6.4",
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
"@eslint/eslintrc": "^3.0.2",
|
||||
|
|
|
@ -19,17 +19,18 @@ import {
|
|||
|
||||
// note: I spent 30 minutes looking for a nice node-based snapshot tool
|
||||
// ...and I gave up. Enjoy big strings!
|
||||
// prettier-ignore
|
||||
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlResult = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link><item><title><![CDATA[${phpFeedItem.title}]]></title><link>${site}${phpFeedItem.link}/</link><guid isPermaLink="true">${site}${phpFeedItem.link}/</guid><description><![CDATA[${phpFeedItem.description}]]></description><pubDate>${new Date(phpFeedItem.pubDate).toUTCString()}</pubDate></item><item><title><![CDATA[${web1FeedItem.title}]]></title><link>${site}${web1FeedItem.link}/</link><guid isPermaLink="true">${site}${web1FeedItem.link}/</guid><description><![CDATA[${web1FeedItem.description}]]></description><pubDate>${new Date(web1FeedItem.pubDate).toUTCString()}</pubDate></item></channel></rss>`;
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlWithContentResult = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link><item><title><![CDATA[${phpFeedItemWithContent.title}]]></title><link>${site}${phpFeedItemWithContent.link}/</link><guid isPermaLink="true">${site}${phpFeedItemWithContent.link}/</guid><description><![CDATA[${phpFeedItemWithContent.description}]]></description><pubDate>${new Date(phpFeedItemWithContent.pubDate).toUTCString()}</pubDate><content:encoded><![CDATA[${phpFeedItemWithContent.content}]]></content:encoded></item><item><title><![CDATA[${web1FeedItemWithContent.title}]]></title><link>${site}${web1FeedItemWithContent.link}/</link><guid isPermaLink="true">${site}${web1FeedItemWithContent.link}/</guid><description><![CDATA[${web1FeedItemWithContent.description}]]></description><pubDate>${new Date(web1FeedItemWithContent.pubDate).toUTCString()}</pubDate><content:encoded><![CDATA[${web1FeedItemWithContent.content}]]></content:encoded></item></channel></rss>`;
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlResultWithAllData = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link><item><title><![CDATA[${phpFeedItem.title}]]></title><link>${site}${phpFeedItem.link}/</link><guid isPermaLink="true">${site}${phpFeedItem.link}/</guid><description><![CDATA[${phpFeedItem.description}]]></description><pubDate>${new Date(phpFeedItem.pubDate).toUTCString()}</pubDate></item><item><title><![CDATA[${web1FeedItemWithAllData.title}]]></title><link>${site}${web1FeedItemWithAllData.link}/</link><guid isPermaLink="true">${site}${web1FeedItemWithAllData.link}/</guid><description><![CDATA[${web1FeedItemWithAllData.description}]]></description><pubDate>${new Date(web1FeedItemWithAllData.pubDate).toUTCString()}</pubDate><category>${web1FeedItemWithAllData.categories[0]}</category><category>${web1FeedItemWithAllData.categories[1]}</category><author>${web1FeedItemWithAllData.author}</author><comments>${web1FeedItemWithAllData.commentsUrl}</comments><source url="${web1FeedItemWithAllData.source.url}">${web1FeedItemWithAllData.source.title}</source><enclosure url="${site}${web1FeedItemWithAllData.enclosure.url}" length="${web1FeedItemWithAllData.enclosure.length}" type="${web1FeedItemWithAllData.enclosure.type}"/></item></channel></rss>`;
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlWithCustomDataResult = `<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link><item><title><![CDATA[${phpFeedItemWithCustomData.title}]]></title><link>${site}${phpFeedItemWithCustomData.link}/</link><guid isPermaLink="true">${site}${phpFeedItemWithCustomData.link}/</guid><description><![CDATA[${phpFeedItemWithCustomData.description}]]></description><pubDate>${new Date(phpFeedItemWithCustomData.pubDate).toUTCString()}</pubDate>${phpFeedItemWithCustomData.customData}</item><item><title><![CDATA[${web1FeedItemWithContent.title}]]></title><link>${site}${web1FeedItemWithContent.link}/</link><guid isPermaLink="true">${site}${web1FeedItemWithContent.link}/</guid><description><![CDATA[${web1FeedItemWithContent.description}]]></description><pubDate>${new Date(web1FeedItemWithContent.pubDate).toUTCString()}</pubDate><content:encoded><![CDATA[${web1FeedItemWithContent.content}]]></content:encoded></item></channel></rss>`;
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlWithStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feedstylesheet.css"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link></channel></rss>`;
|
||||
// prettier-ignore
|
||||
// biome-ignore format: keep in one line
|
||||
const validXmlWithXSLStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feedstylesheet.xsl" type="text/xsl"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link></channel></rss>`;
|
||||
|
||||
function assertXmlDeepEqual(a, b) {
|
||||
|
|
|
@ -1,5 +1,37 @@
|
|||
# astro
|
||||
|
||||
## 4.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#10799](https://github.com/withastro/astro/pull/10799) [`dc74afca9f5eebc2d61331298d6ef187d92051e0`](https://github.com/withastro/astro/commit/dc74afca9f5eebc2d61331298d6ef187d92051e0) Thanks [@martrapp](https://github.com/martrapp)! - Fixes an issue with persisted non-text input fields that have the focus during view transition navigation.
|
||||
|
||||
- [#10773](https://github.com/withastro/astro/pull/10773) [`35e43ecdaae7adc4b9a0b974192a033568cfb3f0`](https://github.com/withastro/astro/commit/35e43ecdaae7adc4b9a0b974192a033568cfb3f0) Thanks [@lilnasy](https://github.com/lilnasy)! - Improves performance for frequent use of small components.
|
||||
|
||||
- [#10763](https://github.com/withastro/astro/pull/10763) [`63132771373ce1510be3e8814897accc0bf62ef8`](https://github.com/withastro/astro/commit/63132771373ce1510be3e8814897accc0bf62ef8) Thanks [@matthewp](https://github.com/matthewp)! - Invalidate CC cache manifest when lockfile or config changes
|
||||
|
||||
- [#10811](https://github.com/withastro/astro/pull/10811) [`77822a822b04b5113726f713df104e8667333c59`](https://github.com/withastro/astro/commit/77822a822b04b5113726f713df104e8667333c59) Thanks [@AvinashReddy3108](https://github.com/AvinashReddy3108)! - Update list of available integrations in the `astro add` CLI help.
|
||||
|
||||
## 4.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#10732](https://github.com/withastro/astro/pull/10732) [`a92e263beb6e0166f1f13c97803d1861793e2a99`](https://github.com/withastro/astro/commit/a92e263beb6e0166f1f13c97803d1861793e2a99) Thanks [@rishi-raj-jain](https://github.com/rishi-raj-jain)! - Correctly sets `build.assets` directory during `vite` config setup
|
||||
|
||||
- [#10776](https://github.com/withastro/astro/pull/10776) [`1607face67051b16d4648555f1001b2a9308e377`](https://github.com/withastro/astro/commit/1607face67051b16d4648555f1001b2a9308e377) Thanks [@fshafiee](https://github.com/fshafiee)! - Fixes cookies type inference
|
||||
|
||||
- [#10796](https://github.com/withastro/astro/pull/10796) [`90669472df3a05b33f0de46fd2d039e3eba7f7dd`](https://github.com/withastro/astro/commit/90669472df3a05b33f0de46fd2d039e3eba7f7dd) Thanks [@bluwy](https://github.com/bluwy)! - Disables streaming when rendering site with `output: "static"`
|
||||
|
||||
- [#10782](https://github.com/withastro/astro/pull/10782) [`b0589d05538fcc77dd3c38198bf93f3548362cd8`](https://github.com/withastro/astro/commit/b0589d05538fcc77dd3c38198bf93f3548362cd8) Thanks [@nektro](https://github.com/nektro)! - Handles possible null value when calling `which-pm` during dynamic package installation
|
||||
|
||||
- [#10774](https://github.com/withastro/astro/pull/10774) [`308b5d8c122f44e7724bb2f3ad3aa5c43a83e584`](https://github.com/withastro/astro/commit/308b5d8c122f44e7724bb2f3ad3aa5c43a83e584) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes `astro add` sometimes modifying `baseUrl` unintentionally
|
||||
|
||||
- [#10783](https://github.com/withastro/astro/pull/10783) [`4dbd545304d1a8af903c8c97f237eb55c988c40b`](https://github.com/withastro/astro/commit/4dbd545304d1a8af903c8c97f237eb55c988c40b) Thanks [@jurajkapsz](https://github.com/jurajkapsz)! - Fixes Picture component specialFormatsFallback fallback check
|
||||
|
||||
- [#10775](https://github.com/withastro/astro/pull/10775) [`06843121450899ecf0390ca4efaff6c9a6fe0f75`](https://github.com/withastro/astro/commit/06843121450899ecf0390ca4efaff6c9a6fe0f75) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes assets endpoint in serverless returning 404 in certain situations where the website might be under a protected route
|
||||
|
||||
- [#10787](https://github.com/withastro/astro/pull/10787) [`699f4559a279b374bddb3e5e48c72afe2709e8e7`](https://github.com/withastro/astro/commit/699f4559a279b374bddb3e5e48c72afe2709e8e7) Thanks [@martrapp](https://github.com/martrapp)! - Fixes a timing issue in the view transition simulation.
|
||||
|
||||
## 4.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
2
packages/astro/astro-jsx.d.ts
vendored
2
packages/astro/astro-jsx.d.ts
vendored
|
@ -9,8 +9,6 @@
|
|||
* Adapted from React’s TypeScript definition from DefinitelyTyped.
|
||||
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts
|
||||
*/
|
||||
// BUG! Prettier 3.0 removes `declare`: https://github.com/prettier/prettier/issues/15207
|
||||
// prettier-ignore
|
||||
declare namespace astroHTML.JSX {
|
||||
export type Child = Node | Node[] | string | number | boolean | null | undefined | unknown;
|
||||
export type Children = Child | Child[];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import { getImage, type LocalImageProps, type RemoteImageProps } from 'astro:assets';
|
||||
import { type LocalImageProps, type RemoteImageProps, getImage } from 'astro:assets';
|
||||
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
|
||||
import type { HTMLAttributes } from '../types';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
import { getImage, type LocalImageProps, type RemoteImageProps } from 'astro:assets';
|
||||
import { type LocalImageProps, type RemoteImageProps, getImage } from 'astro:assets';
|
||||
import type { GetImageResult, ImageOutputFormat } from '../dist/@types/astro';
|
||||
import { isESMImportedImage, resolveSrc } from '../dist/assets/utils/imageKind';
|
||||
import { AstroError, AstroErrorData } from '../dist/core/errors/index.js';
|
||||
|
@ -45,7 +45,7 @@ let resultFallbackFormat = fallbackFormat ?? defaultFallbackFormat;
|
|||
if (
|
||||
!fallbackFormat &&
|
||||
isESMImportedImage(originalSrc) &&
|
||||
originalSrc.format in specialFormatsFallback
|
||||
(specialFormatsFallback as ReadonlyArray<string>).includes(originalSrc.format)
|
||||
) {
|
||||
resultFallbackFormat = originalSrc.format;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import Hero from '../components/Hero.astro';
|
||||
import LinkedLib from '@e2e/astro-linked-lib'
|
||||
import HoistedScript from '@e2e/astro-linked-lib/HoistedScript'
|
||||
import Hero from '../components/Hero.astro';
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.jsx';
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.jsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import One from './One.jsx';
|
||||
import Deeper from './Deeper.astro';
|
||||
import One from './One.jsx';
|
||||
---
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
import ClientOnlyComponent from '../components/ClientOnlyComponent.js';
|
||||
import MyCounter from '../components/Counter.js';
|
||||
import NonDeferredCounter from '../components/NonDeferredCounter.js';
|
||||
import ClientOnlyComponent from '../components/ClientOnlyComponent.js';
|
||||
|
||||
const someProps = {
|
||||
count: 10,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@webcomponents/template-shadowroot": "^0.2.1",
|
||||
"lit": "^2.8.0",
|
||||
"lit": "^3.1.0",
|
||||
"preact": "^10.19.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
---
|
||||
// Style Imports
|
||||
import '../styles/global.css';
|
||||
// Component Imports
|
||||
import { A, B as Renamed } from '../components';
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import * as react from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
// Style Imports
|
||||
import '../styles/global.css';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/preact/PreactCounter.tsx';
|
||||
import { Counter as ReactCounter } from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/basics/astro-components/
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import PreactCounter from '../components/preact/PreactCounter.tsx';
|
||||
import ReactCounter from '../components/react/ReactCounter.jsx';
|
||||
import SolidCounter from '../components/solid/SolidCounter.tsx';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
import SvelteCounter from '../components/svelte/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/vue/VueCounter.vue';
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import type { BigNestedObject } from '../types';
|
||||
import Component from '../components/React';
|
||||
import type { BigNestedObject } from '../types';
|
||||
|
||||
const object: BigNestedObject = {
|
||||
nested: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import WrapperB from "../components/WrapperB.jsx";
|
||||
import WrapperA from "../components/WrapperA.jsx";
|
||||
import WrapperB from "../components/WrapperB.jsx";
|
||||
---
|
||||
|
||||
<html>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
// Component Imports
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Button from '../components/Button.astro';
|
||||
import Complex from '../components/Complex.astro';
|
||||
// Component Imports
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { navigate } from "astro:transitions/client";
|
||||
import React from 'react';
|
||||
export default function ClickToNavigate({ to, id }) {
|
||||
return <button id={id} onClick={() => navigate(to)}>Navigate to `{to}`</button>;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import ClickToNavigate from "../components/ClickToNavigate.jsx"
|
||||
import { ViewTransitions } from "astro:transitions";
|
||||
import ClickToNavigate from "../components/ClickToNavigate.jsx"
|
||||
---
|
||||
<html>
|
||||
<head>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import Layout from '../components/Layout.astro';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
---
|
||||
<Layout>
|
||||
<p id="page-four">Page 4</p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island';
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<a id="click-two" href="/client-only-two">go to page 2</a>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import Layout from '../components/Layout.astro';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
---
|
||||
<Layout>
|
||||
<a id="click-four" href="/client-only-four">go to page 4</a>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island';
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<p id="page-two">Page 2</p>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import InlineScript from '../components/InlineScript.astro';
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<InlineScript />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import InlineScript from '../components/InlineScript.astro';
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<InlineScript />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island.jsx';
|
||||
import Layout from '../components/Layout.astro';
|
||||
export const prerender = false;
|
||||
|
||||
const persistProps = Astro.url.searchParams.has('persist');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
import Island from '../components/Island.jsx';
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<p id="island-two">Page 2</p>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<p id="one">Persist 1</p>
|
||||
<form transition:persist="form" action="/persist-2">
|
||||
<input type="text" name="name" />
|
||||
<input type="checkbox" />
|
||||
</form>
|
||||
<div id="test">test content</div>
|
||||
</Layout>
|
||||
<script>
|
||||
const input = document.querySelector<HTMLInputElement>("form input")!;
|
||||
input.focus();
|
||||
input.value = "some cool text";
|
||||
input.selectionStart=5;
|
||||
input.selectionEnd=9;
|
||||
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
const textInput = document.querySelector<HTMLInputElement>("form input:first-of-type")!;
|
||||
console.log(textInput === document.activeElement, textInput.value, textInput.selectionStart, textInput.selectionEnd);
|
||||
const checkBox = document.querySelector<HTMLInputElement>("form input:nth-of-type(2)")!;
|
||||
checkBox.checked = true;
|
||||
checkBox.focus();
|
||||
}, {once:true});
|
||||
</script>
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
import Layout from '../components/Layout.astro';
|
||||
---
|
||||
<Layout>
|
||||
<p id="two">Persist 2</p>
|
||||
<a id="click-persist-one" href="/persist-1">go to 3</a>
|
||||
<div transition:persist="form"/>
|
||||
<div id="test">test content</div>
|
||||
</Layout>
|
||||
<script>
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
const checkBox = document.querySelector<HTMLInputElement>("form input:nth-of-type(2)")!;
|
||||
console.log(checkBox === document.activeElement, checkBox.checked);
|
||||
}, {once:true});
|
||||
</script>
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
import Counter from '../components/Counter.vue';
|
||||
import VueComponent from '../components/VueComponent.vue';
|
||||
import AsyncTest from '../components/Test.vue'
|
||||
import State from '../components/State.vue'
|
||||
import AsyncTest from '../components/Test.vue'
|
||||
import VueComponent from '../components/VueComponent.vue';
|
||||
|
||||
const someProps = {
|
||||
count: 0,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { expect, test as base } from '@playwright/test';
|
||||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture, waitForHydrate } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
|
|
|
@ -1403,3 +1403,20 @@ test.describe('View Transitions', () => {
|
|||
).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
test('transition:persist persists selection', async ({ page, astro }) => {
|
||||
let text = '';
|
||||
page.on('console', (msg) => {
|
||||
text = msg.text();
|
||||
});
|
||||
await page.goto(astro.resolveUrl('/persist-1'));
|
||||
await expect(page.locator('#one'), 'should have content').toHaveText('Persist 1');
|
||||
// go to page 2
|
||||
await page.press('input[name="name"]', 'Enter');
|
||||
await expect(page.locator('#two'), 'should have content').toHaveText('Persist 2');
|
||||
expect(text).toBe('true some cool text 5 9');
|
||||
|
||||
await page.goBack();
|
||||
await expect(page.locator('#one'), 'should have content').toHaveText('Persist 1');
|
||||
expect(text).toBe('true true');
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "astro",
|
||||
"version": "4.6.1",
|
||||
"version": "4.6.3",
|
||||
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
||||
"type": "module",
|
||||
"author": "withastro",
|
||||
|
@ -125,6 +125,7 @@
|
|||
"@babel/traverse": "^7.23.3",
|
||||
"@babel/types": "^7.23.3",
|
||||
"@types/babel__core": "^7.20.4",
|
||||
"@types/cookie": "^0.5.4",
|
||||
"acorn": "^8.11.2",
|
||||
"aria-query": "^5.3.0",
|
||||
"axobject-query": "^4.0.0",
|
||||
|
@ -137,7 +138,7 @@
|
|||
"cssesc": "^3.0.0",
|
||||
"debug": "^4.3.4",
|
||||
"deterministic-object-hash": "^2.0.1",
|
||||
"devalue": "^4.3.2",
|
||||
"devalue": "^5.0.0",
|
||||
"diff": "^5.1.0",
|
||||
"dlv": "^1.1.3",
|
||||
"dset": "^3.1.3",
|
||||
|
@ -154,8 +155,8 @@
|
|||
"js-yaml": "^4.1.0",
|
||||
"kleur": "^4.1.4",
|
||||
"magic-string": "^0.30.3",
|
||||
"mime": "^3.0.0",
|
||||
"ora": "^7.0.1",
|
||||
"mrmime": "^2.0.0",
|
||||
"ora": "^8.0.1",
|
||||
"p-limit": "^5.0.0",
|
||||
"p-queue": "^8.0.1",
|
||||
"path-to-regexp": "^6.2.1",
|
||||
|
@ -186,10 +187,8 @@
|
|||
"@types/aria-query": "^5.0.4",
|
||||
"@types/babel__generator": "^7.6.7",
|
||||
"@types/babel__traverse": "^7.20.4",
|
||||
"@types/chai": "^4.3.10",
|
||||
"@types/common-ancestor-path": "^1.0.2",
|
||||
"@types/connect": "^3.4.38",
|
||||
"@types/cookie": "^0.5.4",
|
||||
"@types/cssesc": "^3.0.2",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@types/diff": "^5.0.8",
|
||||
|
@ -199,7 +198,6 @@
|
|||
"@types/html-escaper": "^3.0.2",
|
||||
"@types/http-cache-semantics": "^4.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/mime": "^3.0.4",
|
||||
"@types/mocha": "^10.0.4",
|
||||
"@types/probe-image-size": "^7.2.3",
|
||||
"@types/prompts": "^2.4.8",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import { Heading, Aside, LikeButton, HydratedLikeButton } from '@performance/utils';
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
import { Aside, Heading, HydratedLikeButton, LikeButton } from '@performance/utils';
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<'generated'>;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
import Title from './Title.astro';
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
import Title from './Title.astro';
|
||||
|
||||
type Props = {
|
||||
entry: CollectionEntry<'generated'>;
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/yargs-parser": "^21.0.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"kleur": "^4.1.5",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1500,9 +1500,8 @@ export interface AstroUserConfig {
|
|||
* Controls the routing strategy to determine your site URLs. Set this based on your folder/URL path configuration for your default language.
|
||||
*
|
||||
*/
|
||||
// prettier-ignore
|
||||
routing?:
|
||||
{
|
||||
routing?:
|
||||
| {
|
||||
/**
|
||||
* @docs
|
||||
* @name i18n.routing.prefixDefaultLocale
|
||||
|
@ -1519,18 +1518,18 @@ export interface AstroUserConfig {
|
|||
* When `true`, all URLs will display a language prefix.
|
||||
* URLs will be of the form `example.com/[locale]/content/` for every route, including the default language.
|
||||
* Localized folders are used for every language, including the default.
|
||||
*
|
||||
* ```js
|
||||
* export default defineConfig({
|
||||
* i18n: {
|
||||
* defaultLocale: "en",
|
||||
* locales: ["en", "fr", "pt-br", "es"],
|
||||
* routing: {
|
||||
* prefixDefaultLocale: true,
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* export default defineConfig({
|
||||
* i18n: {
|
||||
* defaultLocale: "en",
|
||||
* locales: ["en", "fr", "pt-br", "es"],
|
||||
* routing: {
|
||||
* prefixDefaultLocale: true,
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
prefixDefaultLocale?: boolean;
|
||||
|
||||
|
@ -1573,32 +1572,32 @@ export interface AstroUserConfig {
|
|||
* - `"pathname": The strategy is applied to the pathname of the URLs
|
||||
*/
|
||||
strategy?: 'pathname';
|
||||
} |
|
||||
/**
|
||||
*
|
||||
* @docs
|
||||
* @name i18n.routing.manual
|
||||
* @kind h4
|
||||
* @type {string}
|
||||
* @version 4.6.0
|
||||
* @description
|
||||
* When this option is enabled, Astro will **disable** its i18n middleware so that you can implement your own custom logic. No other `routing` options (e.g. `prefixDefaultLocale`) may be configured with `routing: "manual"`.
|
||||
*
|
||||
* You will be responsible for writing your own routing logic, or executing Astro's i18n middleware manually alongside your own.
|
||||
*
|
||||
* ```js
|
||||
* export default defineConfig({
|
||||
* i18n: {
|
||||
* defaultLocale: "en",
|
||||
* locales: ["en", "fr", "pt-br", "es"],
|
||||
* routing: {
|
||||
* prefixDefaultLocale: true,
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
'manual';
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @docs
|
||||
* @name i18n.routing.manual
|
||||
* @kind h4
|
||||
* @type {string}
|
||||
* @version 4.6.0
|
||||
* @description
|
||||
* When this option is enabled, Astro will **disable** its i18n middleware so that you can implement your own custom logic. No other `routing` options (e.g. `prefixDefaultLocale`) may be configured with `routing: "manual"`.
|
||||
*
|
||||
* You will be responsible for writing your own routing logic, or executing Astro's i18n middleware manually alongside your own.
|
||||
*
|
||||
* ```js
|
||||
* export default defineConfig({
|
||||
* i18n: {
|
||||
* defaultLocale: "en",
|
||||
* locales: ["en", "fr", "pt-br", "es"],
|
||||
* routing: {
|
||||
* prefixDefaultLocale: true,
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
| 'manual';
|
||||
|
||||
/**
|
||||
* @name i18n.domains
|
||||
|
@ -2801,6 +2800,7 @@ export interface AstroIntegration {
|
|||
dir: URL;
|
||||
routes: RouteData[];
|
||||
logger: AstroIntegrationLogger;
|
||||
cacheManifest: boolean;
|
||||
}) => void | Promise<void>;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
// @ts-expect-error
|
||||
import { imageConfig } from 'astro:assets';
|
||||
import { isRemotePath } from '@astrojs/internal-helpers/path';
|
||||
import mime from 'mime/lite.js';
|
||||
import * as mime from 'mrmime';
|
||||
import type { APIRoute } from '../../@types/astro.js';
|
||||
import { getConfiguredImageService } from '../internal.js';
|
||||
import { etag } from '../utils/etag.js';
|
||||
import { isRemoteAllowed } from '../utils/remotePattern.js';
|
||||
// @ts-expect-error
|
||||
import { imageConfig } from 'astro:assets';
|
||||
|
||||
async function loadRemoteImage(src: URL) {
|
||||
async function loadRemoteImage(src: URL, headers: Headers) {
|
||||
try {
|
||||
const res = await fetch(src);
|
||||
const res = await fetch(src, {
|
||||
// Forward all headers from the original request
|
||||
headers,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
return undefined;
|
||||
|
@ -41,15 +44,14 @@ export const GET: APIRoute = async ({ request }) => {
|
|||
|
||||
let inputBuffer: ArrayBuffer | undefined = undefined;
|
||||
|
||||
const sourceUrl = isRemotePath(transform.src)
|
||||
? new URL(transform.src)
|
||||
: new URL(transform.src, url.origin);
|
||||
const isRemoteImage = isRemotePath(transform.src);
|
||||
const sourceUrl = isRemoteImage ? new URL(transform.src) : new URL(transform.src, url.origin);
|
||||
|
||||
if (isRemotePath(transform.src) && isRemoteAllowed(transform.src, imageConfig) === false) {
|
||||
if (isRemoteImage && isRemoteAllowed(transform.src, imageConfig) === false) {
|
||||
return new Response('Forbidden', { status: 403 });
|
||||
}
|
||||
|
||||
inputBuffer = await loadRemoteImage(sourceUrl);
|
||||
inputBuffer = await loadRemoteImage(sourceUrl, isRemoteImage ? new Headers() : request.headers);
|
||||
|
||||
if (!inputBuffer) {
|
||||
return new Response('Not Found', { status: 404 });
|
||||
|
@ -64,7 +66,7 @@ export const GET: APIRoute = async ({ request }) => {
|
|||
return new Response(data, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': mime.getType(format) ?? `image/${format}`,
|
||||
'Content-Type': mime.lookup(format) ?? `image/${format}`,
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
ETag: etag(data.toString()),
|
||||
Date: new Date().toUTCString(),
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
import os from 'node:os';
|
||||
import { isAbsolute } from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
// @ts-expect-error
|
||||
import { assetsDir, imageConfig, outDir } from 'astro:assets';
|
||||
import { isRemotePath, removeQueryString } from '@astrojs/internal-helpers/path';
|
||||
import { readFile } from 'fs/promises';
|
||||
import mime from 'mime/lite.js';
|
||||
import * as mime from 'mrmime';
|
||||
import type { APIRoute } from '../../@types/astro.js';
|
||||
import { getConfiguredImageService } from '../internal.js';
|
||||
import { etag } from '../utils/etag.js';
|
||||
import { isRemoteAllowed } from '../utils/remotePattern.js';
|
||||
// @ts-expect-error
|
||||
import { assetsDir, imageConfig, outDir } from 'astro:assets';
|
||||
|
||||
function replaceFileSystemReferences(src: string) {
|
||||
return os.platform().includes('win32') ? src.replace(/^\/@fs\//, '') : src.replace(/^\/@fs/, '');
|
||||
|
@ -110,7 +110,7 @@ export const GET: APIRoute = async ({ request }) => {
|
|||
return new Response(data, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': mime.getType(format) ?? `image/${format}`,
|
||||
'Content-Type': mime.lookup(format) ?? `image/${format}`,
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
ETag: etag(data.toString()),
|
||||
Date: new Date().toUTCString(),
|
||||
|
|
|
@ -147,7 +147,9 @@ export default function assets({
|
|||
: settings.config.outDir
|
||||
)
|
||||
)});
|
||||
export const assetsDir = /* #__PURE__ */ new URL(${JSON.stringify(settings.config.build.assets)}, outDir);
|
||||
export const assetsDir = /* #__PURE__ */ new URL(${JSON.stringify(
|
||||
settings.config.build.assets
|
||||
)}, outDir);
|
||||
export const getImage = async (options) => await getImageInternal(options, imageConfig);
|
||||
`;
|
||||
}
|
||||
|
|
|
@ -148,12 +148,12 @@ export async function add(names: string[], { flags }: AddOptions) {
|
|||
['node', 'astro add node'],
|
||||
],
|
||||
Others: [
|
||||
['db', 'astro add db'],
|
||||
['tailwind', 'astro add tailwind'],
|
||||
['image', 'astro add image'],
|
||||
['mdx', 'astro add mdx'],
|
||||
['markdoc', 'astro add markdoc'],
|
||||
['partytown', 'astro add partytown'],
|
||||
['sitemap', 'astro add sitemap'],
|
||||
['prefetch', 'astro add prefetch'],
|
||||
],
|
||||
},
|
||||
description: `For more integrations, check out: ${cyan('https://astro.build/integrations')}`,
|
||||
|
|
|
@ -39,7 +39,9 @@ export async function getPackage<T>(
|
|||
return packageImport as T;
|
||||
} catch (e) {
|
||||
if (options.optional) return undefined;
|
||||
let message = `To continue, Astro requires the following dependency to be installed: ${bold(packageName)}.`;
|
||||
let message = `To continue, Astro requires the following dependency to be installed: ${bold(
|
||||
packageName
|
||||
)}.`;
|
||||
|
||||
if (ci.isCI) {
|
||||
message += ` Packages cannot be installed automatically in CI environments.`;
|
||||
|
@ -101,7 +103,7 @@ async function installPackage(
|
|||
logger: Logger
|
||||
): Promise<boolean> {
|
||||
const cwd = options.cwd ?? process.cwd();
|
||||
const packageManager = (await whichPm(cwd)).name ?? 'npm';
|
||||
const packageManager = (await whichPm(cwd))?.name ?? 'npm';
|
||||
const installCommand = getInstallCommand(packageNames, packageManager);
|
||||
|
||||
if (!installCommand) {
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import type {
|
||||
ComponentInstance,
|
||||
ManifestData,
|
||||
ReroutePayload,
|
||||
RouteData,
|
||||
SSRElement,
|
||||
SSRResult,
|
||||
} from '../../@types/astro.js';
|
||||
import { Pipeline } from '../base-pipeline.js';
|
||||
import { createModuleScriptElement, createStylesheetElementSet } from '../render/ssr-element.js';
|
||||
import type { SinglePageBuiltModule } from '../build/types.js';
|
||||
import { DEFAULT_404_COMPONENT } from '../constants.js';
|
||||
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
|
||||
|
||||
export class AppPipeline extends Pipeline {
|
||||
#manifestData: ManifestData | undefined;
|
||||
|
|
1
packages/astro/src/core/build/consts.ts
Normal file
1
packages/astro/src/core/build/consts.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export const CHUNKS_PATH = 'chunks/';
|
|
@ -218,6 +218,7 @@ class AstroBuilder {
|
|||
.flat()
|
||||
.map((pageData) => pageData.route),
|
||||
logging: this.logger,
|
||||
cacheManifest: internals.cacheManifestUsed,
|
||||
});
|
||||
|
||||
if (this.logger.level && levels[this.logger.level()] <= levels['info']) {
|
||||
|
|
|
@ -89,6 +89,7 @@ export interface BuildInternals {
|
|||
discoveredScripts: Set<string>;
|
||||
|
||||
cachedClientEntries: string[];
|
||||
cacheManifestUsed: boolean;
|
||||
|
||||
propagatedStylesMap: Map<string, Set<StylesheetAsset>>;
|
||||
propagatedScriptsMap: Map<string, Set<string>>;
|
||||
|
@ -140,6 +141,7 @@ export function createBuildInternals(): BuildInternals {
|
|||
componentMetadata: new Map(),
|
||||
ssrSplitEntryChunks: new Map(),
|
||||
entryPoints: new Map(),
|
||||
cacheManifestUsed: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,8 @@ export class BuildPipeline extends Pipeline {
|
|||
return assetLink;
|
||||
}
|
||||
const serverLike = isServerLikeOutput(config);
|
||||
const streaming = true;
|
||||
// We can skip streaming in SSG for performance as writing as strings are faster
|
||||
const streaming = serverLike;
|
||||
super(
|
||||
options.logger,
|
||||
manifest,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Plugin as VitePlugin, Rollup } from 'vite';
|
||||
import type { Rollup, Plugin as VitePlugin } from 'vite';
|
||||
import type { BuildInternals } from './internal.js';
|
||||
import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
|
||||
|
||||
|
|
|
@ -10,8 +10,16 @@ import {
|
|||
generateLookupMap,
|
||||
} from '../../../content/vite-plugin-content-virtual-mod.js';
|
||||
import { isServerLikeOutput } from '../../../prerender/utils.js';
|
||||
import { joinPaths, removeFileExtension, removeLeadingForwardSlash } from '../../path.js';
|
||||
import { configPaths } from '../../config/index.js';
|
||||
import { emptyDir } from '../../fs/index.js';
|
||||
import {
|
||||
appendForwardSlash,
|
||||
joinPaths,
|
||||
removeFileExtension,
|
||||
removeLeadingForwardSlash,
|
||||
} from '../../path.js';
|
||||
import { addRollupInput } from '../add-rollup-input.js';
|
||||
import { CHUNKS_PATH } from '../consts.js';
|
||||
import { type BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin } from '../plugin.js';
|
||||
import { copyFiles } from '../static-build.js';
|
||||
|
@ -23,7 +31,7 @@ const CONTENT_CACHE_DIR = './content/';
|
|||
const CONTENT_MANIFEST_FILE = './manifest.json';
|
||||
// IMPORTANT: Update this version when making significant changes to the manifest format.
|
||||
// Only manifests generated with the same version number can be compared.
|
||||
const CONTENT_MANIFEST_VERSION = 0;
|
||||
const CONTENT_MANIFEST_VERSION = 1;
|
||||
|
||||
interface ContentManifestKey {
|
||||
collection: string;
|
||||
|
@ -39,40 +47,51 @@ interface ContentManifest {
|
|||
// Tracks components that should be passed to the client build
|
||||
// When the cache is restored, these might no longer be referenced
|
||||
clientEntries: string[];
|
||||
// Hash of the lockfiles, pnpm-lock.yaml, package-lock.json, etc.
|
||||
// Kept so that installing new packages results in a full rebuild.
|
||||
lockfiles: string;
|
||||
// Hash of the Astro config. Changing options results in invalidating the cache.
|
||||
configs: string;
|
||||
}
|
||||
|
||||
const virtualEmptyModuleId = `virtual:empty-content`;
|
||||
const resolvedVirtualEmptyModuleId = `\0${virtualEmptyModuleId}`;
|
||||
const NO_MANIFEST_VERSION = -1 as const;
|
||||
|
||||
function createContentManifest(): ContentManifest {
|
||||
return { version: -1, entries: [], serverEntries: [], clientEntries: [] };
|
||||
return {
|
||||
version: NO_MANIFEST_VERSION,
|
||||
entries: [],
|
||||
serverEntries: [],
|
||||
clientEntries: [],
|
||||
lockfiles: '',
|
||||
configs: '',
|
||||
};
|
||||
}
|
||||
|
||||
function vitePluginContent(
|
||||
opts: StaticBuildOptions,
|
||||
lookupMap: ContentLookupMap,
|
||||
internals: BuildInternals
|
||||
internals: BuildInternals,
|
||||
cachedBuildOutput: Array<{ cached: URL; dist: URL }>
|
||||
): VitePlugin {
|
||||
const { config } = opts.settings;
|
||||
const { cacheDir } = config;
|
||||
const distRoot = config.outDir;
|
||||
const distContentRoot = new URL('./content/', distRoot);
|
||||
const cachedChunks = new URL('./chunks/', opts.settings.config.cacheDir);
|
||||
const distChunks = new URL('./chunks/', opts.settings.config.outDir);
|
||||
const contentCacheDir = new URL(CONTENT_CACHE_DIR, cacheDir);
|
||||
const contentManifestFile = new URL(CONTENT_MANIFEST_FILE, contentCacheDir);
|
||||
const cache = contentCacheDir;
|
||||
const cacheTmp = new URL('./.tmp/', cache);
|
||||
const cacheTmp = new URL('./.tmp/', contentCacheDir);
|
||||
let oldManifest = createContentManifest();
|
||||
let newManifest = createContentManifest();
|
||||
let entries: ContentEntries;
|
||||
let injectedEmptyFile = false;
|
||||
let currentManifestState: ReturnType<typeof manifestState> = 'valid';
|
||||
|
||||
if (fsMod.existsSync(contentManifestFile)) {
|
||||
try {
|
||||
const data = fsMod.readFileSync(contentManifestFile, { encoding: 'utf8' });
|
||||
oldManifest = JSON.parse(data);
|
||||
internals.cachedClientEntries = oldManifest.clientEntries;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
|
@ -84,6 +103,32 @@ function vitePluginContent(
|
|||
newManifest = await generateContentManifest(opts, lookupMap);
|
||||
entries = getEntriesFromManifests(oldManifest, newManifest);
|
||||
|
||||
// If the manifest is valid, use the cached client entries as nothing has changed
|
||||
currentManifestState = manifestState(oldManifest, newManifest);
|
||||
if (currentManifestState === 'valid') {
|
||||
internals.cachedClientEntries = oldManifest.clientEntries;
|
||||
} else {
|
||||
let logReason = '';
|
||||
switch (currentManifestState) {
|
||||
case 'config-mismatch':
|
||||
logReason = 'Astro config has changed';
|
||||
break;
|
||||
case 'lockfile-mismatch':
|
||||
logReason = 'Lockfiles have changed';
|
||||
break;
|
||||
case 'no-entries':
|
||||
logReason = 'No content collections entries cached';
|
||||
break;
|
||||
case 'version-mismatch':
|
||||
logReason = 'The cache manifest version has changed';
|
||||
break;
|
||||
case 'no-manifest':
|
||||
logReason = 'No content manifest was found in the cache';
|
||||
break;
|
||||
}
|
||||
opts.logger.info('build', `Cache invalid, rebuilding from source. Reason: ${logReason}.`);
|
||||
}
|
||||
|
||||
// Of the cached entries, these ones need to be rebuilt
|
||||
for (const { type, entry } of entries.buildFromSource) {
|
||||
const fileURL = encodeURI(joinPaths(opts.settings.config.root.toString(), entry));
|
||||
|
@ -96,10 +141,18 @@ function vitePluginContent(
|
|||
}
|
||||
newOptions = addRollupInput(newOptions, inputs);
|
||||
}
|
||||
// Restores cached chunks from the previous build
|
||||
if (fsMod.existsSync(cachedChunks)) {
|
||||
await copyFiles(cachedChunks, distChunks, true);
|
||||
|
||||
// Restores cached chunks and assets from the previous build
|
||||
// If the manifest state is not valid then it needs to rebuild everything
|
||||
// so don't do that in this case.
|
||||
if (currentManifestState === 'valid') {
|
||||
for (const { cached, dist } of cachedBuildOutput) {
|
||||
if (fsMod.existsSync(cached)) {
|
||||
await copyFiles(cached, dist, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing needs to be rebuilt, we inject a fake entrypoint to appease Rollup
|
||||
if (entries.buildFromSource.length === 0) {
|
||||
newOptions = addRollupInput(newOptions, [virtualEmptyModuleId]);
|
||||
|
@ -199,16 +252,20 @@ function vitePluginContent(
|
|||
]);
|
||||
newManifest.serverEntries = Array.from(serverComponents);
|
||||
newManifest.clientEntries = Array.from(clientComponents);
|
||||
|
||||
const cacheExists = fsMod.existsSync(contentCacheDir);
|
||||
// If the manifest is invalid, empty the cache so that we can create a new one.
|
||||
if (cacheExists && currentManifestState !== 'valid') {
|
||||
emptyDir(contentCacheDir);
|
||||
}
|
||||
|
||||
await fsMod.promises.mkdir(contentCacheDir, { recursive: true });
|
||||
await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), {
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
const cacheExists = fsMod.existsSync(cache);
|
||||
fsMod.mkdirSync(cache, { recursive: true });
|
||||
await fsMod.promises.mkdir(cacheTmp, { recursive: true });
|
||||
await copyFiles(distContentRoot, cacheTmp, true);
|
||||
if (cacheExists) {
|
||||
if (cacheExists && currentManifestState === 'valid') {
|
||||
await copyFiles(contentCacheDir, distContentRoot, false);
|
||||
}
|
||||
await copyFiles(cacheTmp, contentCacheDir);
|
||||
|
@ -242,12 +299,12 @@ function getEntriesFromManifests(
|
|||
oldManifest: ContentManifest,
|
||||
newManifest: ContentManifest
|
||||
): ContentEntries {
|
||||
const { version: oldVersion, entries: oldEntries } = oldManifest;
|
||||
const { version: newVersion, entries: newEntries } = newManifest;
|
||||
const { entries: oldEntries } = oldManifest;
|
||||
const { entries: newEntries } = newManifest;
|
||||
let entries: ContentEntries = { restoreFromCache: [], buildFromSource: [] };
|
||||
|
||||
const newEntryMap = new Map<ContentManifestKey, string>(newEntries);
|
||||
if (oldVersion !== newVersion || oldEntries.length === 0) {
|
||||
if (manifestState(oldManifest, newManifest) !== 'valid') {
|
||||
entries.buildFromSource = Array.from(newEntryMap.keys());
|
||||
return entries;
|
||||
}
|
||||
|
@ -265,16 +322,43 @@ function getEntriesFromManifests(
|
|||
return entries;
|
||||
}
|
||||
|
||||
type ManifestState =
|
||||
| 'valid'
|
||||
| 'no-manifest'
|
||||
| 'version-mismatch'
|
||||
| 'no-entries'
|
||||
| 'lockfile-mismatch'
|
||||
| 'config-mismatch';
|
||||
|
||||
function manifestState(oldManifest: ContentManifest, newManifest: ContentManifest): ManifestState {
|
||||
// There isn't an existing manifest.
|
||||
if (oldManifest.version === NO_MANIFEST_VERSION) {
|
||||
return 'no-manifest';
|
||||
}
|
||||
// Version mismatch, always invalid
|
||||
if (oldManifest.version !== newManifest.version) {
|
||||
return 'version-mismatch';
|
||||
}
|
||||
if (oldManifest.entries.length === 0) {
|
||||
return 'no-entries';
|
||||
}
|
||||
// Lockfiles have changed or there is no lockfile at all.
|
||||
if (oldManifest.lockfiles !== newManifest.lockfiles || newManifest.lockfiles === '') {
|
||||
return 'lockfile-mismatch';
|
||||
}
|
||||
// Config has changed.
|
||||
if (oldManifest.configs !== newManifest.configs) {
|
||||
return 'config-mismatch';
|
||||
}
|
||||
return 'valid';
|
||||
}
|
||||
|
||||
async function generateContentManifest(
|
||||
opts: StaticBuildOptions,
|
||||
lookupMap: ContentLookupMap
|
||||
): Promise<ContentManifest> {
|
||||
let manifest: ContentManifest = {
|
||||
version: CONTENT_MANIFEST_VERSION,
|
||||
entries: [],
|
||||
serverEntries: [],
|
||||
clientEntries: [],
|
||||
};
|
||||
let manifest = createContentManifest();
|
||||
manifest.version = CONTENT_MANIFEST_VERSION;
|
||||
const limit = pLimit(10);
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
|
@ -291,12 +375,62 @@ async function generateContentManifest(
|
|||
}
|
||||
}
|
||||
|
||||
const [lockfiles, configs] = await Promise.all([
|
||||
lockfilesHash(opts.settings.config.root),
|
||||
configHash(opts.settings.config.root),
|
||||
]);
|
||||
|
||||
manifest.lockfiles = lockfiles;
|
||||
manifest.configs = configs;
|
||||
|
||||
await Promise.all(promises);
|
||||
return manifest;
|
||||
}
|
||||
|
||||
function checksum(data: string): string {
|
||||
return createHash('sha1').update(data).digest('base64');
|
||||
async function pushBufferInto(fileURL: URL, buffers: Uint8Array[]) {
|
||||
try {
|
||||
const handle = await fsMod.promises.open(fileURL, 'r');
|
||||
const data = await handle.readFile();
|
||||
buffers.push(data);
|
||||
await handle.close();
|
||||
} catch {
|
||||
// File doesn't exist, ignore
|
||||
}
|
||||
}
|
||||
|
||||
async function lockfilesHash(root: URL) {
|
||||
// Order is important so don't change this.
|
||||
const lockfiles = ['package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'bun.lockb'];
|
||||
const datas: Uint8Array[] = [];
|
||||
const promises: Promise<void>[] = [];
|
||||
for (const lockfileName of lockfiles) {
|
||||
const fileURL = new URL(`./${lockfileName}`, root);
|
||||
promises.push(pushBufferInto(fileURL, datas));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return checksum(...datas);
|
||||
}
|
||||
|
||||
async function configHash(root: URL) {
|
||||
const configFileNames = configPaths;
|
||||
for (const configPath of configFileNames) {
|
||||
try {
|
||||
const fileURL = new URL(`./${configPath}`, root);
|
||||
const data = await fsMod.promises.readFile(fileURL);
|
||||
const hash = checksum(data);
|
||||
return hash;
|
||||
} catch {
|
||||
// File doesn't exist
|
||||
}
|
||||
}
|
||||
// No config file, still create a hash since we can compare nothing against nothing.
|
||||
return checksum(`export default {}`);
|
||||
}
|
||||
|
||||
function checksum(...datas: string[] | Uint8Array[]): string {
|
||||
const hash = createHash('sha1');
|
||||
datas.forEach((data) => hash.update(data));
|
||||
return hash.digest('base64');
|
||||
}
|
||||
|
||||
function collectionTypeToFlag(type: 'content' | 'data') {
|
||||
|
@ -308,8 +442,15 @@ export function pluginContent(
|
|||
opts: StaticBuildOptions,
|
||||
internals: BuildInternals
|
||||
): AstroBuildPlugin {
|
||||
const cachedChunks = new URL('./chunks/', opts.settings.config.cacheDir);
|
||||
const distChunks = new URL('./chunks/', opts.settings.config.outDir);
|
||||
const { cacheDir, outDir } = opts.settings.config;
|
||||
|
||||
const chunksFolder = './' + CHUNKS_PATH;
|
||||
const assetsFolder = './' + appendForwardSlash(opts.settings.config.build.assets);
|
||||
// These are build output that is kept in the cache.
|
||||
const cachedBuildOutput = [
|
||||
{ cached: new URL(chunksFolder, cacheDir), dist: new URL(chunksFolder, outDir) },
|
||||
{ cached: new URL(assetsFolder, cacheDir), dist: new URL(assetsFolder, outDir) },
|
||||
];
|
||||
|
||||
return {
|
||||
targets: ['server'],
|
||||
|
@ -321,10 +462,9 @@ export function pluginContent(
|
|||
if (isServerLikeOutput(opts.settings.config)) {
|
||||
return { vitePlugin: undefined };
|
||||
}
|
||||
|
||||
const lookupMap = await generateLookupMap({ settings: opts.settings, fs: fsMod });
|
||||
return {
|
||||
vitePlugin: vitePluginContent(opts, lookupMap, internals),
|
||||
vitePlugin: vitePluginContent(opts, lookupMap, internals, cachedBuildOutput),
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -335,8 +475,11 @@ export function pluginContent(
|
|||
if (isServerLikeOutput(opts.settings.config)) {
|
||||
return;
|
||||
}
|
||||
if (fsMod.existsSync(distChunks)) {
|
||||
await copyFiles(distChunks, cachedChunks, true);
|
||||
// Cache build output of chunks and assets
|
||||
for (const { cached, dist } of cachedBuildOutput) {
|
||||
if (fsMod.existsSync(dist)) {
|
||||
await copyFiles(dist, cached, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { GetModuleInfo } from 'rollup';
|
||||
import type { BuildOptions, Plugin as VitePlugin, ResolvedConfig, Rollup } from 'vite';
|
||||
import type { BuildOptions, ResolvedConfig, Rollup, Plugin as VitePlugin } from 'vite';
|
||||
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
||||
import type { BuildInternals } from '../internal.js';
|
||||
import type { AstroBuildPlugin, BuildTarget } from '../plugin.js';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { extname } from 'node:path';
|
||||
import type { BuildOptions, Plugin as VitePlugin, Rollup } from 'vite';
|
||||
import type { BuildOptions, Rollup, Plugin as VitePlugin } from 'vite';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type OutputOptionsHook = Extract<VitePlugin['outputOptions'], Function>;
|
||||
|
|
|
@ -23,6 +23,7 @@ import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js';
|
|||
import { AstroError, AstroErrorData } from '../errors/index.js';
|
||||
import { routeIsRedirect } from '../redirects/index.js';
|
||||
import { getOutDirWithinCwd } from './common.js';
|
||||
import { CHUNKS_PATH } from './consts.js';
|
||||
import { generatePages } from './generate.js';
|
||||
import { trackPageData } from './internal.js';
|
||||
import { type AstroBuildPluginContainer, createPluginContainer } from './plugin.js';
|
||||
|
@ -196,7 +197,7 @@ async function ssrBuild(
|
|||
// We need to keep these separate
|
||||
chunkFileNames(chunkInfo) {
|
||||
const { name } = chunkInfo;
|
||||
let prefix = 'chunks/';
|
||||
let prefix = CHUNKS_PATH;
|
||||
let suffix = '_[hash].mjs';
|
||||
|
||||
if (isContentCache) {
|
||||
|
@ -454,7 +455,7 @@ export async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles
|
|||
dot: includeDotfiles,
|
||||
});
|
||||
if (files.length === 0) return;
|
||||
await Promise.all(
|
||||
return await Promise.all(
|
||||
files.map(async function copyFile(filename) {
|
||||
const from = new URL(filename, fromFolder);
|
||||
const to = new URL(filename, toFolder);
|
||||
|
|
|
@ -78,15 +78,19 @@ export function resolveRoot(cwd?: string | URL): string {
|
|||
return cwd ? path.resolve(cwd) : process.cwd();
|
||||
}
|
||||
|
||||
// Config paths to search for. In order of likely appearance
|
||||
// to speed up the check.
|
||||
export const configPaths = Object.freeze([
|
||||
'astro.config.mjs',
|
||||
'astro.config.js',
|
||||
'astro.config.ts',
|
||||
'astro.config.mts',
|
||||
'astro.config.cjs',
|
||||
'astro.config.cts',
|
||||
]);
|
||||
|
||||
async function search(fsMod: typeof fs, root: string) {
|
||||
const paths = [
|
||||
'astro.config.mjs',
|
||||
'astro.config.js',
|
||||
'astro.config.ts',
|
||||
'astro.config.mts',
|
||||
'astro.config.cjs',
|
||||
'astro.config.cts',
|
||||
].map((p) => path.join(root, p));
|
||||
const paths = configPaths.map((p) => path.join(root, p));
|
||||
|
||||
for (const file of paths) {
|
||||
if (fsMod.existsSync(file)) {
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
export { resolveConfig, resolveConfigPath, resolveFlags, resolveRoot } from './config.js';
|
||||
export {
|
||||
configPaths,
|
||||
resolveConfig,
|
||||
resolveConfigPath,
|
||||
resolveFlags,
|
||||
resolveRoot,
|
||||
} from './config.js';
|
||||
export { createNodeLogger } from './logging.js';
|
||||
export { mergeConfig } from './merge.js';
|
||||
export type { AstroConfigType } from './schema.js';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type {
|
||||
ShikiConfig,
|
||||
RehypePlugin as _RehypePlugin,
|
||||
RemarkPlugin as _RemarkPlugin,
|
||||
RemarkRehype as _RemarkRehype,
|
||||
ShikiConfig,
|
||||
} from '@astrojs/markdown-remark';
|
||||
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
||||
import { type BuiltinTheme, bundledThemes } from 'shiki';
|
||||
|
|
|
@ -208,6 +208,7 @@ export async function createVite(
|
|||
noExternal: [...ALWAYS_NOEXTERNAL, ...astroPkgsConfig.ssr.noExternal],
|
||||
external: [...(mode === 'dev' ? ONLY_DEV_EXTERNAL : []), ...astroPkgsConfig.ssr.external],
|
||||
},
|
||||
build: { assetsDir: settings.config.build.assets },
|
||||
};
|
||||
|
||||
// If the user provides a custom assets prefix, make sure assets handled by Vite
|
||||
|
|
|
@ -171,7 +171,9 @@ function collectInfoFromStacktrace(error: SSRError & { stack: string }): StackIn
|
|||
error.pluginCode ||
|
||||
error.id ||
|
||||
// TODO: this could be better, `src` might be something else
|
||||
stackText.split('\n').find((ln) => ln.includes('src') || ln.includes('node_modules'));
|
||||
stackText
|
||||
.split('\n')
|
||||
.find((ln) => ln.includes('src') || ln.includes('node_modules'));
|
||||
// Disable eslint as we're not sure how to improve this regex yet
|
||||
// eslint-disable-next-line regexp/no-super-linear-backtracking
|
||||
const source = possibleFilePath?.replace?.(/^[^(]+\(([^)]+).*$/, '$1').replace(/^\s+at\s+/, '');
|
||||
|
|
|
@ -168,9 +168,7 @@ export const NoMatchingRenderer = {
|
|||
|
||||
${
|
||||
validRenderersCount > 0
|
||||
? `There ${plural ? 'are' : 'is'} ${validRenderersCount} renderer${
|
||||
plural ? 's' : ''
|
||||
} configured in your \`astro.config.mjs\` file,
|
||||
? `There ${plural ? 'are' : 'is'} ${validRenderersCount} renderer${plural ? 's' : ''} configured in your \`astro.config.mjs\` file,
|
||||
but ${plural ? 'none were' : 'it was not'} able to server-side render \`${componentName}\`.`
|
||||
: `No valid renderer was found ${
|
||||
componentExtension
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { fileURLToPath } from 'url';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import type { LogLevel, Logger as ViteLogger, Rollup } from 'vite';
|
||||
import type { LogLevel, Rollup, Logger as ViteLogger } from 'vite';
|
||||
import { isAstroError } from '../errors/errors.js';
|
||||
import { serverShortcuts as formatServerShortcuts } from '../messages.js';
|
||||
import { type Logger as AstroLogger, isLogLevelEnabled } from './core.js';
|
||||
|
|
|
@ -317,12 +317,57 @@ export class RenderContext {
|
|||
return result;
|
||||
}
|
||||
|
||||
#astroPagePartial?: Omit<AstroGlobal, 'props' | 'self' | 'slots'>;
|
||||
/**
|
||||
* The Astro global is sourced in 3 different phases:
|
||||
* - **Static**: `.generator` and `.glob` is printed by the compiler, instantiated once per process per astro file
|
||||
* - **Page-level**: `.request`, `.cookies`, `.locals` etc. These remain the same for the duration of the request.
|
||||
* - **Component-level**: `.props`, `.slots`, and `.self` are unique to each _use_ of each component.
|
||||
*
|
||||
* The page level partial is used as the prototype of the user-visible `Astro` global object, which is instantiated once per use of a component.
|
||||
*/
|
||||
createAstro(
|
||||
result: SSRResult,
|
||||
astroGlobalPartial: AstroGlobalPartial,
|
||||
astroStaticPartial: AstroGlobalPartial,
|
||||
props: Record<string, any>,
|
||||
slotValues: Record<string, any> | null
|
||||
): AstroGlobal {
|
||||
// Create page partial with static partial so they can be cached together.
|
||||
const astroPagePartial = (this.#astroPagePartial ??= this.createAstroPagePartial(
|
||||
result,
|
||||
astroStaticPartial
|
||||
));
|
||||
// Create component-level partials. `Astro.self` is added by the compiler.
|
||||
const astroComponentPartial = { props, self: null };
|
||||
|
||||
// Create final object. `Astro.slots` will be lazily created.
|
||||
const Astro: Omit<AstroGlobal, 'self' | 'slots'> = Object.assign(
|
||||
Object.create(astroPagePartial),
|
||||
astroComponentPartial
|
||||
);
|
||||
|
||||
// Handle `Astro.slots`
|
||||
let _slots: AstroGlobal['slots'];
|
||||
Object.defineProperty(Astro, 'slots', {
|
||||
get: () => {
|
||||
if (!_slots) {
|
||||
_slots = new Slots(
|
||||
result,
|
||||
slotValues,
|
||||
this.pipeline.logger
|
||||
) as unknown as AstroGlobal['slots'];
|
||||
}
|
||||
return _slots;
|
||||
},
|
||||
});
|
||||
|
||||
return Astro as AstroGlobal;
|
||||
}
|
||||
|
||||
createAstroPagePartial(
|
||||
result: SSRResult,
|
||||
astroStaticPartial: AstroGlobalPartial
|
||||
): Omit<AstroGlobal, 'props' | 'self' | 'slots'> {
|
||||
const renderContext = this;
|
||||
const { cookies, locals, params, pipeline, url } = this;
|
||||
const { response } = result;
|
||||
|
@ -363,12 +408,10 @@ export class RenderContext {
|
|||
}
|
||||
};
|
||||
|
||||
const slots = new Slots(result, slotValues, pipeline.logger) as unknown as AstroGlobal['slots'];
|
||||
|
||||
// `Astro.self` is added by the compiler
|
||||
const astroGlobalCombined: Omit<AstroGlobal, 'self'> = {
|
||||
generator: astroGlobalPartial.generator,
|
||||
glob: astroGlobalPartial.glob,
|
||||
return {
|
||||
generator: astroStaticPartial.generator,
|
||||
glob: astroStaticPartial.glob,
|
||||
cookies,
|
||||
get clientAddress() {
|
||||
return renderContext.clientAddress();
|
||||
|
@ -383,18 +426,14 @@ export class RenderContext {
|
|||
get preferredLocaleList() {
|
||||
return renderContext.computePreferredLocaleList();
|
||||
},
|
||||
props,
|
||||
locals,
|
||||
redirect,
|
||||
reroute,
|
||||
request: this.request,
|
||||
response,
|
||||
slots,
|
||||
site: pipeline.site,
|
||||
url,
|
||||
};
|
||||
|
||||
return astroGlobalCombined as AstroGlobal;
|
||||
}
|
||||
|
||||
clientAddress() {
|
||||
|
|
|
@ -477,9 +477,16 @@ type RunHookBuildDone = {
|
|||
pages: string[];
|
||||
routes: RouteData[];
|
||||
logging: Logger;
|
||||
cacheManifest: boolean;
|
||||
};
|
||||
|
||||
export async function runHookBuildDone({ config, pages, routes, logging }: RunHookBuildDone) {
|
||||
export async function runHookBuildDone({
|
||||
config,
|
||||
pages,
|
||||
routes,
|
||||
logging,
|
||||
cacheManifest,
|
||||
}: RunHookBuildDone) {
|
||||
const dir = isServerLikeOutput(config) ? config.build.client : config.outDir;
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
|
||||
|
@ -495,6 +502,7 @@ export async function runHookBuildDone({ config, pages, routes, logging }: RunHo
|
|||
dir,
|
||||
routes,
|
||||
logger,
|
||||
cacheManifest,
|
||||
}),
|
||||
logger: logging,
|
||||
});
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue