summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/eleven-pens-glow.md41
-rw-r--r--.changeset/fifty-stingrays-flow.md6
-rw-r--r--.changeset/fresh-fans-study.md18
-rw-r--r--.changeset/mean-horses-kiss.md35
-rw-r--r--.changeset/mighty-trees-teach.md5
-rw-r--r--.changeset/odd-buttons-pay.md22
-rw-r--r--.changeset/rude-queens-shop.md7
-rw-r--r--.changeset/serious-pumas-run.md21
-rw-r--r--.changeset/smooth-chicken-wash.md107
-rw-r--r--.changeset/spicy-houses-fry.md5
-rw-r--r--README.md1
-rw-r--r--biome.json10
-rw-r--r--examples/basics/package.json2
-rw-r--r--examples/blog/package.json2
-rw-r--r--examples/component/package.json2
-rw-r--r--examples/container-with-vitest/package.json2
-rw-r--r--examples/framework-alpine/package.json2
-rw-r--r--examples/framework-lit/package.json2
-rw-r--r--examples/framework-multiple/package.json2
-rw-r--r--examples/framework-preact/package.json2
-rw-r--r--examples/framework-react/package.json2
-rw-r--r--examples/framework-solid/package.json2
-rw-r--r--examples/framework-svelte/package.json2
-rw-r--r--examples/framework-vue/package.json2
-rw-r--r--examples/hackernews/package.json2
-rw-r--r--examples/integration/package.json2
-rw-r--r--examples/middleware/package.json2
-rw-r--r--examples/minimal/package.json2
-rw-r--r--examples/non-html-pages/package.json2
-rw-r--r--examples/portfolio/package.json2
-rw-r--r--examples/server-islands/package.json2
-rw-r--r--examples/ssr/package.json2
-rw-r--r--examples/starlog/package.json2
-rw-r--r--examples/toolbar-app/package.json2
-rw-r--r--examples/view-transitions/package.json2
-rw-r--r--examples/with-markdoc/package.json2
-rw-r--r--examples/with-markdown-plugins/package.json2
-rw-r--r--examples/with-markdown-shiki/package.json2
-rw-r--r--examples/with-mdx/package.json2
-rw-r--r--examples/with-nanostores/package.json2
-rw-r--r--examples/with-tailwindcss/package.json2
-rw-r--r--examples/with-vitest/package.json2
-rw-r--r--package.json4
-rw-r--r--packages/astro/CHANGELOG.md240
-rw-r--r--packages/astro/e2e/fixtures/server-islands/astro.config.mjs2
-rw-r--r--packages/astro/e2e/fixtures/server-islands/src/components/HTMLError.astro1
-rw-r--r--packages/astro/e2e/fixtures/server-islands/src/pages/index.astro12
-rw-r--r--packages/astro/e2e/server-islands.test.js29
-rw-r--r--packages/astro/package.json6
-rw-r--r--packages/astro/src/@types/astro.ts40
-rw-r--r--packages/astro/src/assets/endpoint/node.ts2
-rw-r--r--packages/astro/src/cli/check/index.ts2
-rw-r--r--packages/astro/src/cli/db/index.ts22
-rw-r--r--packages/astro/src/cli/flags.ts8
-rw-r--r--packages/astro/src/cli/index.ts37
-rw-r--r--packages/astro/src/content/content-layer.ts6
-rw-r--r--packages/astro/src/content/data-store.ts375
-rw-r--r--packages/astro/src/content/loaders/types.ts2
-rw-r--r--packages/astro/src/content/mutable-data-store.ts370
-rw-r--r--packages/astro/src/content/types-generator.ts16
-rw-r--r--packages/astro/src/content/utils.ts8
-rw-r--r--packages/astro/src/core/build/plugins/plugin-ssr.ts44
-rw-r--r--packages/astro/src/core/dev/dev.ts12
-rw-r--r--packages/astro/src/core/dev/restart.ts2
-rw-r--r--packages/astro/src/core/errors/errors-data.ts4
-rw-r--r--packages/astro/src/core/logger/vite.ts2
-rw-r--r--packages/astro/src/core/preview/static-preview-server.ts2
-rw-r--r--packages/astro/src/core/routing/manifest/create.ts2
-rw-r--r--packages/astro/src/core/sync/index.ts23
-rw-r--r--packages/astro/src/core/sync/write-files.ts12
-rw-r--r--packages/astro/src/runtime/server/render/server-islands.ts10
-rw-r--r--packages/astro/src/vite-plugin-astro-server/response.ts2
-rw-r--r--packages/astro/templates/content/types.d.ts2
-rw-r--r--packages/astro/test/astro-sync.test.js4
-rw-r--r--packages/astro/test/build-readonly-file.test.js2
-rw-r--r--packages/astro/test/ssr-split-manifest.test.js12
-rw-r--r--packages/astro/test/test-adapter.js4
-rw-r--r--packages/astro/test/units/dev/collections-renderentry.test.js5
-rw-r--r--packages/create-astro/CHANGELOG.md12
-rw-r--r--packages/create-astro/package.json2
-rw-r--r--packages/create-astro/src/actions/context.ts91
-rw-r--r--packages/db/CHANGELOG.md35
-rw-r--r--packages/db/package.json4
-rw-r--r--packages/db/src/core/cli/commands/execute/index.ts4
-rw-r--r--packages/db/src/core/cli/commands/login/index.ts4
-rw-r--r--packages/db/src/core/cli/commands/push/index.ts4
-rw-r--r--packages/db/src/core/cli/commands/shell/index.ts4
-rw-r--r--packages/db/src/core/cli/commands/verify/index.ts4
-rw-r--r--packages/db/src/core/cli/index.ts4
-rw-r--r--packages/db/src/core/cli/types.ts4
-rw-r--r--packages/db/src/core/integration/index.ts14
-rw-r--r--packages/db/test/local-prod.test.js4
-rw-r--r--packages/integrations/mdx/src/vite-plugin-mdx.ts5
-rw-r--r--packages/integrations/node/src/standalone.ts2
-rw-r--r--packages/integrations/partytown/src/index.ts2
-rw-r--r--packages/integrations/sitemap/src/write-sitemap.ts10
-rw-r--r--packages/integrations/web-vitals/CHANGELOG.md7
-rw-r--r--packages/integrations/web-vitals/package.json4
-rw-r--r--packages/upgrade/CHANGELOG.md12
-rw-r--r--packages/upgrade/package.json2
-rw-r--r--packages/upgrade/src/actions/context.ts28
-rw-r--r--packages/upgrade/test/context.test.js4
-rw-r--r--pnpm-lock.yaml137
-rw-r--r--turbo.json111
104 files changed, 1178 insertions, 1000 deletions
diff --git a/.changeset/eleven-pens-glow.md b/.changeset/eleven-pens-glow.md
deleted file mode 100644
index d031fba49..000000000
--- a/.changeset/eleven-pens-glow.md
+++ /dev/null
@@ -1,41 +0,0 @@
----
-'astro': minor
----
-
-Deprecates the option for route-generating files to export a dynamic value for `prerender`. Only static values are now supported (e.g. `export const prerender = true` or `= false`). This allows for better treeshaking and bundling configuration in the future.
-
-Adds a new [`"astro:route:setup"` hook](https://docs.astro.build/en/reference/integrations-reference/#astroroutesetup) to the Integrations API to allow you to dynamically set options for a route at build or request time through an integration, such as enabling [on-demand server rendering](https://docs.astro.build/en/guides/server-side-rendering/#opting-in-to-pre-rendering-in-server-mode).
-
-To migrate from a dynamic export to the new hook, update or remove any dynamic `prerender` exports from individual routing files:
-
-```diff
-// src/pages/blog/[slug].astro
-- export const prerender = import.meta.env.PRERENDER
-```
-
-Instead, create an integration with the `"astro:route:setup"` hook and update the route's `prerender` option:
-
-```js
-// astro.config.mjs
-import { defineConfig } from 'astro/config';
-import { loadEnv } from 'vite';
-
-export default defineConfig({
- integrations: [setPrerender()],
-});
-
-function setPrerender() {
- const { PRERENDER } = loadEnv(process.env.NODE_ENV, process.cwd(), '');
-
- return {
- name: 'set-prerender',
- hooks: {
- 'astro:route:setup': ({ route }) => {
- if (route.component.endsWith('/blog/[slug].astro')) {
- route.prerender = PRERENDER;
- }
- },
- },
- };
-}
-```
diff --git a/.changeset/fifty-stingrays-flow.md b/.changeset/fifty-stingrays-flow.md
deleted file mode 100644
index 3f4b96b04..000000000
--- a/.changeset/fifty-stingrays-flow.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'astro': patch
-'@astrojs/db': patch
----
-
-Refactors internally to use `node:util` `parseArgs` instead of `yargs-parser`
diff --git a/.changeset/fresh-fans-study.md b/.changeset/fresh-fans-study.md
deleted file mode 100644
index 9a837b1fd..000000000
--- a/.changeset/fresh-fans-study.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-'@astrojs/db': minor
----
-
-Changes how type generation works
-
-The generated `.d.ts` file is now at a new location:
-
-```diff
-- .astro/db-types.d.ts
-+ .astro/integrations/astro_db/db.d.ts
-```
-
-The following line can now be removed from `src/env.d.ts`:
-
-```diff
-- /// <reference path="../.astro/db-types.d.ts" />
-```
diff --git a/.changeset/mean-horses-kiss.md b/.changeset/mean-horses-kiss.md
deleted file mode 100644
index 7d211e626..000000000
--- a/.changeset/mean-horses-kiss.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-'astro': minor
----
-
-Adds a new [`injectTypes()` utility](https://docs.astro.build/en/reference/integrations-reference/#injecttypes-options) to the Integration API and refactors how type generation works
-
-Use `injectTypes()` in the `astro:config:done` hook to inject types into your user's project by adding a new a `*.d.ts` file.
-
-The `filename` property will be used to generate a file at `/.astro/integrations/<normalized_integration_name>/<normalized_filename>.d.ts` and must end with `".d.ts"`.
-
-The `content` property will create the body of the file, and must be valid TypeScript.
-
-Additionally, `injectTypes()` returns a URL to the normalized path so you can overwrite its content later on, or manipulate it in any way you want.
-
-```js
-// my-integration/index.js
-export default {
- name: 'my-integration',
- 'astro:config:done': ({ injectTypes }) => {
- injectTypes({
- filename: "types.d.ts",
- content: "declare module 'virtual:my-integration' {}"
- })
- }
-};
-```
-
-Codegen has been refactored. Although `src/env.d.ts` will continue to work as is, we recommend you update it:
-
-```diff
-- /// <reference types="astro/client" />
-+ /// <reference path="../.astro/types.d.ts" />
-- /// <reference path="../.astro/env.d.ts" />
-- /// <reference path="../.astro/actions.d.ts" />
-``` \ No newline at end of file
diff --git a/.changeset/mighty-trees-teach.md b/.changeset/mighty-trees-teach.md
new file mode 100644
index 000000000..289a41816
--- /dev/null
+++ b/.changeset/mighty-trees-teach.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/mdx': patch
+---
+
+Fixes stack trace location when failed to parse an MDX file with frontmatter
diff --git a/.changeset/odd-buttons-pay.md b/.changeset/odd-buttons-pay.md
deleted file mode 100644
index 728068ef2..000000000
--- a/.changeset/odd-buttons-pay.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-"astro": minor
----
-
-Adds a new property `meta` to Astro's [built-in `<Code />` component](https://docs.astro.build/en/reference/api-reference/#code-).
-
-This allows you to provide a value for [Shiki's `meta` attribute](https://shiki.style/guide/transformers#meta) to pass options to transformers.
-
-The following example passes an option to highlight lines 1 and 3 to Shiki's `tranformerMetaHighlight`:
-
-```astro
----
-// src/components/Card.astro
-import { Code } from "astro:components";
-import { transformerMetaHighlight } from '@shikijs/transformers';
----
-<Code
- code={code}
- lang="js"
- transformers={[transformerMetaHighlight()]}
- meta="{1,3}" />
-```
diff --git a/.changeset/rude-queens-shop.md b/.changeset/rude-queens-shop.md
deleted file mode 100644
index 6610b16a5..000000000
--- a/.changeset/rude-queens-shop.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'create-astro': patch
-'@astrojs/upgrade': patch
----
-
-Refactors internally to use `node:util` `parseArgs` instead of `arg`
-
diff --git a/.changeset/serious-pumas-run.md b/.changeset/serious-pumas-run.md
deleted file mode 100644
index e6f7c9af1..000000000
--- a/.changeset/serious-pumas-run.md
+++ /dev/null
@@ -1,21 +0,0 @@
----
-'astro': minor
----
-
-Adds support for Intellisense features (e.g. code completion, quick hints) for your content collection entries in compatible editors under the `experimental.contentIntellisense` flag.
-
-```js
-import { defineConfig } from 'astro';
-
-export default defineConfig({
- experimental: {
- contentIntellisense: true
- }
-})
-```
-
-When enabled, this feature will generate and add JSON schemas to the `.astro` directory in your project. These files can be used by the Astro language server to provide Intellisense inside content files (`.md`, `.mdx`, `.mdoc`).
-
-Note that at this time, this also require enabling the `astro.content-intellisense` option in your editor, or passing the `contentIntellisense: true` initialization parameter to the Astro language server for editors using it directly.
-
-See the [experimental content Intellisense docs](https://docs.astro.build/en/reference/configuration-reference/#experimentalcontentintellisense) for more information updates as this feature develops.
diff --git a/.changeset/smooth-chicken-wash.md b/.changeset/smooth-chicken-wash.md
deleted file mode 100644
index 3ced01f52..000000000
--- a/.changeset/smooth-chicken-wash.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-'astro': minor
----
-
-Adds experimental support for the Content Layer API.
-
-The new Content Layer API builds upon content collections, taking them beyond local files in `src/content/` and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. There are significant improvements to performance with large collections of local files.
-
-### Getting started
-
-To try out the new Content Layer API, enable it in your Astro config:
-
-```js
-import { defineConfig } from 'astro';
-
-export default defineConfig({
- experimental: {
- contentLayer: true
- }
-})
-```
-
-You can then create collections in your `src/content/config.ts` using the Content Layer API.
-
-### Loading your content
-
-The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in `glob()` and `file()` loaders to handle your local Markdown, MDX, Markdoc, and JSON files:
-
-```ts {3,7}
-// src/content/config.ts
-import { defineCollection, z } from 'astro:content';
-import { glob } from 'astro/loaders';
-
-const blog = defineCollection({
- // The ID is a slug generated from the path of the file relative to `base`
- loader: glob({ pattern: "**/*.md", base: "./src/data/blog" }),
- schema: z.object({
- title: z.string(),
- description: z.string(),
- publishDate: z.coerce.date(),
- })
-});
-
-export const collections = { blog };
-```
-
-You can then query using the existing content collections functions, and enjoy a simplified `render()` function to display your content:
-
-```astro
----
-import { getEntry, render } from 'astro:content';
-
-const post = await getEntry('blog', Astro.params.slug);
-
-const { Content } = await render(entry);
----
-
-<Content />
-```
-
-### Creating a loader
-
-You're not restricted to the built-in loaders – we hope you'll try building your own. You can fetch content from anywhere and return an array of entries:
-
-```ts
-// src/content/config.ts
-const countries = defineCollection({
- loader: async () => {
- const response = await fetch("https://restcountries.com/v3.1/all");
- const data = await response.json();
- // Must return an array of entries with an id property,
- // or an object with IDs as keys and entries as values
- return data.map((country) => ({
- id: country.cca3,
- ...country,
- }));
- },
- // optionally add a schema to validate the data and make it type-safe for users
- // schema: z.object...
-});
-
-export const collections = { countries };
-```
-
-For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders) for more details.
-
-### Sharing your loaders
-
-Loaders are better when they're shared. You can create a package that exports a loader and publish it to npm, and then anyone can use it on their site. We're excited to see what the community comes up with! To get started, [take a look at some examples](https://github.com/ascorbic/astro-loaders/). Here's how to load content using an RSS/Atom feed loader:
-
-```ts
-// src/content/config.ts
-import { defineCollection } from "astro:content";
-import { feedLoader } from "@ascorbic/feed-loader";
-
-const podcasts = defineCollection({
- loader: feedLoader({
- url: "https://feeds.99percentinvisible.org/99percentinvisible",
- }),
-});
-
-export const collections = { podcasts };
-```
-
-### Learn more
-
-To find out more about using the Content Layer API, check out [the Content Layer RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md) and [share your feedback](https://github.com/withastro/roadmap/pull/982).
diff --git a/.changeset/spicy-houses-fry.md b/.changeset/spicy-houses-fry.md
new file mode 100644
index 000000000..41f376a35
--- /dev/null
+++ b/.changeset/spicy-houses-fry.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Simplifies path operations of `astro sync`
diff --git a/README.md b/README.md
index 9b5e734aa..62589bac8 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@ Join us on [Discord](https://astro.build/chat) to meet other maintainers. We'll
| [@astrojs/mdx](packages/integrations/mdx) | [![@astrojs/mdx version](https://img.shields.io/npm/v/@astrojs/mdx.svg?label=%20)](packages/integrations/mdx/CHANGELOG.md) |
| [@astrojs/db](packages/db) | [![@astrojs/db version](https://img.shields.io/npm/v/@astrojs/db.svg?label=%20)](packages/db/CHANGELOG.md) |
| [@astrojs/rss](packages/astro-rss) | [![@astrojs/rss version](https://img.shields.io/npm/v/@astrojs/rss.svg?label=%20)](packages/astro-rss/CHANGELOG.md) |
+| [@astrojs/netlify](https://github.com/withastro/adapters/blob/main/packages/netlify) | [![@astrojs/netlify version](https://img.shields.io/npm/v/@astrojs/netlify.svg?label=%20)](https://github.com/withastro/adapters/blob/main/packages/netlify/CHANGELOG.md) |
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6178/badge)](https://bestpractices.coreinfrastructure.org/projects/6178)
diff --git a/biome.json b/biome.json
index 2928e8f4f..67e2a4620 100644
--- a/biome.json
+++ b/biome.json
@@ -26,7 +26,15 @@
"organizeImports": {
"enabled": true
},
- "linter": { "enabled": false },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": false,
+ "style": {
+ "useNodejsImportProtocol": "error"
+ }
+ }
+ },
"javascript": {
"formatter": {
"trailingCommas": "all",
diff --git a/examples/basics/package.json b/examples/basics/package.json
index 02e40cb4c..be4bf81ad 100644
--- a/examples/basics/package.json
+++ b/examples/basics/package.json
@@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/blog/package.json b/examples/blog/package.json
index 667fceb41..2b248d3a8 100644
--- a/examples/blog/package.json
+++ b/examples/blog/package.json
@@ -14,6 +14,6 @@
"@astrojs/mdx": "^3.1.3",
"@astrojs/rss": "^4.0.7",
"@astrojs/sitemap": "^3.1.6",
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/component/package.json b/examples/component/package.json
index 6e4ce727e..3d2e2bead 100644
--- a/examples/component/package.json
+++ b/examples/component/package.json
@@ -15,7 +15,7 @@
],
"scripts": {},
"devDependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
},
"peerDependencies": {
"astro": "^4.0.0"
diff --git a/examples/container-with-vitest/package.json b/examples/container-with-vitest/package.json
index 7bddf6df4..1c6732340 100644
--- a/examples/container-with-vitest/package.json
+++ b/examples/container-with-vitest/package.json
@@ -12,7 +12,7 @@
"test": "vitest run"
},
"dependencies": {
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"@astrojs/react": "^3.6.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/examples/framework-alpine/package.json b/examples/framework-alpine/package.json
index 0de84cbbe..03cfff656 100644
--- a/examples/framework-alpine/package.json
+++ b/examples/framework-alpine/package.json
@@ -14,6 +14,6 @@
"@astrojs/alpinejs": "^0.4.0",
"@types/alpinejs": "^3.13.10",
"alpinejs": "^3.14.1",
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/framework-lit/package.json b/examples/framework-lit/package.json
index 638a28be0..cdb7d272a 100644
--- a/examples/framework-lit/package.json
+++ b/examples/framework-lit/package.json
@@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/lit": "^4.3.0",
"@webcomponents/template-shadowroot": "^0.2.1",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"lit": "^3.2.0"
}
}
diff --git a/examples/framework-multiple/package.json b/examples/framework-multiple/package.json
index 800f0b0b6..626962d02 100644
--- a/examples/framework-multiple/package.json
+++ b/examples/framework-multiple/package.json
@@ -18,7 +18,7 @@
"@astrojs/vue": "^4.5.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"preact": "^10.23.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/examples/framework-preact/package.json b/examples/framework-preact/package.json
index 42cf975fc..d7169d6cc 100644
--- a/examples/framework-preact/package.json
+++ b/examples/framework-preact/package.json
@@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/preact": "^3.5.1",
"@preact/signals": "^1.3.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"preact": "^10.23.1"
}
}
diff --git a/examples/framework-react/package.json b/examples/framework-react/package.json
index 8228bf556..4fbde09c6 100644
--- a/examples/framework-react/package.json
+++ b/examples/framework-react/package.json
@@ -14,7 +14,7 @@
"@astrojs/react": "^3.6.2",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
diff --git a/examples/framework-solid/package.json b/examples/framework-solid/package.json
index 5152ce823..cc583f052 100644
--- a/examples/framework-solid/package.json
+++ b/examples/framework-solid/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/solid-js": "^4.4.1",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"solid-js": "^1.8.20"
}
}
diff --git a/examples/framework-svelte/package.json b/examples/framework-svelte/package.json
index cc89304bb..42a99cd24 100644
--- a/examples/framework-svelte/package.json
+++ b/examples/framework-svelte/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/svelte": "^5.7.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"svelte": "^4.2.18"
}
}
diff --git a/examples/framework-vue/package.json b/examples/framework-vue/package.json
index 3cd8d2325..1bff3df25 100644
--- a/examples/framework-vue/package.json
+++ b/examples/framework-vue/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/vue": "^4.5.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"vue": "^3.4.37"
}
}
diff --git a/examples/hackernews/package.json b/examples/hackernews/package.json
index 836cb8486..bc5ee46b2 100644
--- a/examples/hackernews/package.json
+++ b/examples/hackernews/package.json
@@ -12,6 +12,6 @@
},
"dependencies": {
"@astrojs/node": "^8.3.3",
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/integration/package.json b/examples/integration/package.json
index 044510712..d8225462a 100644
--- a/examples/integration/package.json
+++ b/examples/integration/package.json
@@ -15,7 +15,7 @@
],
"scripts": {},
"devDependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
},
"peerDependencies": {
"astro": "^4.0.0"
diff --git a/examples/middleware/package.json b/examples/middleware/package.json
index b86e1b311..db80ba2fe 100644
--- a/examples/middleware/package.json
+++ b/examples/middleware/package.json
@@ -13,7 +13,7 @@
},
"dependencies": {
"@astrojs/node": "^8.3.3",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"html-minifier": "^4.0.0"
},
"devDependencies": {
diff --git a/examples/minimal/package.json b/examples/minimal/package.json
index a2892c7e4..129a0e1c6 100644
--- a/examples/minimal/package.json
+++ b/examples/minimal/package.json
@@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/non-html-pages/package.json b/examples/non-html-pages/package.json
index a6dc53a80..14750d841 100644
--- a/examples/non-html-pages/package.json
+++ b/examples/non-html-pages/package.json
@@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/portfolio/package.json b/examples/portfolio/package.json
index 1e2b79ea0..22e75e141 100644
--- a/examples/portfolio/package.json
+++ b/examples/portfolio/package.json
@@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/server-islands/package.json b/examples/server-islands/package.json
index 3a1ae97fb..a3bf73294 100644
--- a/examples/server-islands/package.json
+++ b/examples/server-islands/package.json
@@ -17,7 +17,7 @@
"@tailwindcss/forms": "^0.5.7",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"postcss": "^8.4.41",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/examples/ssr/package.json b/examples/ssr/package.json
index 10703eb9d..d35df0ec4 100644
--- a/examples/ssr/package.json
+++ b/examples/ssr/package.json
@@ -14,7 +14,7 @@
"dependencies": {
"@astrojs/node": "^8.3.3",
"@astrojs/svelte": "^5.7.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"svelte": "^4.2.18"
}
}
diff --git a/examples/starlog/package.json b/examples/starlog/package.json
index 33e546e77..905df4a69 100644
--- a/examples/starlog/package.json
+++ b/examples/starlog/package.json
@@ -10,7 +10,7 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"sass": "^1.77.8",
"sharp": "^0.33.3"
}
diff --git a/examples/toolbar-app/package.json b/examples/toolbar-app/package.json
index 6f147be74..d08c29bca 100644
--- a/examples/toolbar-app/package.json
+++ b/examples/toolbar-app/package.json
@@ -15,6 +15,6 @@
"./app": "./dist/app.js"
},
"devDependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/view-transitions/package.json b/examples/view-transitions/package.json
index 6328e7665..7448b9ec0 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.3.3",
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/with-markdoc/package.json b/examples/with-markdoc/package.json
index dcf8596bd..1af3bc63c 100644
--- a/examples/with-markdoc/package.json
+++ b/examples/with-markdoc/package.json
@@ -12,6 +12,6 @@
},
"dependencies": {
"@astrojs/markdoc": "^0.11.3",
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/with-markdown-plugins/package.json b/examples/with-markdown-plugins/package.json
index 407130b83..61f125345 100644
--- a/examples/with-markdown-plugins/package.json
+++ b/examples/with-markdown-plugins/package.json
@@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/markdown-remark": "^5.2.0",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"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 8a32a5f36..e1486a376 100644
--- a/examples/with-markdown-shiki/package.json
+++ b/examples/with-markdown-shiki/package.json
@@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
- "astro": "^4.13.4"
+ "astro": "^4.14.2"
}
}
diff --git a/examples/with-mdx/package.json b/examples/with-mdx/package.json
index 8782c588c..934959975 100644
--- a/examples/with-mdx/package.json
+++ b/examples/with-mdx/package.json
@@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/mdx": "^3.1.3",
"@astrojs/preact": "^3.5.1",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"preact": "^10.23.1"
}
}
diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json
index 2c73ab734..b8db777b4 100644
--- a/examples/with-nanostores/package.json
+++ b/examples/with-nanostores/package.json
@@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/preact": "^3.5.1",
"@nanostores/preact": "^0.5.2",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"nanostores": "^0.11.2",
"preact": "^10.23.1"
}
diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json
index 16cb073c7..80ba691d8 100644
--- a/examples/with-tailwindcss/package.json
+++ b/examples/with-tailwindcss/package.json
@@ -14,7 +14,7 @@
"@astrojs/mdx": "^3.1.3",
"@astrojs/tailwind": "^5.1.0",
"@types/canvas-confetti": "^1.6.4",
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"autoprefixer": "^10.4.20",
"canvas-confetti": "^1.9.3",
"postcss": "^8.4.41",
diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json
index 2bc1e2d03..88956a94e 100644
--- a/examples/with-vitest/package.json
+++ b/examples/with-vitest/package.json
@@ -12,7 +12,7 @@
"test": "vitest"
},
"dependencies": {
- "astro": "^4.13.4",
+ "astro": "^4.14.2",
"vitest": "^2.0.5"
}
}
diff --git a/package.json b/package.json
index 5f2eb056c..850816b5e 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"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",
+ "lint": "biome lint && eslint . --report-unused-disable-directives",
"version": "changeset version && node ./scripts/deps/update-example-versions.js && pnpm install --no-frozen-lockfile && pnpm run format",
"preinstall": "npx only-allow pnpm"
},
@@ -65,7 +65,7 @@
"only-allow": "^1.2.1",
"prettier": "^3.3.3",
"prettier-plugin-astro": "^0.14.1",
- "turbo": "^1.13.4",
+ "turbo": "^2.0.12",
"typescript": "~5.5.4",
"typescript-eslint": "^8.0.1"
},
diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md
index 9db8916b2..5c93709a4 100644
--- a/packages/astro/CHANGELOG.md
+++ b/packages/astro/CHANGELOG.md
@@ -1,5 +1,245 @@
# astro
+## 4.14.2
+
+### Patch Changes
+
+- [#11733](https://github.com/withastro/astro/pull/11733) [`391324d`](https://github.com/withastro/astro/commit/391324df969db71d1c7ca25c2ed14c9eb6eea5ee) Thanks [@bluwy](https://github.com/bluwy)! - Reverts back to `yargs-parser` package for CLI argument parsing
+
+## 4.14.1
+
+### Patch Changes
+
+- [#11725](https://github.com/withastro/astro/pull/11725) [`6c1560f`](https://github.com/withastro/astro/commit/6c1560fb0d19ce659bc9f9090f8050254d5c03f3) Thanks [@ascorbic](https://github.com/ascorbic)! - Prevents content layer importing node builtins in runtime
+
+- [#11692](https://github.com/withastro/astro/pull/11692) [`35af73a`](https://github.com/withastro/astro/commit/35af73aace97a7cc898b9aa5040db8bc2ac62687) Thanks [@matthewp](https://github.com/matthewp)! - Prevent errant HTML from crashing server islands
+
+ When an HTML minifier strips away the server island comment, the script can't correctly know where the end of the fallback content is. This makes it so that it simply doesn't remove any DOM in that scenario. This means the fallback isn't removed, but it also doesn't crash the browser.
+
+- [#11727](https://github.com/withastro/astro/pull/11727) [`3c2f93b`](https://github.com/withastro/astro/commit/3c2f93b66c6b8e9d2ab58e2cbe941c14ffab89b5) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Fixes a type issue when using the Content Layer in dev
+
+## 4.14.0
+
+### Minor Changes
+
+- [#11657](https://github.com/withastro/astro/pull/11657) [`a23c69d`](https://github.com/withastro/astro/commit/a23c69d0d0bed229bee52a32e61f135f9ebf9122) Thanks [@bluwy](https://github.com/bluwy)! - Deprecates the option for route-generating files to export a dynamic value for `prerender`. Only static values are now supported (e.g. `export const prerender = true` or `= false`). This allows for better treeshaking and bundling configuration in the future.
+
+ Adds a new [`"astro:route:setup"` hook](https://docs.astro.build/en/reference/integrations-reference/#astroroutesetup) to the Integrations API to allow you to dynamically set options for a route at build or request time through an integration, such as enabling [on-demand server rendering](https://docs.astro.build/en/guides/server-side-rendering/#opting-in-to-pre-rendering-in-server-mode).
+
+ To migrate from a dynamic export to the new hook, update or remove any dynamic `prerender` exports from individual routing files:
+
+ ```diff
+ // src/pages/blog/[slug].astro
+ - export const prerender = import.meta.env.PRERENDER
+ ```
+
+ Instead, create an integration with the `"astro:route:setup"` hook and update the route's `prerender` option:
+
+ ```js
+ // astro.config.mjs
+ import { defineConfig } from 'astro/config';
+ import { loadEnv } from 'vite';
+
+ export default defineConfig({
+ integrations: [setPrerender()],
+ });
+
+ function setPrerender() {
+ const { PRERENDER } = loadEnv(process.env.NODE_ENV, process.cwd(), '');
+
+ return {
+ name: 'set-prerender',
+ hooks: {
+ 'astro:route:setup': ({ route }) => {
+ if (route.component.endsWith('/blog/[slug].astro')) {
+ route.prerender = PRERENDER;
+ }
+ },
+ },
+ };
+ }
+ ```
+
+- [#11360](https://github.com/withastro/astro/pull/11360) [`a79a8b0`](https://github.com/withastro/astro/commit/a79a8b0230b06ed32ce1802f2a5f84a6cf92dbe7) Thanks [@ascorbic](https://github.com/ascorbic)! - Adds a new [`injectTypes()` utility](https://docs.astro.build/en/reference/integrations-reference/#injecttypes-options) to the Integration API and refactors how type generation works
+
+ Use `injectTypes()` in the `astro:config:done` hook to inject types into your user's project by adding a new a `*.d.ts` file.
+
+ The `filename` property will be used to generate a file at `/.astro/integrations/<normalized_integration_name>/<normalized_filename>.d.ts` and must end with `".d.ts"`.
+
+ The `content` property will create the body of the file, and must be valid TypeScript.
+
+ Additionally, `injectTypes()` returns a URL to the normalized path so you can overwrite its content later on, or manipulate it in any way you want.
+
+ ```js
+ // my-integration/index.js
+ export default {
+ name: 'my-integration',
+ 'astro:config:done': ({ injectTypes }) => {
+ injectTypes({
+ filename: 'types.d.ts',
+ content: "declare module 'virtual:my-integration' {}",
+ });
+ },
+ };
+ ```
+
+ Codegen has been refactored. Although `src/env.d.ts` will continue to work as is, we recommend you update it:
+
+ ```diff
+ - /// <reference types="astro/client" />
+ + /// <reference path="../.astro/types.d.ts" />
+ - /// <reference path="../.astro/env.d.ts" />
+ - /// <reference path="../.astro/actions.d.ts" />
+ ```
+
+- [#11605](https://github.com/withastro/astro/pull/11605) [`d3d99fb`](https://github.com/withastro/astro/commit/d3d99fba269da9e812e748539a11dfed785ef8a4) Thanks [@jcayzac](https://github.com/jcayzac)! - Adds a new property `meta` to Astro's [built-in `<Code />` component](https://docs.astro.build/en/reference/api-reference/#code-).
+
+ This allows you to provide a value for [Shiki's `meta` attribute](https://shiki.style/guide/transformers#meta) to pass options to transformers.
+
+ The following example passes an option to highlight lines 1 and 3 to Shiki's `tranformerMetaHighlight`:
+
+ ```astro
+ ---
+ // src/components/Card.astro
+ import { Code } from 'astro:components';
+ import { transformerMetaHighlight } from '@shikijs/transformers';
+ ---
+
+ <Code code={code} lang="js" transformers={[transformerMetaHighlight()]} meta="{1,3}" />
+ ```
+
+- [#11360](https://github.com/withastro/astro/pull/11360) [`a79a8b0`](https://github.com/withastro/astro/commit/a79a8b0230b06ed32ce1802f2a5f84a6cf92dbe7) Thanks [@ascorbic](https://github.com/ascorbic)! - Adds support for Intellisense features (e.g. code completion, quick hints) for your content collection entries in compatible editors under the `experimental.contentIntellisense` flag.
+
+ ```js
+ import { defineConfig } from 'astro';
+
+ export default defineConfig({
+ experimental: {
+ contentIntellisense: true,
+ },
+ });
+ ```
+
+ When enabled, this feature will generate and add JSON schemas to the `.astro` directory in your project. These files can be used by the Astro language server to provide Intellisense inside content files (`.md`, `.mdx`, `.mdoc`).
+
+ Note that at this time, this also require enabling the `astro.content-intellisense` option in your editor, or passing the `contentIntellisense: true` initialization parameter to the Astro language server for editors using it directly.
+
+ See the [experimental content Intellisense docs](https://docs.astro.build/en/reference/configuration-reference/#experimentalcontentintellisense) for more information updates as this feature develops.
+
+- [#11360](https://github.com/withastro/astro/pull/11360) [`a79a8b0`](https://github.com/withastro/astro/commit/a79a8b0230b06ed32ce1802f2a5f84a6cf92dbe7) Thanks [@ascorbic](https://github.com/ascorbic)! - Adds experimental support for the Content Layer API.
+
+ The new Content Layer API builds upon content collections, taking them beyond local files in `src/content/` and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. There are significant improvements to performance with large collections of local files.
+
+ ### Getting started
+
+ To try out the new Content Layer API, enable it in your Astro config:
+
+ ```js
+ import { defineConfig } from 'astro';
+
+ export default defineConfig({
+ experimental: {
+ contentLayer: true,
+ },
+ });
+ ```
+
+ You can then create collections in your `src/content/config.ts` using the Content Layer API.
+
+ ### Loading your content
+
+ The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in `glob()` and `file()` loaders to handle your local Markdown, MDX, Markdoc, and JSON files:
+
+ ```ts {3,7}
+ // src/content/config.ts
+ import { defineCollection, z } from 'astro:content';
+ import { glob } from 'astro/loaders';
+
+ const blog = defineCollection({
+ // The ID is a slug generated from the path of the file relative to `base`
+ loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),
+ schema: z.object({
+ title: z.string(),
+ description: z.string(),
+ publishDate: z.coerce.date(),
+ }),
+ });
+
+ export const collections = { blog };
+ ```
+
+ You can then query using the existing content collections functions, and enjoy a simplified `render()` function to display your content:
+
+ ```astro
+ ---
+ import { getEntry, render } from 'astro:content';
+
+ const post = await getEntry('blog', Astro.params.slug);
+
+ const { Content } = await render(entry);
+ ---
+
+ <Content />
+ ```
+
+ ### Creating a loader
+
+ You're not restricted to the built-in loaders – we hope you'll try building your own. You can fetch content from anywhere and return an array of entries:
+
+ ```ts
+ // src/content/config.ts
+ const countries = defineCollection({
+ loader: async () => {
+ const response = await fetch('https://restcountries.com/v3.1/all');
+ const data = await response.json();
+ // Must return an array of entries with an id property,
+ // or an object with IDs as keys and entries as values
+ return data.map((country) => ({
+ id: country.cca3,
+ ...country,
+ }));
+ },
+ // optionally add a schema to validate the data and make it type-safe for users
+ // schema: z.object...
+ });
+
+ export const collections = { countries };
+ ```
+
+ For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders) for more details.
+
+ ### Sharing your loaders
+
+ Loaders are better when they're shared. You can create a package that exports a loader and publish it to npm, and then anyone can use it on their site. We're excited to see what the community comes up with! To get started, [take a look at some examples](https://github.com/ascorbic/astro-loaders/). Here's how to load content using an RSS/Atom feed loader:
+
+ ```ts
+ // src/content/config.ts
+ import { defineCollection } from 'astro:content';
+ import { feedLoader } from '@ascorbic/feed-loader';
+
+ const podcasts = defineCollection({
+ loader: feedLoader({
+ url: 'https://feeds.99percentinvisible.org/99percentinvisible',
+ }),
+ });
+
+ export const collections = { podcasts };
+ ```
+
+ ### Learn more
+
+ To find out more about using the Content Layer API, check out [the Content Layer RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md) and [share your feedback](https://github.com/withastro/roadmap/pull/982).
+
+### Patch Changes
+
+- [#11716](https://github.com/withastro/astro/pull/11716) [`f4057c1`](https://github.com/withastro/astro/commit/f4057c18c91f969e3e508545fb988aff94c3ff08) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Fixes content types sync in dev
+
+- [#11645](https://github.com/withastro/astro/pull/11645) [`849e4c6`](https://github.com/withastro/astro/commit/849e4c6c23e61f7fa59f583419048b998bef2475) Thanks [@bluwy](https://github.com/bluwy)! - Refactors internally to use `node:util` `parseArgs` instead of `yargs-parser`
+
+- [#11712](https://github.com/withastro/astro/pull/11712) [`791d809`](https://github.com/withastro/astro/commit/791d809cbc22ed30dda1195ca026daa46a54b551) Thanks [@matthewp](https://github.com/matthewp)! - Fix mixed use of base + trailingSlash in Server Islands
+
+- [#11709](https://github.com/withastro/astro/pull/11709) [`3d8ae76`](https://github.com/withastro/astro/commit/3d8ae767fd4952af7332542b58fe98886eb2e99e) Thanks [@matthewp](https://github.com/matthewp)! - Fix adapter causing Netlify to break
+
## 4.13.4
### Patch Changes
diff --git a/packages/astro/e2e/fixtures/server-islands/astro.config.mjs b/packages/astro/e2e/fixtures/server-islands/astro.config.mjs
index 4bec97b9e..2175a1bf8 100644
--- a/packages/astro/e2e/fixtures/server-islands/astro.config.mjs
+++ b/packages/astro/e2e/fixtures/server-islands/astro.config.mjs
@@ -9,7 +9,7 @@ export default defineConfig({
output: 'hybrid',
adapter: nodejs({ mode: 'standalone' }),
integrations: [react(), mdx()],
- trailingSlash: 'always',
+ trailingSlash: process.env.TRAILING_SLASH ?? 'always',
experimental: {
serverIslands: true,
}
diff --git a/packages/astro/e2e/fixtures/server-islands/src/components/HTMLError.astro b/packages/astro/e2e/fixtures/server-islands/src/components/HTMLError.astro
new file mode 100644
index 000000000..91b194653
--- /dev/null
+++ b/packages/astro/e2e/fixtures/server-islands/src/components/HTMLError.astro
@@ -0,0 +1 @@
+<div id="first"></div>
diff --git a/packages/astro/e2e/fixtures/server-islands/src/pages/index.astro b/packages/astro/e2e/fixtures/server-islands/src/pages/index.astro
index de9a6c456..eff5df25e 100644
--- a/packages/astro/e2e/fixtures/server-islands/src/pages/index.astro
+++ b/packages/astro/e2e/fixtures/server-islands/src/pages/index.astro
@@ -1,6 +1,7 @@
---
import Island from '../components/Island.astro';
import Self from '../components/Self.astro';
+import HTMLError from '../components/HTMLError.astro';
---
<html>
@@ -12,5 +13,16 @@ import Self from '../components/Self.astro';
<h3 id="children">children</h3>
</Island>
<Self server:defer />
+
+ <div id="error-test">
+ <HTMLError server:defer>
+ <script is:inline slot="fallback">
+ // Delete the previous element, the island comment
+ document.currentScript.previousSibling.remove();
+
+ // This simulates a host which has minified the HTML, destroying the comment
+ </script>
+ </HTMLError>
+ </div>
</body>
</html>
diff --git a/packages/astro/e2e/server-islands.test.js b/packages/astro/e2e/server-islands.test.js
index b37495b28..496cf229c 100644
--- a/packages/astro/e2e/server-islands.test.js
+++ b/packages/astro/e2e/server-islands.test.js
@@ -50,8 +50,37 @@ test.describe('Server islands', () => {
await expect(el).toHaveCount(2);
});
+
+ test("Missing server island start comment doesn't cause browser to lock up", async ({
+ page,
+ astro,
+ }) => {
+ await page.goto(astro.resolveUrl('/base/'));
+ let el = page.locator('#first');
+ await expect(el).toHaveCount(1);
+ });
});
+ test.describe('Development - trailingSlash: ignore', () => {
+ let devServer;
+
+ test.beforeAll(async ({ astro }) => {
+ process.env.TRAILING_SLASH = 'ignore';
+ devServer = await astro.startDevServer();
+ });
+
+ test.afterAll(async () => {
+ await devServer.stop();
+ });
+
+ test('Load content from the server', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/base/'));
+ let el = page.locator('#island');
+
+ await expect(el, 'element rendered').toBeVisible();
+ await expect(el, 'should have content').toHaveText('I am an island');
+ });
+ });
test.describe('Production', () => {
let previewServer;
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 31591eb29..9fac8c9b7 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -1,6 +1,6 @@
{
"name": "astro",
- "version": "4.13.4",
+ "version": "4.14.2",
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
"type": "module",
"author": "withastro",
@@ -133,8 +133,8 @@
"@babel/plugin-transform-react-jsx": "^7.25.2",
"@babel/traverse": "^7.25.3",
"@babel/types": "^7.25.2",
- "@rollup/pluginutils": "^5.1.0",
"@oslojs/encoding": "^0.4.1",
+ "@rollup/pluginutils": "^5.1.0",
"@types/babel__core": "^7.20.5",
"@types/cookie": "^0.6.0",
"acorn": "^8.12.1",
@@ -186,6 +186,7 @@
"vitefu": "^0.2.5",
"which-pm": "^3.0.0",
"xxhash-wasm": "^1.0.2",
+ "yargs-parser": "^21.1.1",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.2",
"zod-to-ts": "^1.2.0"
@@ -212,6 +213,7 @@
"@types/micromatch": "^4.0.9",
"@types/prompts": "^2.4.9",
"@types/semver": "^7.5.8",
+ "@types/yargs-parser": "^21.0.3",
"astro-scripts": "workspace:*",
"cheerio": "1.0.0",
"eol": "^0.9.1",
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 2cf416060..a10ad5126 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -1,3 +1,5 @@
+import type { OutgoingHttpHeaders } from 'node:http';
+import type { AddressInfo } from 'node:net';
import type {
MarkdownHeading,
MarkdownVFile,
@@ -7,8 +9,6 @@ import type {
ShikiConfig,
} from '@astrojs/markdown-remark';
import type * as babel from '@babel/core';
-import type { OutgoingHttpHeaders } from 'node:http';
-import type { AddressInfo } from 'node:net';
import type * as rollup from 'rollup';
import type * as vite from 'vite';
import type {
@@ -2220,7 +2220,7 @@ export interface AstroUserConfig {
*
* The Content Layer API is a new way to handle content and data in Astro. It is similar to and builds upon [content collections](/en/guides/content-collections/), taking them beyond local files in `src/content/` and allowing you to fetch content from anywhere, including remote APIs, by adding a `loader` to your collection.
*
- * Your existing content collections can be [migrated to the Content Layer API](#migrating-a-content-collection-to-content-layer) with a few small changes. However, it is not necessary to update all your collections at once to add a new collection powered by the Content Layer API. You may have collections using both the existing and new APIs defined in `src/content/config.ts` at the same time.
+ * Your existing content collections can be [migrated to the Content Layer API](#migrating-an-existing-content-collection-to-use-the-content-layer-api) with a few small changes. However, it is not necessary to update all your collections at once to add a new collection powered by the Content Layer API. You may have collections using both the existing and new APIs defined in `src/content/config.ts` at the same time.
*
* The Content Layer API is designed to be more powerful and more performant, helping sites scale to thousands of pages. Data is cached between builds and updated incrementally. Markdown parsing is also 5-10 times faster, with similar scale reductions in memory, and MDX is 2-3 times faster.
*
@@ -2237,7 +2237,7 @@ export interface AstroUserConfig {
*
* #### Fetching data with a `loader`
*
- * The Content Layer API allows you to fetch your content from outside of the `src/content/` folder (whether stored locally in your project or remotely), and uses a `loader` property to retrieve your data.
+ * The Content Layer API allows you to fetch your content from outside of the `src/content/` folder (whether stored locally in your project or remotely) and uses a `loader` property to retrieve your data.
*
* The `loader` is defined in the collection's schema and returns an array of entries. Astro provides two built-in loader functions (`glob()` and `file()`) for fetching your local content, as well as access to the API to [construct your own loader and fetch remote data](#creating-a-loader).
*
@@ -2261,7 +2261,7 @@ export interface AstroUserConfig {
* updatedDate: z.coerce.date().optional(),
* })
* });
- *
+ *
* const dogs = defineCollection({
* // The path is relative to the project root, or an absolute path.
* loader: file("src/data/dogs.json"),
@@ -2292,10 +2292,10 @@ export interface AstroUserConfig {
* const labradorData = await getEntry('dogs', 'labrador-retriever');
* ```
*
- * Entries generated from Markdown, MDX or Markdoc can be rendered directly to a page using the `render()` function.
+ * Entries generated from Markdown, MDX, or Markdoc can be rendered directly to a page using the `render()` function.
*
* :::note
- * The syntax for rendering collection entries is different from current content collections syntax.
+ * The syntax for rendering collection entries is different from the current content collections syntax.
* :::
*
* ```astro title="src/pages/[slug].astro"
@@ -2336,7 +2336,7 @@ export interface AstroUserConfig {
* export const collections = { countries };
* ```
*
- * For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. See the API in [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders).
+ * For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading while also giving full access to the data store. See the API in [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders).
*
* #### Migrating an existing content collection to use the Content Layer API
*
@@ -2348,15 +2348,15 @@ export interface AstroUserConfig {
*
* 2. **Edit the collection definition**. Your updated collection requires a `loader`, and the option to select a collection `type` is no longer available.
*
- * ```diff
+ * ```ts ins={3,8} del={7}
* // src/content/config.ts
* import { defineCollection, z } from 'astro:content';
- * + import { glob } from 'astro/loaders';
+ * import { glob } from 'astro/loaders';
*
* const blog = defineCollection({
* // For content layer you no longer define a `type`
- * - type: 'content',
- * + loader: glob({ pattern: "**\/*.md", base: "./src/data/blog" }),
+ * type: 'content',
+ * loader: glob({ pattern: "**\/*.md", base: "./src/data/blog" }),
* schema: z.object({
* title: z.string(),
* description: z.string(),
@@ -2368,14 +2368,14 @@ export interface AstroUserConfig {
*
* 3. **Change references from `slug` to `id`**. Content layer collections do not have a `slug` field. Instead, all updated collections will have an `id`.
*
- * ```diff
+ * ```astro ins={7} del={6}
* // src/pages/index.astro
* ---
* export async function getStaticPaths() {
* const posts = await getCollection('blog');
* return posts.map((post) => ({
- * - params: { slug: post.slug },
- * + params: { slug: post.id },
+ * params: { slug: post.slug },
+ * params: { slug: post.id },
* props: post,
* }));
* }
@@ -2384,16 +2384,16 @@ export interface AstroUserConfig {
*
* 4. **Switch to the new `render()` function**. Entries no longer have a `render()` method, as they are now serializable plain objects. Instead, import the `render()` function from `astro:content`.
*
- * ```diff
+ * ```astro ins={4,9} del={3,8}
* // src/pages/index.astro
* ---
- * - import { getEntry } from 'astro:content';
- * + import { getEntry, render } from 'astro:content';
+ * import { getEntry } from 'astro:content';
+ * import { getEntry, render } from 'astro:content';
*
* const post = await getEntry('blog', params.slug);
*
- * - const { Content, headings } = await post.render();
- * + const { Content, headings } = await render(post);
+ * const { Content, headings } = await post.render();
+ * const { Content, headings } = await render(post);
* ---
*
* <Content />
diff --git a/packages/astro/src/assets/endpoint/node.ts b/packages/astro/src/assets/endpoint/node.ts
index 4c50fe95f..cb3ae7806 100644
--- a/packages/astro/src/assets/endpoint/node.ts
+++ b/packages/astro/src/assets/endpoint/node.ts
@@ -1,3 +1,4 @@
+import { readFile } from 'node:fs/promises';
/* eslint-disable no-console */
import os from 'node:os';
import { isAbsolute } from 'node:path';
@@ -5,7 +6,6 @@ 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 * as mime from 'mrmime';
import type { APIRoute } from '../../@types/astro.js';
import { getConfiguredImageService } from '../internal.js';
diff --git a/packages/astro/src/cli/check/index.ts b/packages/astro/src/cli/check/index.ts
index 9a354c8e0..c93e3b2f4 100644
--- a/packages/astro/src/cli/check/index.ts
+++ b/packages/astro/src/cli/check/index.ts
@@ -8,7 +8,7 @@ export async function check(flags: Flags) {
const logger = createLoggerFromFlags(flags);
const getPackageOpts = {
skipAsk: !!flags.yes || !!flags.y,
- cwd: typeof flags.root == 'string' ? flags.root : undefined,
+ cwd: flags.root,
};
const checkPackage = await getPackage<typeof import('@astrojs/check')>(
'@astrojs/check',
diff --git a/packages/astro/src/cli/db/index.ts b/packages/astro/src/cli/db/index.ts
index c6be7411b..ae97e498f 100644
--- a/packages/astro/src/cli/db/index.ts
+++ b/packages/astro/src/cli/db/index.ts
@@ -1,25 +1,20 @@
+import type { Arguments } from 'yargs-parser';
import type { AstroConfig } from '../../@types/astro.js';
import { resolveConfig } from '../../core/config/config.js';
import { apply as applyPolyfill } from '../../core/polyfill.js';
-import { type Flags, createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js';
+import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js';
import { getPackage } from '../install-package.js';
-interface YargsArguments {
- _: Array<string | number>;
- '--'?: Array<string | number>;
- [argName: string]: any;
-}
-
type DBPackage = {
- cli: (args: { flags: YargsArguments; config: AstroConfig }) => unknown;
+ cli: (args: { flags: Arguments; config: AstroConfig }) => unknown;
};
-export async function db({ positionals, flags }: { positionals: string[]; flags: Flags }) {
+export async function db({ flags }: { flags: Arguments }) {
applyPolyfill();
const logger = createLoggerFromFlags(flags);
const getPackageOpts = {
skipAsk: !!flags.yes || !!flags.y,
- cwd: typeof flags.root == 'string' ? flags.root : undefined,
+ cwd: flags.root,
};
const dbPackage = await getPackage<DBPackage>('@astrojs/db', logger, getPackageOpts, []);
@@ -35,10 +30,5 @@ export async function db({ positionals, flags }: { positionals: string[]; flags:
const inlineConfig = flagsToAstroInlineConfig(flags);
const { astroConfig } = await resolveConfig(inlineConfig, 'build');
- const yargsArgs: YargsArguments = {
- _: positionals,
- ...flags,
- };
-
- await cli({ flags: yargsArgs, config: astroConfig });
+ await cli({ flags, config: astroConfig });
}
diff --git a/packages/astro/src/cli/flags.ts b/packages/astro/src/cli/flags.ts
index 59dfbf00a..9d57c0316 100644
--- a/packages/astro/src/cli/flags.ts
+++ b/packages/astro/src/cli/flags.ts
@@ -1,10 +1,10 @@
-import type { parseArgs } from 'node:util';
+import type { Arguments } from 'yargs-parser';
import type { AstroInlineConfig } from '../@types/astro.js';
import { type LogOptions, Logger } from '../core/logger/core.js';
import { nodeLogDestination } from '../core/logger/node.js';
-export type ParsedArgsResult = ReturnType<typeof parseArgs>;
-export type Flags = ParsedArgsResult['values'];
+// Alias for now, but allows easier migration to node's `parseArgs` in the future.
+export type Flags = Arguments;
export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
return {
@@ -20,7 +20,7 @@ export function flagsToAstroInlineConfig(flags: Flags): AstroInlineConfig {
base: typeof flags.base === 'string' ? flags.base : undefined,
outDir: typeof flags.outDir === 'string' ? flags.outDir : undefined,
server: {
- port: typeof flags.port === 'string' ? Number(flags.port) : undefined,
+ port: typeof flags.port === 'number' ? flags.port : undefined,
host:
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
open:
diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts
index b3a819e58..c767569fd 100644
--- a/packages/astro/src/cli/index.ts
+++ b/packages/astro/src/cli/index.ts
@@ -1,8 +1,7 @@
-import { parseArgs } from 'node:util';
/* eslint-disable no-console */
import * as colors from 'kleur/colors';
+import yargs from 'yargs-parser';
import { ASTRO_VERSION } from '../core/constants.js';
-import type { ParsedArgsResult } from './flags.js';
type CLICommand =
| 'help'
@@ -66,9 +65,9 @@ function printVersion() {
}
/** Determine which command the user requested */
-function resolveCommand(args: ParsedArgsResult): CLICommand {
- const cmd = args.positionals[2] as string;
- if (args.values.version) return 'version';
+function resolveCommand(flags: yargs.Arguments): CLICommand {
+ const cmd = flags._[2] as string;
+ if (flags.version) return 'version';
const supportedCommands = new Set([
'add',
@@ -98,9 +97,7 @@ function resolveCommand(args: ParsedArgsResult): CLICommand {
* NOTE: This function provides no error handling, so be sure
* to present user-friendly error output where the fn is called.
**/
-async function runCommand(cmd: string, args: ParsedArgsResult) {
- const flags = args.values;
-
+async function runCommand(cmd: string, flags: yargs.Arguments) {
// These commands can run directly without parsing the user config.
switch (cmd) {
case 'help':
@@ -123,7 +120,7 @@ async function runCommand(cmd: string, args: ParsedArgsResult) {
// Do not track session start, since the user may be trying to enable,
// disable, or modify telemetry settings.
const { update } = await import('./telemetry/index.js');
- const subcommand = args.positionals[3];
+ const subcommand = flags._[3]?.toString();
await update(subcommand, { flags });
return;
}
@@ -134,7 +131,7 @@ async function runCommand(cmd: string, args: ParsedArgsResult) {
}
case 'preferences': {
const { preferences } = await import('./preferences/index.js');
- const [subcommand, key, value] = args.positionals.slice(3);
+ const [subcommand, key, value] = flags._.slice(3).map((v) => v.toString());
const exitCode = await preferences(subcommand, key, value, { flags });
return process.exit(exitCode);
}
@@ -154,7 +151,7 @@ async function runCommand(cmd: string, args: ParsedArgsResult) {
switch (cmd) {
case 'add': {
const { add } = await import('./add/index.js');
- const packages = args.positionals.slice(3);
+ const packages = flags._.slice(3) as string[];
await add(packages, { flags });
return;
}
@@ -164,7 +161,7 @@ async function runCommand(cmd: string, args: ParsedArgsResult) {
case 'link':
case 'init': {
const { db } = await import('./db/index.js');
- await db({ positionals: args.positionals, flags });
+ await db({ flags });
return;
}
case 'dev': {
@@ -205,20 +202,10 @@ async function runCommand(cmd: string, args: ParsedArgsResult) {
/** The primary CLI action */
export async function cli(argv: string[]) {
- const args = parseArgs({
- args: argv,
- allowPositionals: true,
- strict: false,
- options: {
- global: { type: 'boolean', short: 'g' },
- host: { type: 'string' }, // Can be boolean too, which is covered by `strict: false`
- open: { type: 'string' }, // Can be boolean too, which is covered by `strict: false`
- // TODO: Add more flags here
- },
- });
- const cmd = resolveCommand(args);
+ const flags = yargs(argv, { boolean: ['global'], alias: { g: 'global' } });
+ const cmd = resolveCommand(flags);
try {
- await runCommand(cmd, args);
+ await runCommand(cmd, flags);
} catch (err) {
const { throwAndExit } = await import('./throw-and-exit.js');
await throwAndExit(cmd, err);
diff --git a/packages/astro/src/content/content-layer.ts b/packages/astro/src/content/content-layer.ts
index 9a6d4ed37..4861f3f61 100644
--- a/packages/astro/src/content/content-layer.ts
+++ b/packages/astro/src/content/content-layer.ts
@@ -12,12 +12,12 @@ import {
DATA_STORE_FILE,
MODULES_IMPORTS_FILE,
} from './consts.js';
-import type { DataStore } from './data-store.js';
import type { LoaderContext } from './loaders/types.js';
+import type { MutableDataStore } from './mutable-data-store.js';
import { getEntryDataAndImages, globalContentConfigObserver, posixRelative } from './utils.js';
export interface ContentLayerOptions {
- store: DataStore;
+ store: MutableDataStore;
settings: AstroSettings;
logger: Logger;
watcher?: FSWatcher;
@@ -25,7 +25,7 @@ export interface ContentLayerOptions {
export class ContentLayer {
#logger: Logger;
- #store: DataStore;
+ #store: MutableDataStore;
#settings: AstroSettings;
#watcher?: FSWatcher;
#lastConfigDigest?: string;
diff --git a/packages/astro/src/content/data-store.ts b/packages/astro/src/content/data-store.ts
index f416082f9..76cefc411 100644
--- a/packages/astro/src/content/data-store.ts
+++ b/packages/astro/src/content/data-store.ts
@@ -1,11 +1,5 @@
import type { MarkdownHeading } from '@astrojs/markdown-remark';
import * as devalue from 'devalue';
-import { existsSync, promises as fs, type PathLike } from 'fs';
-import { imageSrcToImportId, importIdToSymbolName } from '../assets/utils/resolveImports.js';
-import { AstroError, AstroErrorData } from '../core/errors/index.js';
-import { CONTENT_MODULE_FLAG, DEFERRED_MODULE } from './consts.js';
-
-const SAVE_DEBOUNCE_MS = 500;
export interface RenderedContent {
/** Rendered HTML string. If present then `render(entry)` will return a component that renders this HTML. */
@@ -41,75 +35,39 @@ export interface DataEntry<TData extends Record<string, unknown> = Record<string
deferredRender?: boolean;
}
-export class DataStore {
- #collections = new Map<string, Map<string, any>>();
-
- #file?: PathLike;
-
- #assetsFile?: PathLike;
- #modulesFile?: PathLike;
-
- #saveTimeout: NodeJS.Timeout | undefined;
- #assetsSaveTimeout: NodeJS.Timeout | undefined;
- #modulesSaveTimeout: NodeJS.Timeout | undefined;
-
- #dirty = false;
- #assetsDirty = false;
- #modulesDirty = false;
+/**
+ * A read-only data store for content collections. This is used to retrieve data from the content layer at runtime.
+ * To add or modify data, use {@link MutableDataStore} instead.
+ */
- #assetImports = new Set<string>();
- #moduleImports = new Map<string, string>();
+export class DataStore {
+ protected _collections = new Map<string, Map<string, any>>();
constructor() {
- this.#collections = new Map();
+ this._collections = new Map();
}
get<T = DataEntry>(collectionName: string, key: string): T | undefined {
- return this.#collections.get(collectionName)?.get(String(key));
+ return this._collections.get(collectionName)?.get(String(key));
}
entries<T = DataEntry>(collectionName: string): Array<[id: string, T]> {
- const collection = this.#collections.get(collectionName) ?? new Map();
+ const collection = this._collections.get(collectionName) ?? new Map();
return [...collection.entries()];
}
values<T = DataEntry>(collectionName: string): Array<T> {
- const collection = this.#collections.get(collectionName) ?? new Map();
+ const collection = this._collections.get(collectionName) ?? new Map();
return [...collection.values()];
}
keys(collectionName: string): Array<string> {
- const collection = this.#collections.get(collectionName) ?? new Map();
+ const collection = this._collections.get(collectionName) ?? new Map();
return [...collection.keys()];
}
- set(collectionName: string, key: string, value: unknown) {
- const collection = this.#collections.get(collectionName) ?? new Map();
- collection.set(String(key), value);
- this.#collections.set(collectionName, collection);
- this.#saveToDiskDebounced();
- }
-
- delete(collectionName: string, key: string) {
- const collection = this.#collections.get(collectionName);
- if (collection) {
- collection.delete(String(key));
- this.#saveToDiskDebounced();
- }
- }
-
- clear(collectionName: string) {
- this.#collections.delete(collectionName);
- this.#saveToDiskDebounced();
- }
-
- clearAll() {
- this.#collections.clear();
- this.#saveToDiskDebounced();
- }
-
has(collectionName: string, key: string) {
- const collection = this.#collections.get(collectionName);
+ const collection = this._collections.get(collectionName);
if (collection) {
return collection.has(String(key));
}
@@ -117,234 +75,11 @@ export class DataStore {
}
hasCollection(collectionName: string) {
- return this.#collections.has(collectionName);
+ return this._collections.has(collectionName);
}
collections() {
- return this.#collections;
- }
-
- addAssetImport(assetImport: string, filePath: string) {
- const id = imageSrcToImportId(assetImport, filePath);
- if (id) {
- this.#assetImports.add(id);
- // We debounce the writes to disk because addAssetImport is called for every image in every file,
- // and can be called many times in quick succession by a filesystem watcher. We only want to write
- // the file once, after all the imports have been added.
- this.#writeAssetsImportsDebounced();
- }
- }
-
- addAssetImports(assets: Array<string>, filePath: string) {
- assets.forEach((asset) => this.addAssetImport(asset, filePath));
- }
-
- addModuleImport(fileName: string) {
- const id = contentModuleToId(fileName);
- if (id) {
- this.#moduleImports.set(fileName, id);
- // We debounce the writes to disk because addAssetImport is called for every image in every file,
- // and can be called many times in quick succession by a filesystem watcher. We only want to write
- // the file once, after all the imports have been added.
- this.#writeModulesImportsDebounced();
- }
- }
-
- async writeAssetImports(filePath: PathLike) {
- this.#assetsFile = filePath;
-
- if (this.#assetImports.size === 0) {
- try {
- await fs.writeFile(filePath, 'export default new Map();');
- } catch (err) {
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
- }
- }
-
- if (!this.#assetsDirty && existsSync(filePath)) {
- return;
- }
- // Import the assets, with a symbol name that is unique to the import id. The import
- // for each asset is an object with path, format and dimensions.
- // We then export them all, mapped by the import id, so we can find them again in the build.
- const imports: Array<string> = [];
- const exports: Array<string> = [];
- this.#assetImports.forEach((id) => {
- const symbol = importIdToSymbolName(id);
- imports.push(`import ${symbol} from '${id}';`);
- exports.push(`[${JSON.stringify(id)}, ${symbol}]`);
- });
- const code = /* js */ `
-${imports.join('\n')}
-export default new Map([${exports.join(', ')}]);
- `;
- try {
- await fs.writeFile(filePath, code);
- } catch (err) {
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
- }
- this.#assetsDirty = false;
- }
-
- async writeModuleImports(filePath: PathLike) {
- this.#modulesFile = filePath;
-
- if (this.#moduleImports.size === 0) {
- try {
- await fs.writeFile(filePath, 'export default new Map();');
- } catch (err) {
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
- }
- }
-
- if (!this.#modulesDirty && existsSync(filePath)) {
- return;
- }
-
- // Import the assets, with a symbol name that is unique to the import id. The import
- // for each asset is an object with path, format and dimensions.
- // We then export them all, mapped by the import id, so we can find them again in the build.
- const lines: Array<string> = [];
- for (const [fileName, specifier] of this.#moduleImports) {
- lines.push(`['${fileName}', () => import('${specifier}')]`);
- }
- const code = `
-export default new Map([\n${lines.join(',\n')}]);
- `;
- try {
- await fs.writeFile(filePath, code);
- } catch (err) {
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
- }
- this.#modulesDirty = false;
- }
-
- #writeAssetsImportsDebounced() {
- this.#assetsDirty = true;
- if (this.#assetsFile) {
- if (this.#assetsSaveTimeout) {
- clearTimeout(this.#assetsSaveTimeout);
- }
- this.#assetsSaveTimeout = setTimeout(() => {
- this.#assetsSaveTimeout = undefined;
- this.writeAssetImports(this.#assetsFile!);
- }, SAVE_DEBOUNCE_MS);
- }
- }
-
- #writeModulesImportsDebounced() {
- this.#modulesDirty = true;
- if (this.#modulesFile) {
- if (this.#modulesSaveTimeout) {
- clearTimeout(this.#modulesSaveTimeout);
- }
- this.#modulesSaveTimeout = setTimeout(() => {
- this.#modulesSaveTimeout = undefined;
- this.writeModuleImports(this.#modulesFile!);
- }, SAVE_DEBOUNCE_MS);
- }
- }
-
- #saveToDiskDebounced() {
- this.#dirty = true;
- // Only save to disk if it has already been saved once
- if (this.#file) {
- if (this.#saveTimeout) {
- clearTimeout(this.#saveTimeout);
- }
- this.#saveTimeout = setTimeout(() => {
- this.#saveTimeout = undefined;
- this.writeToDisk(this.#file!);
- }, SAVE_DEBOUNCE_MS);
- }
- }
-
- scopedStore(collectionName: string): ScopedDataStore {
- return {
- get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) =>
- this.get<DataEntry<TData>>(collectionName, key),
- entries: () => this.entries(collectionName),
- values: () => this.values(collectionName),
- keys: () => this.keys(collectionName),
- set: ({ id: key, data, body, filePath, deferredRender, digest, rendered }) => {
- if (!key) {
- throw new Error(`ID must be a non-empty string`);
- }
- const id = String(key);
- if (digest) {
- const existing = this.get<DataEntry>(collectionName, id);
- if (existing && existing.digest === digest) {
- return false;
- }
- }
- const entry: DataEntry = {
- id,
- data,
- };
- // We do it like this so we don't waste space stringifying
- // the fields if they are not set
- if (body) {
- entry.body = body;
- }
- if (filePath) {
- if (filePath.startsWith('/')) {
- throw new Error(`File path must be relative to the site root. Got: ${filePath}`);
- }
- entry.filePath = filePath;
- }
- if (digest) {
- entry.digest = digest;
- }
- if (rendered) {
- entry.rendered = rendered;
- }
- if (deferredRender) {
- entry.deferredRender = deferredRender;
- if (filePath) {
- this.addModuleImport(filePath);
- }
- }
- this.set(collectionName, id, entry);
- return true;
- },
- delete: (key: string) => this.delete(collectionName, key),
- clear: () => this.clear(collectionName),
- has: (key: string) => this.has(collectionName, key),
- addAssetImport: (assetImport: string, fileName: string) =>
- this.addAssetImport(assetImport, fileName),
- addAssetImports: (assets: Array<string>, fileName: string) =>
- this.addAssetImports(assets, fileName),
- addModuleImport: (fileName: string) => this.addModuleImport(fileName),
- };
- }
- /**
- * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
- */
- metaStore(collectionName = ':meta'): MetaStore {
- const collectionKey = `meta:${collectionName}`;
- return {
- get: (key: string) => this.get(collectionKey, key),
- set: (key: string, data: string) => this.set(collectionKey, key, data),
- delete: (key: string) => this.delete(collectionKey, key),
- has: (key: string) => this.has(collectionKey, key),
- };
- }
-
- toString() {
- return devalue.stringify(this.#collections);
- }
-
- async writeToDisk(filePath: PathLike) {
- if (!this.#dirty) {
- return;
- }
- try {
- await fs.writeFile(filePath, this.toString());
- this.#file = filePath;
- this.#dirty = false;
- } catch (err) {
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
- }
+ return this._collections;
}
/**
@@ -363,81 +98,9 @@ export default new Map([\n${lines.join(',\n')}]);
static async fromMap(data: Map<string, Map<string, any>>) {
const store = new DataStore();
- store.#collections = data;
+ store._collections = data;
return store;
}
-
- static async fromString(data: string) {
- const map = devalue.parse(data);
- return DataStore.fromMap(map);
- }
-
- static async fromFile(filePath: string | URL) {
- try {
- if (existsSync(filePath)) {
- const data = await fs.readFile(filePath, 'utf-8');
- return DataStore.fromString(data);
- }
- } catch {}
- return new DataStore();
- }
-}
-
-export interface ScopedDataStore {
- get: <TData extends Record<string, unknown> = Record<string, unknown>>(
- key: string,
- ) => DataEntry<TData> | undefined;
- entries: () => Array<[id: string, DataEntry]>;
- set: <TData extends Record<string, unknown>>(opts: {
- /** The ID of the entry. Must be unique per collection. */
- id: string;
- /** The data to store. */
- data: TData;
- /** The raw body of the content, if applicable. */
- body?: string;
- /** The file path of the content, if applicable. Relative to the site root. */
- filePath?: string;
- /** A content digest, to check if the content has changed. */
- digest?: number | string;
- /** The rendered content, if applicable. */
- rendered?: RenderedContent;
- /**
- * If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase.
- */
- deferredRender?: boolean;
- }) => boolean;
- values: () => Array<DataEntry>;
- keys: () => Array<string>;
- delete: (key: string) => void;
- clear: () => void;
- has: (key: string) => boolean;
- /**
- * @internal Adds asset imports to the store. This is used to track image imports for the build. This API is subject to change.
- */
- addAssetImports: (assets: Array<string>, fileName: string) => void;
- /**
- * @internal Adds an asset import to the store. This is used to track image imports for the build. This API is subject to change.
- */
- addAssetImport: (assetImport: string, fileName: string) => void;
- /**
- * Adds a single asset to the store. This asset will be transformed
- * by Vite, and the URL will be available in the final build.
- * @param fileName
- * @param specifier
- * @returns
- */
- addModuleImport: (fileName: string) => void;
-}
-
-/**
- * A key-value store for metadata strings. Useful for storing things like sync tokens.
- */
-
-export interface MetaStore {
- get: (key: string) => string | undefined;
- set: (key: string, value: string) => void;
- has: (key: string) => boolean;
- delete: (key: string) => void;
}
function dataStoreSingleton() {
@@ -455,13 +118,5 @@ function dataStoreSingleton() {
};
}
-// TODO: find a better place to put this image
-export function contentModuleToId(fileName: string) {
- const params = new URLSearchParams(DEFERRED_MODULE);
- params.set('fileName', fileName);
- params.set(CONTENT_MODULE_FLAG, 'true');
- return `${DEFERRED_MODULE}?${params.toString()}`;
-}
-
/** @internal */
export const globalDataStore = dataStoreSingleton();
diff --git a/packages/astro/src/content/loaders/types.ts b/packages/astro/src/content/loaders/types.ts
index f37296727..26be0495a 100644
--- a/packages/astro/src/content/loaders/types.ts
+++ b/packages/astro/src/content/loaders/types.ts
@@ -1,7 +1,7 @@
import type { FSWatcher } from 'vite';
import type { ZodSchema } from 'zod';
import type { AstroIntegrationLogger, AstroSettings } from '../../@types/astro.js';
-import type { MetaStore, ScopedDataStore } from '../data-store.js';
+import type { MetaStore, ScopedDataStore } from '../mutable-data-store.js';
export interface ParseDataOptions<TData extends Record<string, unknown>> {
/** The ID of the entry. Unique per collection */
diff --git a/packages/astro/src/content/mutable-data-store.ts b/packages/astro/src/content/mutable-data-store.ts
new file mode 100644
index 000000000..200951848
--- /dev/null
+++ b/packages/astro/src/content/mutable-data-store.ts
@@ -0,0 +1,370 @@
+import { promises as fs, type PathLike, existsSync } from 'node:fs';
+import * as devalue from 'devalue';
+import { imageSrcToImportId, importIdToSymbolName } from '../assets/utils/resolveImports.js';
+import { AstroError, AstroErrorData } from '../core/errors/index.js';
+import { type DataEntry, DataStore, type RenderedContent } from './data-store.js';
+import { contentModuleToId } from './utils.js';
+
+const SAVE_DEBOUNCE_MS = 500;
+
+/**
+ * Extends the DataStore with the ability to change entries and write them to disk.
+ * This is kept as a separate class to avoid needing node builtins at runtime, when read-only access is all that is needed.
+ */
+export class MutableDataStore extends DataStore {
+ #file?: PathLike;
+
+ #assetsFile?: PathLike;
+ #modulesFile?: PathLike;
+
+ #saveTimeout: NodeJS.Timeout | undefined;
+ #assetsSaveTimeout: NodeJS.Timeout | undefined;
+ #modulesSaveTimeout: NodeJS.Timeout | undefined;
+
+ #dirty = false;
+ #assetsDirty = false;
+ #modulesDirty = false;
+
+ #assetImports = new Set<string>();
+ #moduleImports = new Map<string, string>();
+
+ set(collectionName: string, key: string, value: unknown) {
+ const collection = this._collections.get(collectionName) ?? new Map();
+ collection.set(String(key), value);
+ this._collections.set(collectionName, collection);
+ this.#saveToDiskDebounced();
+ }
+
+ delete(collectionName: string, key: string) {
+ const collection = this._collections.get(collectionName);
+ if (collection) {
+ collection.delete(String(key));
+ this.#saveToDiskDebounced();
+ }
+ }
+
+ clear(collectionName: string) {
+ this._collections.delete(collectionName);
+ this.#saveToDiskDebounced();
+ }
+
+ clearAll() {
+ this._collections.clear();
+ this.#saveToDiskDebounced();
+ }
+
+ addAssetImport(assetImport: string, filePath: string) {
+ const id = imageSrcToImportId(assetImport, filePath);
+ if (id) {
+ this.#assetImports.add(id);
+ // We debounce the writes to disk because addAssetImport is called for every image in every file,
+ // and can be called many times in quick succession by a filesystem watcher. We only want to write
+ // the file once, after all the imports have been added.
+ this.#writeAssetsImportsDebounced();
+ }
+ }
+
+ addAssetImports(assets: Array<string>, filePath: string) {
+ assets.forEach((asset) => this.addAssetImport(asset, filePath));
+ }
+
+ addModuleImport(fileName: string) {
+ const id = contentModuleToId(fileName);
+ if (id) {
+ this.#moduleImports.set(fileName, id);
+ // We debounce the writes to disk because addAssetImport is called for every image in every file,
+ // and can be called many times in quick succession by a filesystem watcher. We only want to write
+ // the file once, after all the imports have been added.
+ this.#writeModulesImportsDebounced();
+ }
+ }
+
+ async writeAssetImports(filePath: PathLike) {
+ this.#assetsFile = filePath;
+
+ if (this.#assetImports.size === 0) {
+ try {
+ await fs.writeFile(filePath, 'export default new Map();');
+ } catch (err) {
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
+ }
+ }
+
+ if (!this.#assetsDirty && existsSync(filePath)) {
+ return;
+ }
+ // Import the assets, with a symbol name that is unique to the import id. The import
+ // for each asset is an object with path, format and dimensions.
+ // We then export them all, mapped by the import id, so we can find them again in the build.
+ const imports: Array<string> = [];
+ const exports: Array<string> = [];
+ this.#assetImports.forEach((id) => {
+ const symbol = importIdToSymbolName(id);
+ imports.push(`import ${symbol} from '${id}';`);
+ exports.push(`[${JSON.stringify(id)}, ${symbol}]`);
+ });
+ const code = /* js */ `
+${imports.join('\n')}
+export default new Map([${exports.join(', ')}]);
+ `;
+ try {
+ await fs.writeFile(filePath, code);
+ } catch (err) {
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
+ }
+ this.#assetsDirty = false;
+ }
+
+ async writeModuleImports(filePath: PathLike) {
+ this.#modulesFile = filePath;
+
+ if (this.#moduleImports.size === 0) {
+ try {
+ await fs.writeFile(filePath, 'export default new Map();');
+ } catch (err) {
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
+ }
+ }
+
+ if (!this.#modulesDirty && existsSync(filePath)) {
+ return;
+ }
+
+ // Import the assets, with a symbol name that is unique to the import id. The import
+ // for each asset is an object with path, format and dimensions.
+ // We then export them all, mapped by the import id, so we can find them again in the build.
+ const lines: Array<string> = [];
+ for (const [fileName, specifier] of this.#moduleImports) {
+ lines.push(`['${fileName}', () => import('${specifier}')]`);
+ }
+ const code = `
+export default new Map([\n${lines.join(',\n')}]);
+ `;
+ try {
+ await fs.writeFile(filePath, code);
+ } catch (err) {
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
+ }
+ this.#modulesDirty = false;
+ }
+
+ #writeAssetsImportsDebounced() {
+ this.#assetsDirty = true;
+ if (this.#assetsFile) {
+ if (this.#assetsSaveTimeout) {
+ clearTimeout(this.#assetsSaveTimeout);
+ }
+ this.#assetsSaveTimeout = setTimeout(() => {
+ this.#assetsSaveTimeout = undefined;
+ this.writeAssetImports(this.#assetsFile!);
+ }, SAVE_DEBOUNCE_MS);
+ }
+ }
+
+ #writeModulesImportsDebounced() {
+ this.#modulesDirty = true;
+ if (this.#modulesFile) {
+ if (this.#modulesSaveTimeout) {
+ clearTimeout(this.#modulesSaveTimeout);
+ }
+ this.#modulesSaveTimeout = setTimeout(() => {
+ this.#modulesSaveTimeout = undefined;
+ this.writeModuleImports(this.#modulesFile!);
+ }, SAVE_DEBOUNCE_MS);
+ }
+ }
+
+ #saveToDiskDebounced() {
+ this.#dirty = true;
+ // Only save to disk if it has already been saved once
+ if (this.#file) {
+ if (this.#saveTimeout) {
+ clearTimeout(this.#saveTimeout);
+ }
+ this.#saveTimeout = setTimeout(() => {
+ this.#saveTimeout = undefined;
+ this.writeToDisk(this.#file!);
+ }, SAVE_DEBOUNCE_MS);
+ }
+ }
+
+ scopedStore(collectionName: string): ScopedDataStore {
+ return {
+ get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) =>
+ this.get<DataEntry<TData>>(collectionName, key),
+ entries: () => this.entries(collectionName),
+ values: () => this.values(collectionName),
+ keys: () => this.keys(collectionName),
+ set: ({ id: key, data, body, filePath, deferredRender, digest, rendered }) => {
+ if (!key) {
+ throw new Error(`ID must be a non-empty string`);
+ }
+ const id = String(key);
+ if (digest) {
+ const existing = this.get<DataEntry>(collectionName, id);
+ if (existing && existing.digest === digest) {
+ return false;
+ }
+ }
+ const entry: DataEntry = {
+ id,
+ data,
+ };
+ // We do it like this so we don't waste space stringifying
+ // the fields if they are not set
+ if (body) {
+ entry.body = body;
+ }
+ if (filePath) {
+ if (filePath.startsWith('/')) {
+ throw new Error(`File path must be relative to the site root. Got: ${filePath}`);
+ }
+ entry.filePath = filePath;
+ }
+ if (digest) {
+ entry.digest = digest;
+ }
+ if (rendered) {
+ entry.rendered = rendered;
+ }
+ if (deferredRender) {
+ entry.deferredRender = deferredRender;
+ if (filePath) {
+ this.addModuleImport(filePath);
+ }
+ }
+ this.set(collectionName, id, entry);
+ return true;
+ },
+ delete: (key: string) => this.delete(collectionName, key),
+ clear: () => this.clear(collectionName),
+ has: (key: string) => this.has(collectionName, key),
+ addAssetImport: (assetImport: string, fileName: string) =>
+ this.addAssetImport(assetImport, fileName),
+ addAssetImports: (assets: Array<string>, fileName: string) =>
+ this.addAssetImports(assets, fileName),
+ addModuleImport: (fileName: string) => this.addModuleImport(fileName),
+ };
+ }
+ /**
+ * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
+ */
+ metaStore(collectionName = ':meta'): MetaStore {
+ const collectionKey = `meta:${collectionName}`;
+ return {
+ get: (key: string) => this.get(collectionKey, key),
+ set: (key: string, data: string) => this.set(collectionKey, key, data),
+ delete: (key: string) => this.delete(collectionKey, key),
+ has: (key: string) => this.has(collectionKey, key),
+ };
+ }
+
+ toString() {
+ return devalue.stringify(this._collections);
+ }
+
+ async writeToDisk(filePath: PathLike) {
+ if (!this.#dirty) {
+ return;
+ }
+ try {
+ await fs.writeFile(filePath, this.toString());
+ this.#file = filePath;
+ this.#dirty = false;
+ } catch (err) {
+ throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: err });
+ }
+ }
+
+ /**
+ * Attempts to load a MutableDataStore from the virtual module.
+ * This only works in Vite.
+ */
+ static async fromModule() {
+ try {
+ // @ts-expect-error - this is a virtual module
+ const data = await import('astro:data-layer-content');
+ const map = devalue.unflatten(data.default);
+ return MutableDataStore.fromMap(map);
+ } catch {}
+ return new MutableDataStore();
+ }
+
+ static async fromMap(data: Map<string, Map<string, any>>) {
+ const store = new MutableDataStore();
+ store._collections = data;
+ return store;
+ }
+
+ static async fromString(data: string) {
+ const map = devalue.parse(data);
+ return MutableDataStore.fromMap(map);
+ }
+
+ static async fromFile(filePath: string | URL) {
+ try {
+ if (existsSync(filePath)) {
+ const data = await fs.readFile(filePath, 'utf-8');
+ return MutableDataStore.fromString(data);
+ }
+ } catch {}
+ return new MutableDataStore();
+ }
+}
+
+export interface ScopedDataStore {
+ get: <TData extends Record<string, unknown> = Record<string, unknown>>(
+ key: string,
+ ) => DataEntry<TData> | undefined;
+ entries: () => Array<[id: string, DataEntry]>;
+ set: <TData extends Record<string, unknown>>(opts: {
+ /** The ID of the entry. Must be unique per collection. */
+ id: string;
+ /** The data to store. */
+ data: TData;
+ /** The raw body of the content, if applicable. */
+ body?: string;
+ /** The file path of the content, if applicable. Relative to the site root. */
+ filePath?: string;
+ /** A content digest, to check if the content has changed. */
+ digest?: number | string;
+ /** The rendered content, if applicable. */
+ rendered?: RenderedContent;
+ /**
+ * If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase.
+ */
+ deferredRender?: boolean;
+ }) => boolean;
+ values: () => Array<DataEntry>;
+ keys: () => Array<string>;
+ delete: (key: string) => void;
+ clear: () => void;
+ has: (key: string) => boolean;
+ /**
+ * @internal Adds asset imports to the store. This is used to track image imports for the build. This API is subject to change.
+ */
+ addAssetImports: (assets: Array<string>, fileName: string) => void;
+ /**
+ * @internal Adds an asset import to the store. This is used to track image imports for the build. This API is subject to change.
+ */
+ addAssetImport: (assetImport: string, fileName: string) => void;
+ /**
+ * Adds a single asset to the store. This asset will be transformed
+ * by Vite, and the URL will be available in the final build.
+ * @param fileName
+ * @param specifier
+ * @returns
+ */
+ addModuleImport: (fileName: string) => void;
+}
+
+/**
+ * A key-value store for metadata strings. Useful for storing things like sync tokens.
+ */
+
+export interface MetaStore {
+ get: (key: string) => string | undefined;
+ set: (key: string, value: string) => void;
+ has: (key: string) => boolean;
+ delete: (key: string) => void;
+}
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index 6fa0db94b..faf02d95d 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -1,10 +1,10 @@
-import glob from 'fast-glob';
-import { bold, cyan } from 'kleur/colors';
import type fsMod from 'node:fs';
import * as path from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
+import glob from 'fast-glob';
+import { bold, cyan } from 'kleur/colors';
import { type ViteDevServer, normalizePath } from 'vite';
-import { z, type ZodSchema } from 'zod';
+import { type ZodSchema, z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';
import { printNode, zodToTs } from 'zod-to-ts';
import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
@@ -473,7 +473,7 @@ async function writeContentFiles({
collection.type === 'unknown'
? // Add empty / unknown collections to the data type map by default
// This ensures `getCollection('empty-collection')` doesn't raise a type error
- (collectionConfig?.type ?? 'data')
+ collectionConfig?.type ?? 'data'
: collection.type;
const collectionEntryKeys = Object.keys(collection.entries).sort();
@@ -590,11 +590,9 @@ async function writeContentFiles({
// If it's the first time, we inject types the usual way. sync() will handle creating files and references. If it's not the first time, we just override the dts content
if (settings.injectedTypes.some((t) => t.filename === CONTENT_TYPES_FILE)) {
- fs.promises.writeFile(
- new URL(CONTENT_TYPES_FILE, settings.dotAstroDir),
- typeTemplateContent,
- 'utf-8',
- );
+ const filePath = fileURLToPath(new URL(CONTENT_TYPES_FILE, settings.dotAstroDir));
+ await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
+ await fs.promises.writeFile(filePath, typeTemplateContent, 'utf-8');
} else {
settings.injectedTypes.push({
filename: CONTENT_TYPES_FILE,
diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts
index 79a37a28d..6d0627247 100644
--- a/packages/astro/src/content/utils.ts
+++ b/packages/astro/src/content/utils.ts
@@ -20,6 +20,7 @@ import {
CONTENT_FLAGS,
CONTENT_LAYER_TYPE,
CONTENT_MODULE_FLAG,
+ DEFERRED_MODULE,
IMAGE_IMPORT_PREFIX,
PROPAGATED_ASSET_FLAG,
} from './consts.js';
@@ -670,3 +671,10 @@ export function posixifyPath(filePath: string) {
export function posixRelative(from: string, to: string) {
return posixifyPath(path.relative(from, to));
}
+
+export function contentModuleToId(fileName: string) {
+ const params = new URLSearchParams(DEFERRED_MODULE);
+ params.set('fileName', fileName);
+ params.set(CONTENT_MODULE_FLAG, 'true');
+ return `${DEFERRED_MODULE}?${params.toString()}`;
+}
diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts
index 70997e40e..e9eda1dc9 100644
--- a/packages/astro/src/core/build/plugins/plugin-ssr.ts
+++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts
@@ -19,6 +19,26 @@ import { getComponentFromVirtualModulePageName, getVirtualModulePageName } from
export const SSR_VIRTUAL_MODULE_ID = '@astrojs-ssr-virtual-entry';
export const RESOLVED_SSR_VIRTUAL_MODULE_ID = '\0' + SSR_VIRTUAL_MODULE_ID;
+const ADAPTER_VIRTUAL_MODULE_ID = '@astrojs-ssr-adapter';
+const RESOLVED_ADAPTER_VIRTUAL_MODULE_ID = '\0' + ADAPTER_VIRTUAL_MODULE_ID;
+
+function vitePluginAdapter(adapter: AstroAdapter): VitePlugin {
+ return {
+ name: '@astrojs/vite-plugin-astro-adapter',
+ enforce: 'post',
+ resolveId(id) {
+ if (id === ADAPTER_VIRTUAL_MODULE_ID) {
+ return RESOLVED_ADAPTER_VIRTUAL_MODULE_ID;
+ }
+ },
+ async load(id) {
+ if (id === RESOLVED_ADAPTER_VIRTUAL_MODULE_ID) {
+ return `export * from '${adapter.serverEntrypoint}';`;
+ }
+ },
+ };
+}
+
function vitePluginSSR(
internals: BuildInternals,
adapter: AstroAdapter,
@@ -39,7 +59,7 @@ function vitePluginSSR(
const adapterServerEntrypoint = options.settings.adapter?.serverEntrypoint;
if (adapterServerEntrypoint) {
- inputs.add(adapterServerEntrypoint);
+ inputs.add(ADAPTER_VIRTUAL_MODULE_ID);
}
inputs.add(SSR_VIRTUAL_MODULE_ID);
@@ -119,14 +139,19 @@ export function pluginSSR(
targets: ['server'],
hooks: {
'build:before': () => {
- let vitePlugin =
+ const adapter = options.settings.adapter!;
+ let ssrPlugin =
ssr && functionPerRouteEnabled === false
- ? vitePluginSSR(internals, options.settings.adapter!, options)
+ ? vitePluginSSR(internals, adapter, options)
: undefined;
+ const vitePlugin = [vitePluginAdapter(adapter)];
+ if (ssrPlugin) {
+ vitePlugin.unshift(ssrPlugin);
+ }
return {
enforce: 'after-user-plugins',
- vitePlugin,
+ vitePlugin: vitePlugin,
};
},
'build:post': async () => {
@@ -231,10 +256,15 @@ export function pluginSSRSplit(
targets: ['server'],
hooks: {
'build:before': () => {
- let vitePlugin =
+ const adapter = options.settings.adapter!;
+ let ssrPlugin =
ssr && functionPerRouteEnabled
- ? vitePluginSSRSplit(internals, options.settings.adapter!, options)
+ ? vitePluginSSRSplit(internals, adapter, options)
: undefined;
+ const vitePlugin = [vitePluginAdapter(adapter)];
+ if (ssrPlugin) {
+ vitePlugin.unshift(ssrPlugin);
+ }
return {
enforce: 'after-user-plugins',
@@ -251,7 +281,7 @@ function generateSSRCode(settings: AstroSettings, adapter: AstroAdapter, middlew
const imports = [
`import { renderers } from '${RENDERERS_MODULE_ID}';`,
- `import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`,
+ `import * as serverEntrypointModule from '${ADAPTER_VIRTUAL_MODULE_ID}';`,
`import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`,
settings.config.experimental.serverIslands
diff --git a/packages/astro/src/core/dev/dev.ts b/packages/astro/src/core/dev/dev.ts
index 127f34b94..12b6d3b55 100644
--- a/packages/astro/src/core/dev/dev.ts
+++ b/packages/astro/src/core/dev/dev.ts
@@ -1,15 +1,15 @@
import fs, { existsSync } from 'node:fs';
import type http from 'node:http';
import type { AddressInfo } from 'node:net';
+import { performance } from 'node:perf_hooks';
import { green } from 'kleur/colors';
-import { performance } from 'perf_hooks';
import { gt, major, minor, patch } from 'semver';
import type * as vite from 'vite';
import type { AstroInlineConfig } from '../../@types/astro.js';
import { DATA_STORE_FILE } from '../../content/consts.js';
import { globalContentLayer } from '../../content/content-layer.js';
-import { DataStore, globalDataStore } from '../../content/data-store.js';
import { attachContentServerListeners } from '../../content/index.js';
+import { MutableDataStore } from '../../content/mutable-data-store.js';
import { globalContentConfigObserver } from '../../content/utils.js';
import { telemetry } from '../../events/index.js';
import * as msg from '../messages.js';
@@ -106,19 +106,17 @@ export default async function dev(inlineConfig: AstroInlineConfig): Promise<DevS
await attachContentServerListeners(restart.container);
- let store: DataStore | undefined;
+ let store: MutableDataStore | undefined;
try {
const dataStoreFile = new URL(DATA_STORE_FILE, restart.container.settings.config.cacheDir);
if (existsSync(dataStoreFile)) {
- store = await DataStore.fromFile(dataStoreFile);
- globalDataStore.set(store);
+ store = await MutableDataStore.fromFile(dataStoreFile);
}
} catch (err: any) {
logger.error('content', err.message);
}
if (!store) {
- store = new DataStore();
- globalDataStore.set(store);
+ store = new MutableDataStore();
}
const config = globalContentConfigObserver.get();
diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts
index 235454cb5..ee0ba995c 100644
--- a/packages/astro/src/core/dev/restart.ts
+++ b/packages/astro/src/core/dev/restart.ts
@@ -51,7 +51,7 @@ function shouldRestartContainer(
const settingsPath = vite.normalizePath(
fileURLToPath(new URL('settings.json', settings.dotAstroDir)),
);
- if (settingsPath.match(normalizedChangedFile)) {
+ if (settingsPath.endsWith(normalizedChangedFile)) {
shouldRestart = settings.preferences.ignoreNextPreferenceReload ? false : true;
settings.preferences.ignoreNextPreferenceReload = false;
diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts
index aa19b6dc3..24b9ad687 100644
--- a/packages/astro/src/core/errors/errors-data.ts
+++ b/packages/astro/src/core/errors/errors-data.ts
@@ -1294,11 +1294,11 @@ export const RewriteWithBodyUsed = {
/**
* @docs
* @description
- * An unknown error occured while reading or writing files to disk. It can be caused by many things, eg. missing permissions or a file not existing we attempt to read.
+ * An unknown error occurred while reading or writing files to disk. It can be caused by many things, eg. missing permissions or a file not existing we attempt to read.
*/
export const UnknownFilesystemError = {
name: 'UnknownFilesystemError',
- title: 'An unknown error occured while reading or writing files to disk.',
+ title: 'An unknown error occurred while reading or writing files to disk.',
hint: 'It can be caused by many things, eg. missing permissions or a file not existing we attempt to read. Check the error cause for more details.',
} satisfies ErrorData;
diff --git a/packages/astro/src/core/logger/vite.ts b/packages/astro/src/core/logger/vite.ts
index ed62adc8d..f1ed49dce 100644
--- a/packages/astro/src/core/logger/vite.ts
+++ b/packages/astro/src/core/logger/vite.ts
@@ -1,4 +1,4 @@
-import { fileURLToPath } from 'url';
+import { fileURLToPath } from 'node:url';
import stripAnsi from 'strip-ansi';
import type { LogLevel, Rollup, Logger as ViteLogger } from 'vite';
import { isAstroError } from '../errors/errors.js';
diff --git a/packages/astro/src/core/preview/static-preview-server.ts b/packages/astro/src/core/preview/static-preview-server.ts
index 68ca3236b..0afa34b60 100644
--- a/packages/astro/src/core/preview/static-preview-server.ts
+++ b/packages/astro/src/core/preview/static-preview-server.ts
@@ -1,6 +1,6 @@
import type http from 'node:http';
+import { performance } from 'node:perf_hooks';
import { fileURLToPath } from 'node:url';
-import { performance } from 'perf_hooks';
import { type PreviewServer as VitePreviewServer, preview } from 'vite';
import type { AstroSettings } from '../../@types/astro.js';
import type { Logger } from '../logger/core.js';
diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts
index f9c19b9ed..df548ec82 100644
--- a/packages/astro/src/core/routing/manifest/create.ts
+++ b/packages/astro/src/core/routing/manifest/create.ts
@@ -8,8 +8,8 @@ import type {
} from '../../../@types/astro.js';
import type { Logger } from '../../logger/core.js';
-import { createRequire } from 'module';
import nodeFs from 'node:fs';
+import { createRequire } from 'node:module';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { bold } from 'kleur/colors';
diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts
index c9b2ec235..92b3478e3 100644
--- a/packages/astro/src/core/sync/index.ts
+++ b/packages/astro/src/core/sync/index.ts
@@ -1,13 +1,14 @@
import fsMod, { existsSync } from 'node:fs';
import { performance } from 'node:perf_hooks';
+import { fileURLToPath } from 'node:url';
import { dim } from 'kleur/colors';
import { type HMRPayload, createServer } from 'vite';
import type { AstroConfig, AstroInlineConfig, AstroSettings } from '../../@types/astro.js';
-import { DATA_STORE_FILE } from '../../content/consts.js';
+import { CONTENT_TYPES_FILE, DATA_STORE_FILE } from '../../content/consts.js';
import { globalContentLayer } from '../../content/content-layer.js';
-import { DataStore, globalDataStore } from '../../content/data-store.js';
import { createContentTypesGenerator } from '../../content/index.js';
-import { globalContentConfigObserver } from '../../content/utils.js';
+import { MutableDataStore } from '../../content/mutable-data-store.js';
+import { getContentPaths, globalContentConfigObserver } from '../../content/utils.js';
import { syncAstroEnv } from '../../env/sync.js';
import { telemetry } from '../../events/index.js';
import { eventCliSession } from '../../events/session.js';
@@ -103,19 +104,17 @@ export async function syncInternal({
if (!skip?.content) {
await syncContentCollections(settings, { fs, logger });
settings.timer.start('Sync content layer');
- let store: DataStore | undefined;
+ let store: MutableDataStore | undefined;
try {
const dataStoreFile = new URL(DATA_STORE_FILE, settings.config.cacheDir);
if (existsSync(dataStoreFile)) {
- store = await DataStore.fromFile(dataStoreFile);
- globalDataStore.set(store);
+ store = await MutableDataStore.fromFile(dataStoreFile);
}
} catch (err: any) {
logger.error('content', err.message);
}
if (!store) {
- store = new DataStore();
- globalDataStore.set(store);
+ store = new MutableDataStore();
}
const contentLayer = globalContentLayer.init({
settings,
@@ -124,6 +123,14 @@ export async function syncInternal({
});
await contentLayer.sync();
settings.timer.end('Sync content layer');
+ } else if (fs.existsSync(fileURLToPath(getContentPaths(settings.config, fs).contentDir))) {
+ // Content is synced after writeFiles. That means references are not created
+ // To work around it, we create a stub so the reference is created and content
+ // sync will override the empty file
+ settings.injectedTypes.push({
+ filename: CONTENT_TYPES_FILE,
+ content: '',
+ });
}
syncAstroEnv(settings, fs);
diff --git a/packages/astro/src/core/sync/write-files.ts b/packages/astro/src/core/sync/write-files.ts
index 56ab131f1..91084c36f 100644
--- a/packages/astro/src/core/sync/write-files.ts
+++ b/packages/astro/src/core/sync/write-files.ts
@@ -4,9 +4,9 @@ import { fileURLToPath } from 'node:url';
import { bold } from 'kleur/colors';
import { normalizePath } from 'vite';
import type { AstroSettings } from '../../@types/astro.js';
+import { AstroError, AstroErrorData } from '../errors/index.js';
import type { Logger } from '../logger/core.js';
import { REFERENCE_FILE } from './constants.js';
-import { AstroError, AstroErrorData } from '../errors/index.js';
export async function writeFiles(settings: AstroSettings, fs: typeof fsMod, logger: Logger) {
try {
@@ -27,7 +27,7 @@ function writeInjectedTypes(settings: AstroSettings, fs: typeof fsMod) {
const references: Array<string> = [];
for (const { filename, content } of settings.injectedTypes) {
- const filepath = normalizePath(fileURLToPath(new URL(filename, settings.dotAstroDir)));
+ const filepath = fileURLToPath(new URL(filename, settings.dotAstroDir));
fs.mkdirSync(dirname(filepath), { recursive: true });
fs.writeFileSync(filepath, content, 'utf-8');
references.push(normalizePath(relative(fileURLToPath(settings.dotAstroDir), filepath)));
@@ -38,17 +38,15 @@ function writeInjectedTypes(settings: AstroSettings, fs: typeof fsMod) {
fs.mkdirSync(settings.dotAstroDir, { recursive: true });
}
fs.writeFileSync(
- normalizePath(fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir))),
+ fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir)),
astroDtsContent,
'utf-8',
);
}
async function setUpEnvTs(settings: AstroSettings, fs: typeof fsMod, logger: Logger) {
- const envTsPath = normalizePath(fileURLToPath(new URL('env.d.ts', settings.config.srcDir)));
- const envTsPathRelativetoRoot = normalizePath(
- relative(fileURLToPath(settings.config.root), envTsPath),
- );
+ const envTsPath = fileURLToPath(new URL('env.d.ts', settings.config.srcDir));
+ const envTsPathRelativetoRoot = relative(fileURLToPath(settings.config.root), envTsPath);
const relativePath = normalizePath(
relative(
fileURLToPath(settings.config.srcDir),
diff --git a/packages/astro/src/runtime/server/render/server-islands.ts b/packages/astro/src/runtime/server/render/server-islands.ts
index 58cce4e14..0a0721134 100644
--- a/packages/astro/src/runtime/server/render/server-islands.ts
+++ b/packages/astro/src/runtime/server/render/server-islands.ts
@@ -64,7 +64,8 @@ export function renderServerIsland(
const propsEncrypted = await encryptString(key, JSON.stringify(props));
const hostId = crypto.randomUUID();
- const serverIslandUrl = `${result.base}_server-islands/${componentId}${result.trailingSlash === 'always' ? '/' : ''}`;
+ const slash = result.base.endsWith('/') ? '' : '/';
+ const serverIslandUrl = `${result.base}${slash}_server-islands/${componentId}${result.trailingSlash === 'always' ? '/' : ''}`;
destination.write(`<script async type="module" data-island-id="${hostId}">
let componentId = ${safeJsonStringify(componentId)};
@@ -85,9 +86,10 @@ if(response.status === 200 && response.headers.get('content-type') === 'text/htm
let html = await response.text();
// Swap!
- while(script.previousSibling?.nodeType !== 8 &&
- script.previousSibling?.data !== 'server-island-start') {
- script.previousSibling?.remove();
+ while(script.previousSibling &&
+ script.previousSibling.nodeType !== 8 &&
+ script.previousSibling.data !== 'server-island-start') {
+ script.previousSibling.remove();
}
script.previousSibling?.remove();
diff --git a/packages/astro/src/vite-plugin-astro-server/response.ts b/packages/astro/src/vite-plugin-astro-server/response.ts
index 2ccf1aade..707a26e40 100644
--- a/packages/astro/src/vite-plugin-astro-server/response.ts
+++ b/packages/astro/src/vite-plugin-astro-server/response.ts
@@ -2,7 +2,7 @@ import type http from 'node:http';
import type { ErrorWithMetadata } from '../core/errors/index.js';
import type { ModuleLoader } from '../core/module-loader/index.js';
-import { Readable } from 'stream';
+import { Readable } from 'node:stream';
import { getSetCookiesFromResponse } from '../core/cookies/index.js';
import { getViteErrorPayload } from '../core/errors/dev/index.js';
import notFoundTemplate from '../template/4xx.js';
diff --git a/packages/astro/templates/content/types.d.ts b/packages/astro/templates/content/types.d.ts
index 9f277576a..f83f28177 100644
--- a/packages/astro/templates/content/types.d.ts
+++ b/packages/astro/templates/content/types.d.ts
@@ -1,5 +1,4 @@
declare module 'astro:content' {
-
interface RenderResult {
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
headings: import('astro').MarkdownHeading[];
@@ -9,7 +8,6 @@ declare module 'astro:content' {
'.md': Promise<RenderResult>;
}
-
export interface RenderedContent {
html: string;
metadata?: {
diff --git a/packages/astro/test/astro-sync.test.js b/packages/astro/test/astro-sync.test.js
index dfe4755d1..bb044574f 100644
--- a/packages/astro/test/astro-sync.test.js
+++ b/packages/astro/test/astro-sync.test.js
@@ -4,7 +4,6 @@ import * as fs from 'node:fs';
import { beforeEach, describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';
import ts from 'typescript';
-import { normalizePath } from 'vite';
import { loadFixture } from './test-utils.js';
const createFixture = () => {
@@ -16,8 +15,7 @@ const createFixture = () => {
/**
* @param {string} path
*/
- const getExpectedPath = (path) =>
- normalizePath(fileURLToPath(new URL(path, astroFixture.config.root)));
+ const getExpectedPath = (path) => fileURLToPath(new URL(path, astroFixture.config.root));
return {
/** @param {string} root */
diff --git a/packages/astro/test/build-readonly-file.test.js b/packages/astro/test/build-readonly-file.test.js
index bf6dd3fa4..60b3f507b 100644
--- a/packages/astro/test/build-readonly-file.test.js
+++ b/packages/astro/test/build-readonly-file.test.js
@@ -1,5 +1,5 @@
import { after, before, describe, it } from 'node:test';
-import { fileURLToPath } from 'url';
+import { fileURLToPath } from 'node:url';
import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
diff --git a/packages/astro/test/ssr-split-manifest.test.js b/packages/astro/test/ssr-split-manifest.test.js
index 06a6fe8c6..af0234c6a 100644
--- a/packages/astro/test/ssr-split-manifest.test.js
+++ b/packages/astro/test/ssr-split-manifest.test.js
@@ -1,6 +1,5 @@
import assert from 'node:assert/strict';
import { existsSync, readFileSync } from 'node:fs';
-import { resolve } from 'node:path';
import { before, describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';
import * as cheerio from 'cheerio';
@@ -62,12 +61,13 @@ describe('astro:ssr-manifest, split', () => {
});
it('should correctly emit the the pre render page', async () => {
- const text = readFileSync(
- resolve('./test/fixtures/ssr-split-manifest/dist/client/prerender/index.html'),
- {
- encoding: 'utf8',
- },
+ const indexUrl = new URL(
+ './fixtures/ssr-split-manifest/dist/client/prerender/index.html',
+ import.meta.url,
);
+ const text = readFileSync(indexUrl, {
+ encoding: 'utf8',
+ });
assert.equal(text.includes('<title>Pre render me</title>'), true);
});
diff --git a/packages/astro/test/test-adapter.js b/packages/astro/test/test-adapter.js
index 8c4643367..fc5249561 100644
--- a/packages/astro/test/test-adapter.js
+++ b/packages/astro/test/test-adapter.js
@@ -108,6 +108,10 @@ export default function ({
supportedAstroFeatures: {
serverOutput: 'stable',
envGetSecret: 'experimental',
+ staticOutput: 'stable',
+ hybridOutput: 'stable',
+ assets: 'stable',
+ i18nDomains: 'stable',
},
...extendAdapter,
});
diff --git a/packages/astro/test/units/dev/collections-renderentry.test.js b/packages/astro/test/units/dev/collections-renderentry.test.js
index 9441129a7..082cd6b2f 100644
--- a/packages/astro/test/units/dev/collections-renderentry.test.js
+++ b/packages/astro/test/units/dev/collections-renderentry.test.js
@@ -1,5 +1,4 @@
import * as assert from 'node:assert/strict';
-import os from 'node:os';
import { describe, it } from 'node:test';
import { fileURLToPath } from 'node:url';
import * as cheerio from 'cheerio';
@@ -9,8 +8,6 @@ import { createFsWithFallback, createRequestAndResponse, runInContainer } from '
const root = new URL('../../fixtures/content/', import.meta.url);
-const _describe = os.platform() === 'win32' ? describe.skip : describe;
-
/** @type {typeof runInContainer} */
async function runInContainerWithContentListeners(params, callback) {
return await runInContainer(params, async (container) => {
@@ -19,7 +16,7 @@ async function runInContainerWithContentListeners(params, callback) {
});
}
-_describe('Content Collections - render()', () => {
+describe('Content Collections - render()', () => {
it('can be called in a page component', async () => {
const fs = createFsWithFallback(
{
diff --git a/packages/create-astro/CHANGELOG.md b/packages/create-astro/CHANGELOG.md
index 5af50e312..19ae5f93f 100644
--- a/packages/create-astro/CHANGELOG.md
+++ b/packages/create-astro/CHANGELOG.md
@@ -1,5 +1,17 @@
# create-astro
+## 4.8.3
+
+### Patch Changes
+
+- [#11733](https://github.com/withastro/astro/pull/11733) [`391324d`](https://github.com/withastro/astro/commit/391324df969db71d1c7ca25c2ed14c9eb6eea5ee) Thanks [@bluwy](https://github.com/bluwy)! - Reverts back to `arg` package for CLI argument parsing
+
+## 4.8.2
+
+### Patch Changes
+
+- [#11645](https://github.com/withastro/astro/pull/11645) [`849e4c6`](https://github.com/withastro/astro/commit/849e4c6c23e61f7fa59f583419048b998bef2475) Thanks [@bluwy](https://github.com/bluwy)! - Refactors internally to use `node:util` `parseArgs` instead of `arg`
+
## 4.8.1
### Patch Changes
diff --git a/packages/create-astro/package.json b/packages/create-astro/package.json
index 4a2fc13ad..e22a738fa 100644
--- a/packages/create-astro/package.json
+++ b/packages/create-astro/package.json
@@ -1,6 +1,6 @@
{
"name": "create-astro",
- "version": "4.8.1",
+ "version": "4.8.3",
"type": "module",
"author": "withastro",
"license": "MIT",
diff --git a/packages/create-astro/src/actions/context.ts b/packages/create-astro/src/actions/context.ts
index bf1b522bd..83a13eda7 100644
--- a/packages/create-astro/src/actions/context.ts
+++ b/packages/create-astro/src/actions/context.ts
@@ -1,7 +1,7 @@
import os from 'node:os';
-import { parseArgs } from 'node:util';
import { type Task, prompt } from '@astrojs/cli-kit';
import { random } from '@astrojs/cli-kit/utils';
+import arg from 'arg';
import getSeasonalData from '../data/seasonal.js';
import { getName, getVersion } from '../messages.js';
@@ -33,44 +33,47 @@ export interface Context {
}
export async function getContext(argv: string[]): Promise<Context> {
- const args = parseArgs({
- args: argv,
- allowPositionals: true,
- strict: false,
- options: {
- template: { type: 'string' },
- ref: { type: 'string' },
- yes: { type: 'boolean', short: 'y' },
- no: { type: 'boolean', short: 'n' },
- install: { type: 'boolean' },
- 'no-install': { type: 'boolean' },
- git: { type: 'boolean' },
- 'no-git': { type: 'boolean' },
- typescript: { type: 'string' },
- 'skip-houston': { type: 'boolean' },
- 'dry-run': { type: 'boolean' },
- help: { type: 'boolean', short: 'h' },
- fancy: { type: 'boolean' },
+ const flags = arg(
+ {
+ '--template': String,
+ '--ref': String,
+ '--yes': Boolean,
+ '--no': Boolean,
+ '--install': Boolean,
+ '--no-install': Boolean,
+ '--git': Boolean,
+ '--no-git': Boolean,
+ '--typescript': String,
+ '--skip-houston': Boolean,
+ '--dry-run': Boolean,
+ '--help': Boolean,
+ '--fancy': Boolean,
+
+ '-y': '--yes',
+ '-n': '--no',
+ '-h': '--help',
},
- });
+ { argv, permissive: true },
+ );
const packageManager = detectPackageManager() ?? 'npm';
- const projectName = args.positionals[0];
+ let cwd = flags['_'][0];
let {
- help,
- template,
- no,
- yes,
- install,
- 'no-install': noInstall,
- git,
- 'no-git': noGit,
- typescript,
- fancy,
- 'skip-houston': skipHouston,
- 'dry-run': dryRun,
- ref,
- } = args.values;
+ '--help': help = false,
+ '--template': template,
+ '--no': no,
+ '--yes': yes,
+ '--install': install,
+ '--no-install': noInstall,
+ '--git': git,
+ '--no-git': noGit,
+ '--typescript': typescript,
+ '--fancy': fancy,
+ '--skip-houston': skipHouston,
+ '--dry-run': dryRun,
+ '--ref': ref,
+ } = flags;
+ let projectName = cwd;
if (no) {
yes = false;
@@ -79,26 +82,10 @@ export async function getContext(argv: string[]): Promise<Context> {
if (typescript == undefined) typescript = 'strict';
}
- skipHouston = typeof skipHouston == 'boolean' ? skipHouston : undefined;
skipHouston =
((os.platform() === 'win32' && !fancy) || skipHouston) ??
[yes, no, install, git, typescript].some((v) => v !== undefined);
- // We use `strict: false` in `parseArgs` to allow unknown options, but Node also
- // simply doesn't guarantee the types anymore, so we need to validate ourselves :(
- help = !!help;
- template = typeof template == 'string' ? template : undefined;
- no = !!no;
- yes = !!yes;
- install = !!install;
- noInstall = !!noInstall;
- git = !!git;
- noGit = !!noGit;
- typescript = typeof typescript == 'string' ? typescript : undefined;
- fancy = !!fancy;
- dryRun = !!dryRun;
- ref = typeof ref == 'string' ? ref : undefined;
-
const { messages, hats, ties } = getSeasonalData({ fancy });
const context: Context = {
@@ -120,7 +107,7 @@ export async function getContext(argv: string[]): Promise<Context> {
install: install ?? (noInstall ? false : undefined),
git: git ?? (noGit ? false : undefined),
typescript,
- cwd: projectName,
+ cwd,
exit(code) {
process.exit(code);
},
diff --git a/packages/db/CHANGELOG.md b/packages/db/CHANGELOG.md
index eb7978ead..9fcc870d3 100644
--- a/packages/db/CHANGELOG.md
+++ b/packages/db/CHANGELOG.md
@@ -1,5 +1,40 @@
# @astrojs/db
+## 0.13.1
+
+### Patch Changes
+
+- [#11733](https://github.com/withastro/astro/pull/11733) [`391324d`](https://github.com/withastro/astro/commit/391324df969db71d1c7ca25c2ed14c9eb6eea5ee) Thanks [@bluwy](https://github.com/bluwy)! - Reverts back to `yargs-parser` package for CLI argument parsing
+
+- Updated dependencies []:
+ - @astrojs/studio@0.1.1
+
+## 0.13.0
+
+### Minor Changes
+
+- [#11360](https://github.com/withastro/astro/pull/11360) [`a79a8b0`](https://github.com/withastro/astro/commit/a79a8b0230b06ed32ce1802f2a5f84a6cf92dbe7) Thanks [@ascorbic](https://github.com/ascorbic)! - Changes how type generation works
+
+ The generated `.d.ts` file is now at a new location:
+
+ ```diff
+ - .astro/db-types.d.ts
+ + .astro/integrations/astro_db/db.d.ts
+ ```
+
+ The following line can now be removed from `src/env.d.ts`:
+
+ ```diff
+ - /// <reference path="../.astro/db-types.d.ts" />
+ ```
+
+### Patch Changes
+
+- [#11645](https://github.com/withastro/astro/pull/11645) [`849e4c6`](https://github.com/withastro/astro/commit/849e4c6c23e61f7fa59f583419048b998bef2475) Thanks [@bluwy](https://github.com/bluwy)! - Refactors internally to use `node:util` `parseArgs` instead of `yargs-parser`
+
+- Updated dependencies []:
+ - @astrojs/studio@0.1.1
+
## 0.12.0
### Minor Changes
diff --git a/packages/db/package.json b/packages/db/package.json
index 6dd5d5823..5f82fa910 100644
--- a/packages/db/package.json
+++ b/packages/db/package.json
@@ -1,6 +1,6 @@
{
"name": "@astrojs/db",
- "version": "0.12.0",
+ "version": "0.13.1",
"description": "Add libSQL and Astro Studio support to your Astro site",
"license": "MIT",
"repository": {
@@ -81,11 +81,13 @@
"ora": "^8.0.1",
"prompts": "^2.4.2",
"strip-ansi": "^7.1.0",
+ "yargs-parser": "^21.1.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/deep-diff": "^1.0.5",
"@types/prompts": "^2.4.9",
+ "@types/yargs-parser": "^21.0.3",
"astro": "workspace:*",
"astro-scripts": "workspace:*",
"cheerio": "1.0.0",
diff --git a/packages/db/src/core/cli/commands/execute/index.ts b/packages/db/src/core/cli/commands/execute/index.ts
index 03b3d00ad..c6c11cdbb 100644
--- a/packages/db/src/core/cli/commands/execute/index.ts
+++ b/packages/db/src/core/cli/commands/execute/index.ts
@@ -3,6 +3,7 @@ import { getManagedAppTokenOrExit } from '@astrojs/studio';
import { LibsqlError } from '@libsql/client';
import type { AstroConfig } from 'astro';
import { green } from 'kleur/colors';
+import type { Arguments } from 'yargs-parser';
import {
EXEC_DEFAULT_EXPORT_ERROR,
EXEC_ERROR,
@@ -15,7 +16,6 @@ import {
} from '../../../integration/vite-plugin-db.js';
import { bundleFile, importBundledFile } from '../../../load-file.js';
import type { DBConfig } from '../../../types.js';
-import type { YargsArguments } from '../../types.js';
export async function cmd({
astroConfig,
@@ -24,7 +24,7 @@ export async function cmd({
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
- flags: YargsArguments;
+ flags: Arguments;
}) {
const filePath = flags._[4];
if (typeof filePath !== 'string') {
diff --git a/packages/db/src/core/cli/commands/login/index.ts b/packages/db/src/core/cli/commands/login/index.ts
index 251d61e05..61f7e0275 100644
--- a/packages/db/src/core/cli/commands/login/index.ts
+++ b/packages/db/src/core/cli/commands/login/index.ts
@@ -7,8 +7,8 @@ import { cyan } from 'kleur/colors';
import open from 'open';
import ora from 'ora';
import prompt from 'prompts';
+import type { Arguments } from 'yargs-parser';
import type { DBConfig } from '../../../types.js';
-import type { YargsArguments } from '../../types.js';
const isWebContainer =
// Stackblitz heuristic
@@ -21,7 +21,7 @@ export async function cmd({
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
- flags: YargsArguments;
+ flags: Arguments;
}) {
let session = flags.session;
diff --git a/packages/db/src/core/cli/commands/push/index.ts b/packages/db/src/core/cli/commands/push/index.ts
index 237f7f6ea..ecd101ece 100644
--- a/packages/db/src/core/cli/commands/push/index.ts
+++ b/packages/db/src/core/cli/commands/push/index.ts
@@ -1,6 +1,7 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
import prompts from 'prompts';
+import type { Arguments } from 'yargs-parser';
import { safeFetch } from '../../../../runtime/utils.js';
import { MIGRATION_VERSION } from '../../../consts.js';
import { type DBConfig, type DBSnapshot } from '../../../types.js';
@@ -12,7 +13,6 @@ import {
getMigrationQueries,
getProductionCurrentSnapshot,
} from '../../migration-queries.js';
-import type { YargsArguments } from '../../types.js';
export async function cmd({
dbConfig,
@@ -20,7 +20,7 @@ export async function cmd({
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
- flags: YargsArguments;
+ flags: Arguments;
}) {
const isDryRun = flags.dryRun;
const isForceReset = flags.forceReset;
diff --git a/packages/db/src/core/cli/commands/shell/index.ts b/packages/db/src/core/cli/commands/shell/index.ts
index 5a6bcaa53..e0a1a6086 100644
--- a/packages/db/src/core/cli/commands/shell/index.ts
+++ b/packages/db/src/core/cli/commands/shell/index.ts
@@ -1,6 +1,7 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
import { sql } from 'drizzle-orm';
+import type { Arguments } from 'yargs-parser';
import {
createLocalDatabaseClient,
createRemoteDatabaseClient,
@@ -10,7 +11,6 @@ import { DB_PATH } from '../../../consts.js';
import { SHELL_QUERY_MISSING_ERROR } from '../../../errors.js';
import type { DBConfigInput } from '../../../types.js';
import { getAstroEnv, getRemoteDatabaseUrl } from '../../../utils.js';
-import type { YargsArguments } from '../../types.js';
export async function cmd({
flags,
@@ -18,7 +18,7 @@ export async function cmd({
}: {
dbConfig: DBConfigInput;
astroConfig: AstroConfig;
- flags: YargsArguments;
+ flags: Arguments;
}) {
const query = flags.query;
if (!query) {
diff --git a/packages/db/src/core/cli/commands/verify/index.ts b/packages/db/src/core/cli/commands/verify/index.ts
index 081c8ae3f..950fb6615 100644
--- a/packages/db/src/core/cli/commands/verify/index.ts
+++ b/packages/db/src/core/cli/commands/verify/index.ts
@@ -1,5 +1,6 @@
import { getManagedAppTokenOrExit } from '@astrojs/studio';
import type { AstroConfig } from 'astro';
+import type { Arguments } from 'yargs-parser';
import type { DBConfig } from '../../../types.js';
import {
createCurrentSnapshot,
@@ -8,7 +9,6 @@ import {
getMigrationQueries,
getProductionCurrentSnapshot,
} from '../../migration-queries.js';
-import type { YargsArguments } from '../../types.js';
export async function cmd({
dbConfig,
@@ -16,7 +16,7 @@ export async function cmd({
}: {
astroConfig: AstroConfig;
dbConfig: DBConfig;
- flags: YargsArguments;
+ flags: Arguments;
}) {
const isJson = flags.json;
const appToken = await getManagedAppTokenOrExit(flags.token);
diff --git a/packages/db/src/core/cli/index.ts b/packages/db/src/core/cli/index.ts
index 5d9aa10e9..531b016a6 100644
--- a/packages/db/src/core/cli/index.ts
+++ b/packages/db/src/core/cli/index.ts
@@ -1,13 +1,13 @@
import type { AstroConfig } from 'astro';
+import type { Arguments } from 'yargs-parser';
import { resolveDbConfig } from '../load-file.js';
import { printHelp } from './print-help.js';
-import type { YargsArguments } from './types.js';
export async function cli({
flags,
config: astroConfig,
}: {
- flags: YargsArguments;
+ flags: Arguments;
config: AstroConfig;
}) {
const args = flags._ as string[];
diff --git a/packages/db/src/core/cli/types.ts b/packages/db/src/core/cli/types.ts
index 9d8aad56b..4294c3fb0 100644
--- a/packages/db/src/core/cli/types.ts
+++ b/packages/db/src/core/cli/types.ts
@@ -1,6 +1,4 @@
-// Copy of `yargs-parser` `Arguments` type. We don't use `yargs-parser`
-// in runtime anymore, but our exposed API still relies on this shape.
-export interface YargsArguments {
+export interface Arguments {
_: Array<string | number>;
'--'?: Array<string | number>;
[argName: string]: any;
diff --git a/packages/db/src/core/integration/index.ts b/packages/db/src/core/integration/index.ts
index 68439cfb9..da03e71f2 100644
--- a/packages/db/src/core/integration/index.ts
+++ b/packages/db/src/core/integration/index.ts
@@ -1,11 +1,10 @@
-import { existsSync } from 'fs';
-import { parseArgs } from 'node:util';
-import { dirname } from 'path';
-import { fileURLToPath } from 'url';
+import { existsSync } from 'node:fs';
+import { mkdir, writeFile } from 'node:fs/promises';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
import { type ManagedAppToken, getManagedAppTokenOrExit } from '@astrojs/studio';
import { LibsqlError } from '@libsql/client';
import type { AstroConfig, AstroIntegration } from 'astro';
-import { mkdir, writeFile } from 'fs/promises';
import { blue, yellow } from 'kleur/colors';
import {
type HMRPayload,
@@ -15,6 +14,7 @@ import {
loadEnv,
mergeConfig,
} from 'vite';
+import parseArgs from 'yargs-parser';
import { AstroDbError } from '../../runtime/utils.js';
import { CONFIG_FILE_NAMES, DB_PATH } from '../consts.js';
import { EXEC_DEFAULT_EXPORT_ERROR, EXEC_ERROR } from '../errors.js';
@@ -71,8 +71,8 @@ function astroDBIntegration(): AstroIntegration {
if (command === 'preview') return;
let dbPlugin: VitePlugin | undefined = undefined;
- const args = parseArgs({ strict: false });
- connectToStudio = !!process.env.ASTRO_INTERNAL_TEST_REMOTE || !!args.values.remote;
+ const args = parseArgs(process.argv.slice(3));
+ connectToStudio = process.env.ASTRO_INTERNAL_TEST_REMOTE || args['remote'];
if (connectToStudio) {
appToken = await getManagedAppTokenOrExit();
diff --git a/packages/db/test/local-prod.test.js b/packages/db/test/local-prod.test.js
index 134ee6b56..6513aeb08 100644
--- a/packages/db/test/local-prod.test.js
+++ b/packages/db/test/local-prod.test.js
@@ -1,7 +1,7 @@
import assert from 'node:assert/strict';
+import { relative } from 'node:path';
import { after, before, describe, it } from 'node:test';
-import { relative } from 'path';
-import { fileURLToPath } from 'url';
+import { fileURLToPath } from 'node:url';
import testAdapter from '../../astro/test/test-adapter.js';
import { loadFixture } from '../../astro/test/test-utils.js';
diff --git a/packages/integrations/mdx/src/vite-plugin-mdx.ts b/packages/integrations/mdx/src/vite-plugin-mdx.ts
index b232d1c83..7b37535d8 100644
--- a/packages/integrations/mdx/src/vite-plugin-mdx.ts
+++ b/packages/integrations/mdx/src/vite-plugin-mdx.ts
@@ -44,9 +44,10 @@ export function vitePluginMdx(mdxOptions: MdxOptions): Plugin {
async transform(code, id) {
if (!id.endsWith('.mdx')) return;
- const { data: frontmatter, content: pageContent } = parseFrontmatter(code, id);
+ const { data: frontmatter, content: pageContent, matter } = parseFrontmatter(code, id);
+ const frontmatterLines = matter ? matter.match(/\n/g)?.join('') + '\n\n' : '';
- const vfile = new VFile({ value: pageContent, path: id });
+ const vfile = new VFile({ value: frontmatterLines + pageContent, path: id });
// Ensure `data.astro` is available to all remark plugins
setVfileFrontmatter(vfile, frontmatter);
diff --git a/packages/integrations/node/src/standalone.ts b/packages/integrations/node/src/standalone.ts
index 817ca7020..76e672d2f 100644
--- a/packages/integrations/node/src/standalone.ts
+++ b/packages/integrations/node/src/standalone.ts
@@ -1,6 +1,6 @@
-import https from 'https';
import fs from 'node:fs';
import http from 'node:http';
+import https from 'node:https';
import type { PreviewServer } from 'astro';
import type { NodeApp } from 'astro/app/node';
import enableDestroy from 'server-destroy';
diff --git a/packages/integrations/partytown/src/index.ts b/packages/integrations/partytown/src/index.ts
index bf8a6db1c..739ff0e4b 100644
--- a/packages/integrations/partytown/src/index.ts
+++ b/packages/integrations/partytown/src/index.ts
@@ -1,5 +1,5 @@
-import { createRequire } from 'module';
import * as fs from 'node:fs';
+import { createRequire } from 'node:module';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { PartytownConfig } from '@builder.io/partytown/integration';
diff --git a/packages/integrations/sitemap/src/write-sitemap.ts b/packages/integrations/sitemap/src/write-sitemap.ts
index 8c86ae166..4c189ee3c 100644
--- a/packages/integrations/sitemap/src/write-sitemap.ts
+++ b/packages/integrations/sitemap/src/write-sitemap.ts
@@ -1,8 +1,8 @@
-import { type WriteStream, createWriteStream } from 'fs';
-import { normalize, resolve } from 'path';
-import { Readable, pipeline } from 'stream';
-import { promisify } from 'util';
-import { mkdir } from 'fs/promises';
+import { type WriteStream, createWriteStream } from 'node:fs';
+import { mkdir } from 'node:fs/promises';
+import { normalize, resolve } from 'node:path';
+import { Readable, pipeline } from 'node:stream';
+import { promisify } from 'node:util';
import replace from 'stream-replace-string';
import { SitemapAndIndexStream, SitemapStream } from 'sitemap';
diff --git a/packages/integrations/web-vitals/CHANGELOG.md b/packages/integrations/web-vitals/CHANGELOG.md
index 3d5628824..037e868a9 100644
--- a/packages/integrations/web-vitals/CHANGELOG.md
+++ b/packages/integrations/web-vitals/CHANGELOG.md
@@ -1,5 +1,12 @@
# @astrojs/web-vitals
+## 2.0.0
+
+### Patch Changes
+
+- Updated dependencies [[`849e4c6`](https://github.com/withastro/astro/commit/849e4c6c23e61f7fa59f583419048b998bef2475), [`a79a8b0`](https://github.com/withastro/astro/commit/a79a8b0230b06ed32ce1802f2a5f84a6cf92dbe7)]:
+ - @astrojs/db@0.13.0
+
## 1.0.0
### Patch Changes
diff --git a/packages/integrations/web-vitals/package.json b/packages/integrations/web-vitals/package.json
index 7ae27f247..fcf42d536 100644
--- a/packages/integrations/web-vitals/package.json
+++ b/packages/integrations/web-vitals/package.json
@@ -1,7 +1,7 @@
{
"name": "@astrojs/web-vitals",
"description": "Track your website’s performance with Astro DB",
- "version": "1.0.0",
+ "version": "2.0.0",
"type": "module",
"author": "withastro",
"license": "MIT",
@@ -35,7 +35,7 @@
"web-vitals": "^4.2.3"
},
"peerDependencies": {
- "@astrojs/db": "^0.12.0"
+ "@astrojs/db": "^0.13.0"
},
"devDependencies": {
"@astrojs/db": "workspace:*",
diff --git a/packages/upgrade/CHANGELOG.md b/packages/upgrade/CHANGELOG.md
index c4e7da9cf..2156497a7 100644
--- a/packages/upgrade/CHANGELOG.md
+++ b/packages/upgrade/CHANGELOG.md
@@ -1,5 +1,17 @@
# @astrojs/upgrade
+## 0.3.3
+
+### Patch Changes
+
+- [#11733](https://github.com/withastro/astro/pull/11733) [`391324d`](https://github.com/withastro/astro/commit/391324df969db71d1c7ca25c2ed14c9eb6eea5ee) Thanks [@bluwy](https://github.com/bluwy)! - Reverts back to `arg` package for CLI argument parsing
+
+## 0.3.2
+
+### Patch Changes
+
+- [#11645](https://github.com/withastro/astro/pull/11645) [`849e4c6`](https://github.com/withastro/astro/commit/849e4c6c23e61f7fa59f583419048b998bef2475) Thanks [@bluwy](https://github.com/bluwy)! - Refactors internally to use `node:util` `parseArgs` instead of `arg`
+
## 0.3.1
### Patch Changes
diff --git a/packages/upgrade/package.json b/packages/upgrade/package.json
index fe36ecd24..286a0be78 100644
--- a/packages/upgrade/package.json
+++ b/packages/upgrade/package.json
@@ -1,6 +1,6 @@
{
"name": "@astrojs/upgrade",
- "version": "0.3.1",
+ "version": "0.3.3",
"type": "module",
"author": "withastro",
"license": "MIT",
diff --git a/packages/upgrade/src/actions/context.ts b/packages/upgrade/src/actions/context.ts
index cd9028e85..2103a5327 100644
--- a/packages/upgrade/src/actions/context.ts
+++ b/packages/upgrade/src/actions/context.ts
@@ -1,13 +1,13 @@
import { pathToFileURL } from 'node:url';
-import { parseArgs } from 'node:util';
import { prompt } from '@astrojs/cli-kit';
+import arg from 'arg';
import detectPackageManager from 'preferred-pm';
export interface Context {
help: boolean;
prompt: typeof prompt;
version: string;
- dryRun: boolean;
+ dryRun?: boolean;
cwd: URL;
stdin?: typeof process.stdin;
stdout?: typeof process.stdout;
@@ -28,20 +28,22 @@ export interface PackageInfo {
}
export async function getContext(argv: string[]): Promise<Context> {
- const args = parseArgs({
- args: argv,
- allowPositionals: true,
- strict: false,
- options: {
- 'dry-run': { type: 'boolean' },
- help: { type: 'boolean', short: 'h' },
+ const flags = arg(
+ {
+ '--dry-run': Boolean,
+ '--help': Boolean,
+
+ '-h': '--help',
},
- });
+ { argv, permissive: true },
+ );
const packageManager = (await detectPackageManager(process.cwd()))?.name ?? 'npm';
- const version = args.positionals[0] ?? 'latest';
- const help = !!args.values.help;
- const dryRun = !!args.values['dry-run'];
+ const {
+ _: [version = 'latest'] = [],
+ '--help': help = false,
+ '--dry-run': dryRun,
+ } = flags;
return {
help,
diff --git a/packages/upgrade/test/context.test.js b/packages/upgrade/test/context.test.js
index 5ba484740..bbc887c2a 100644
--- a/packages/upgrade/test/context.test.js
+++ b/packages/upgrade/test/context.test.js
@@ -6,12 +6,12 @@ describe('context', () => {
it('no arguments', async () => {
const ctx = await getContext([]);
assert.equal(ctx.version, 'latest');
- assert.equal(ctx.dryRun, false);
+ assert.equal(ctx.dryRun, undefined);
});
it('tag', async () => {
const ctx = await getContext(['beta']);
assert.equal(ctx.version, 'beta');
- assert.equal(ctx.dryRun, false);
+ assert.equal(ctx.dryRun, undefined);
});
it('dry run', async () => {
const ctx = await getContext(['--dry-run']);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 01db0912e..64c206e7e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -52,8 +52,8 @@ importers:
specifier: ^0.14.1
version: 0.14.1
turbo:
- specifier: ^1.13.4
- version: 1.13.4
+ specifier: ^2.0.12
+ version: 2.0.12
typescript:
specifier: ~5.5.4
version: 5.5.4
@@ -116,7 +116,7 @@ importers:
examples/basics:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/blog:
@@ -131,13 +131,13 @@ importers:
specifier: ^3.1.6
version: link:../../packages/integrations/sitemap
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/component:
devDependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/container-with-vitest:
@@ -146,7 +146,7 @@ importers:
specifier: ^3.6.2
version: link:../../packages/integrations/react
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
react:
specifier: ^18.3.1
@@ -177,7 +177,7 @@ importers:
specifier: ^3.14.1
version: 3.14.1
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/framework-lit:
@@ -189,7 +189,7 @@ importers:
specifier: ^0.2.1
version: 0.2.1
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
lit:
specifier: ^3.2.0
@@ -219,7 +219,7 @@ importers:
specifier: ^18.3.0
version: 18.3.0
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
preact:
specifier: ^10.23.1
@@ -249,7 +249,7 @@ importers:
specifier: ^1.3.0
version: 1.3.0(preact@10.23.1)
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
preact:
specifier: ^10.23.1
@@ -267,7 +267,7 @@ importers:
specifier: ^18.3.0
version: 18.3.0
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
react:
specifier: ^18.3.1
@@ -282,7 +282,7 @@ importers:
specifier: ^4.4.1
version: link:../../packages/integrations/solid
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
solid-js:
specifier: ^1.8.20
@@ -294,7 +294,7 @@ importers:
specifier: ^5.7.0
version: link:../../packages/integrations/svelte
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
svelte:
specifier: ^4.2.18
@@ -306,7 +306,7 @@ importers:
specifier: ^4.5.0
version: link:../../packages/integrations/vue
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
vue:
specifier: ^3.4.37
@@ -318,13 +318,13 @@ importers:
specifier: ^8.3.3
version: link:../../packages/integrations/node
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/integration:
devDependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/middleware:
@@ -333,7 +333,7 @@ importers:
specifier: ^8.3.3
version: link:../../packages/integrations/node
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
html-minifier:
specifier: ^4.0.0
@@ -346,19 +346,19 @@ importers:
examples/minimal:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/non-html-pages:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/portfolio:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/server-islands:
@@ -385,7 +385,7 @@ importers:
specifier: ^18.3.0
version: 18.3.0
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
postcss:
specifier: ^8.4.41
@@ -409,7 +409,7 @@ importers:
specifier: ^5.7.0
version: link:../../packages/integrations/svelte
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
svelte:
specifier: ^4.2.18
@@ -418,7 +418,7 @@ importers:
examples/starlog:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
sass:
specifier: ^1.77.8
@@ -430,7 +430,7 @@ importers:
examples/toolbar-app:
devDependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/view-transitions:
@@ -442,7 +442,7 @@ importers:
specifier: ^5.1.0
version: link:../../packages/integrations/tailwind
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/with-markdoc:
@@ -451,7 +451,7 @@ importers:
specifier: ^0.11.3
version: link:../../packages/integrations/markdoc
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/with-markdown-plugins:
@@ -460,7 +460,7 @@ importers:
specifier: ^5.2.0
version: link:../../packages/markdown/remark
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
hast-util-select:
specifier: ^6.0.2
@@ -481,7 +481,7 @@ importers:
examples/with-markdown-shiki:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
examples/with-mdx:
@@ -493,7 +493,7 @@ importers:
specifier: ^3.5.1
version: link:../../packages/integrations/preact
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
preact:
specifier: ^10.23.1
@@ -508,7 +508,7 @@ importers:
specifier: ^0.5.2
version: 0.5.2(nanostores@0.11.2)(preact@10.23.1)
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
nanostores:
specifier: ^0.11.2
@@ -529,7 +529,7 @@ importers:
specifier: ^1.6.4
version: 1.6.4
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
autoprefixer:
specifier: ^10.4.20
@@ -547,7 +547,7 @@ importers:
examples/with-vitest:
dependencies:
astro:
- specifier: ^4.13.4
+ specifier: ^4.14.2
version: link:../../packages/astro
vitest:
specifier: ^2.0.5
@@ -744,6 +744,9 @@ importers:
xxhash-wasm:
specifier: ^1.0.2
version: 1.0.2
+ yargs-parser:
+ specifier: ^21.1.1
+ version: 21.1.1
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -812,6 +815,9 @@ importers:
'@types/semver':
specifier: ^7.5.8
version: 7.5.8
+ '@types/yargs-parser':
+ specifier: ^21.0.3
+ version: 21.0.3
astro-scripts:
specifier: workspace:*
version: link:../../scripts
@@ -4306,6 +4312,9 @@ importers:
strip-ansi:
specifier: ^7.1.0
version: 7.1.0
+ yargs-parser:
+ specifier: ^21.1.1
+ version: 21.1.1
zod:
specifier: ^3.23.8
version: 3.23.8
@@ -4316,6 +4325,9 @@ importers:
'@types/prompts':
specifier: ^2.4.9
version: 2.4.9
+ '@types/yargs-parser':
+ specifier: ^21.0.3
+ version: 21.0.3
astro:
specifier: workspace:*
version: link:../astro
@@ -7598,6 +7610,9 @@ packages:
'@types/xml2js@0.4.14':
resolution: {integrity: sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==}
+ '@types/yargs-parser@21.0.3':
+ resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
+
'@typescript-eslint/eslint-plugin@8.0.1':
resolution: {integrity: sha512-5g3Y7GDFsJAnY4Yhvk8sZtFfV6YNF2caLzjrRPUBzewjPCaj0yokePB4LJSobyCzGMzjZZYFbwuzbfDHlimXbQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -8281,7 +8296,7 @@ packages:
resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==}
concat-map@0.0.1:
- resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
+ resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
consola@3.2.3:
resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==}
@@ -11224,38 +11239,38 @@ packages:
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
- turbo-darwin-64@1.13.4:
- resolution: {integrity: sha512-A0eKd73R7CGnRinTiS7txkMElg+R5rKFp9HV7baDiEL4xTG1FIg/56Vm7A5RVgg8UNgG2qNnrfatJtb+dRmNdw==}
+ turbo-darwin-64@2.0.12:
+ resolution: {integrity: sha512-NAgfgbXxX/JScWQmmQnGbPuFZq7LIswHfcMk5JwyBXQM/xmklNOxxac7MnGGIOf19Z2f6S3qHy17VIj0SeGfnA==}
cpu: [x64]
os: [darwin]
- turbo-darwin-arm64@1.13.4:
- resolution: {integrity: sha512-eG769Q0NF6/Vyjsr3mKCnkG/eW6dKMBZk6dxWOdrHfrg6QgfkBUk0WUUujzdtVPiUIvsh4l46vQrNVd9EOtbyA==}
+ turbo-darwin-arm64@2.0.12:
+ resolution: {integrity: sha512-cP02uer5KSJ+fXL+OfRRk5hnVjV0c60hxDgNcJxrZpfhun7HHoKDDR7w2xhQntiA45aC6ZZEXRqMKpj6GAmKbg==}
cpu: [arm64]
os: [darwin]
- turbo-linux-64@1.13.4:
- resolution: {integrity: sha512-Bq0JphDeNw3XEi+Xb/e4xoKhs1DHN7OoLVUbTIQz+gazYjigVZvtwCvgrZI7eW9Xo1eOXM2zw2u1DGLLUfmGkQ==}
+ turbo-linux-64@2.0.12:
+ resolution: {integrity: sha512-+mQgGfg1eq5qF+wenK/FKJaNMNAo5DQLC4htQy+8osW+fx6U+8+6UlPQPaycAWDEqwOI7NwuqkeHfkEQLQUTyQ==}
cpu: [x64]
os: [linux]
- turbo-linux-arm64@1.13.4:
- resolution: {integrity: sha512-BJcXw1DDiHO/okYbaNdcWN6szjXyHWx9d460v6fCHY65G8CyqGU3y2uUTPK89o8lq/b2C8NK0yZD+Vp0f9VoIg==}
+ turbo-linux-arm64@2.0.12:
+ resolution: {integrity: sha512-KFyEZDXfPU1DK4zimxdCcqAcK7IIttX4mfsgB7NsSEOmH0dhHOih/YFYiyEDC1lTRx0C2RlzQ0Kjjdz48AN5Eg==}
cpu: [arm64]
os: [linux]
- turbo-windows-64@1.13.4:
- resolution: {integrity: sha512-OFFhXHOFLN7A78vD/dlVuuSSVEB3s9ZBj18Tm1hk3aW1HTWTuAw0ReN6ZNlVObZUHvGy8d57OAGGxf2bT3etQw==}
+ turbo-windows-64@2.0.12:
+ resolution: {integrity: sha512-kJj4KCkZTkDTDCqsSw1m1dbO4WeoQq1mYUm/thXOH0OkeqYbSMt0EyoTcJOgKUDsrMnzZD2gPfYrlYHtV69lVA==}
cpu: [x64]
os: [win32]
- turbo-windows-arm64@1.13.4:
- resolution: {integrity: sha512-u5A+VOKHswJJmJ8o8rcilBfU5U3Y1TTAfP9wX8bFh8teYF1ghP0EhtMRLjhtp6RPa+XCxHHVA2CiC3gbh5eg5g==}
+ turbo-windows-arm64@2.0.12:
+ resolution: {integrity: sha512-TY3ROxguDilN2olCwcZMaePdW01Xhma0pZU7bNhsQEqca9RGAmsZBuzfGnTMcWPmv4tpnb/PlX1hrt1Hod/44Q==}
cpu: [arm64]
os: [win32]
- turbo@1.13.4:
- resolution: {integrity: sha512-1q7+9UJABuBAHrcC4Sxp5lOqYS5mvxRrwa33wpIyM18hlOCpRD/fTJNxZ0vhbMcJmz15o9kkVm743mPn7p6jpQ==}
+ turbo@2.0.12:
+ resolution: {integrity: sha512-8s2KwqjwQj7z8Z53SUZSKVkQOZ2/Sl4D2F440oaBY/k2lGju60dW6srEpnn8/RIDeICZmQn3pQHF79Jfnc5Skw==}
hasBin: true
type-check@0.4.0:
@@ -13557,6 +13572,8 @@ snapshots:
dependencies:
'@types/node': 18.19.31
+ '@types/yargs-parser@21.0.3': {}
+
'@typescript-eslint/eslint-plugin@8.0.1(@typescript-eslint/parser@8.0.1(eslint@9.9.0(jiti@1.21.0))(typescript@5.5.4))(eslint@9.9.0(jiti@1.21.0))(typescript@5.5.4)':
dependencies:
'@eslint-community/regexpp': 4.11.0
@@ -17872,32 +17889,32 @@ snapshots:
tslib@2.6.2: {}
- turbo-darwin-64@1.13.4:
+ turbo-darwin-64@2.0.12:
optional: true
- turbo-darwin-arm64@1.13.4:
+ turbo-darwin-arm64@2.0.12:
optional: true
- turbo-linux-64@1.13.4:
+ turbo-linux-64@2.0.12:
optional: true
- turbo-linux-arm64@1.13.4:
+ turbo-linux-arm64@2.0.12:
optional: true
- turbo-windows-64@1.13.4:
+ turbo-windows-64@2.0.12:
optional: true
- turbo-windows-arm64@1.13.4:
+ turbo-windows-arm64@2.0.12:
optional: true
- turbo@1.13.4:
+ turbo@2.0.12:
optionalDependencies:
- turbo-darwin-64: 1.13.4
- turbo-darwin-arm64: 1.13.4
- turbo-linux-64: 1.13.4
- turbo-linux-arm64: 1.13.4
- turbo-windows-64: 1.13.4
- turbo-windows-arm64: 1.13.4
+ turbo-darwin-64: 2.0.12
+ turbo-darwin-arm64: 2.0.12
+ turbo-linux-64: 2.0.12
+ turbo-linux-arm64: 2.0.12
+ turbo-windows-64: 2.0.12
+ turbo-windows-arm64: 2.0.12
type-check@0.4.0:
dependencies:
diff --git a/turbo.json b/turbo.json
index ffced482b..c873e24c9 100644
--- a/turbo.json
+++ b/turbo.json
@@ -1,48 +1,67 @@
{
- "$schema": "https://turborepo.org/schema.json",
- "pipeline": {
- "build": {
- "dependsOn": ["^build"],
- "inputs": [
- "**/*",
- "!test/**/*",
- "!e2e/**/*",
- "!performance/**/*",
- "!.astro/**/*",
- "!.cache/**/*",
- "!mod.js",
- "!mod.js.map"
- ],
- "outputs": ["dist/**/*", "!vendor/**", "mod.js", "mod.js.map"],
- "outputMode": "new-only"
- },
- "build:ci": {
- "dependsOn": ["^build:ci"],
- "inputs": [
- "**/*",
- "!test/**/*",
- "!e2e/**/*",
- "!performance/**/*",
- "!.astro/**/*",
- "!.cache/**/*",
- "!mod.js",
- "!mod.js.map"
- ],
- "outputs": ["dist/**/*", "!vendor/**", "mod.js", "mod.js.map"],
- "outputMode": "new-only"
- },
- "dev": {
- "cache": false,
- "persistent": true
- },
- "test": {
- "dependsOn": ["^test"],
- "env": ["RUNNER_OS", "NODE_VERSION"],
- "outputMode": "new-only"
- },
- "test:hosted": {
- "outputMode": "new-only",
- "cache": false
- }
- }
+ "$schema": "https://turborepo.org/schema.json",
+ "tasks": {
+ "build": {
+ "dependsOn": [
+ "^build"
+ ],
+ "inputs": [
+ "**/*",
+ "!test/**/*",
+ "!e2e/**/*",
+ "!performance/**/*",
+ "!.astro/**/*",
+ "!.cache/**/*",
+ "!mod.js",
+ "!mod.js.map"
+ ],
+ "outputs": [
+ "dist/**/*",
+ "!vendor/**",
+ "mod.js",
+ "mod.js.map"
+ ],
+ "outputLogs": "new-only"
+ },
+ "build:ci": {
+ "dependsOn": [
+ "^build:ci"
+ ],
+ "inputs": [
+ "**/*",
+ "!test/**/*",
+ "!e2e/**/*",
+ "!performance/**/*",
+ "!.astro/**/*",
+ "!.cache/**/*",
+ "!mod.js",
+ "!mod.js.map"
+ ],
+ "outputs": [
+ "dist/**/*",
+ "!vendor/**",
+ "mod.js",
+ "mod.js.map"
+ ],
+ "outputLogs": "new-only"
+ },
+ "dev": {
+ "cache": false,
+ "persistent": true
+ },
+ "test": {
+ "dependsOn": [
+ "^test"
+ ],
+ "env": [
+ "RUNNER_OS",
+ "NODE_VERSION"
+ ],
+ "outputLogs": "new-only"
+ },
+ "test:hosted": {
+ "cache": false,
+ "outputLogs": "new-only"
+ }
+ }
}