From 1beb56cbff517390f8c0663f231243d43f762ddf Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 24 May 2024 16:03:32 +0100 Subject: [PATCH 01/10] feat(container): provide a virtual module to load renderers --- .changeset/fair-singers-reflect.md | 30 ++++++++++++ .changeset/gold-mayflies-beam.md | 27 +++++++++++ .../test/ReactWrapper.test.ts | 12 ++--- packages/astro/client.d.ts | 4 ++ packages/astro/src/@types/astro.ts | 14 ++++++ packages/astro/src/container/index.ts | 48 +++++-------------- .../astro/src/virtual-modules/container.ts | 33 +++++++++++++ packages/integrations/lit/src/index.ts | 10 +++- packages/integrations/mdx/src/index.ts | 10 +++- packages/integrations/preact/src/index.ts | 9 +++- packages/integrations/react/src/index.ts | 9 +++- packages/integrations/solid/src/index.ts | 11 ++++- packages/integrations/svelte/src/index.ts | 9 +++- packages/integrations/vue/src/index.ts | 9 +++- 14 files changed, 186 insertions(+), 49 deletions(-) create mode 100644 .changeset/fair-singers-reflect.md create mode 100644 .changeset/gold-mayflies-beam.md create mode 100644 packages/astro/src/virtual-modules/container.ts diff --git a/.changeset/fair-singers-reflect.md b/.changeset/fair-singers-reflect.md new file mode 100644 index 000000000000..10a7d01ef2a7 --- /dev/null +++ b/.changeset/fair-singers-reflect.md @@ -0,0 +1,30 @@ +--- +"@astrojs/preact": minor +"@astrojs/svelte": minor +"@astrojs/react": minor +"@astrojs/solid-js": minor +"@astrojs/lit": minor +"@astrojs/mdx": minor +"@astrojs/vue": minor +"astro": patch +--- + +The integration now exposes a function called `getContainerRenderer`, that can be used inside the Container APIs to load the relative renderer. + +```js +import { experimental_AstroContainer as AstroContainer } from 'astro/container'; +import ReactWrapper from '../src/components/ReactWrapper.astro'; +import { loadRenderers} from "astro:container"; +import { getContainerRenderer } from "@astrojs/react"; + +test('ReactWrapper with react renderer', async () => { + const renderers = await loadRenderers([getContainerRenderer(19)]) + const container = await AstroContainer.create({ + renderers, + }); + const result = await container.renderToString(ReactWrapper); + + expect(result).toContain('Counter'); + expect(result).toContain('Count: 5'); +}); +``` diff --git a/.changeset/gold-mayflies-beam.md b/.changeset/gold-mayflies-beam.md new file mode 100644 index 000000000000..43e7256d7711 --- /dev/null +++ b/.changeset/gold-mayflies-beam.md @@ -0,0 +1,27 @@ +--- +"astro": patch +--- + +**BREAKING CHANGE** + +The **type** of the `renderers` option of the `AstroContainer::create` function has been changed. Now, in order to load the renderer, you can use a dedicated function: + +```js +import { experimental_AstroContainer as AstroContainer } from 'astro/container'; +import ReactWrapper from '../src/components/ReactWrapper.astro'; +import { loadRenderers} from "astro:container"; +import { getContainerRenderer } from "@astrojs/react"; + +test('ReactWrapper with react renderer', async () => { + const renderers = await loadRenderers([getContainerRenderer(19)]) + const container = await AstroContainer.create({ + renderers, + }); + const result = await container.renderToString(ReactWrapper); + + expect(result).toContain('Counter'); + expect(result).toContain('Count: 5'); +}); +``` + +The `astro:container` is a virtual module that can be used when running the Astro container inside `vite`. diff --git a/examples/container-with-vitest/test/ReactWrapper.test.ts b/examples/container-with-vitest/test/ReactWrapper.test.ts index 91e3dd09d994..dd357b3855dc 100644 --- a/examples/container-with-vitest/test/ReactWrapper.test.ts +++ b/examples/container-with-vitest/test/ReactWrapper.test.ts @@ -1,16 +1,14 @@ import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import { expect, test } from 'vitest'; import ReactWrapper from '../src/components/ReactWrapper.astro'; +import { loadRenderers} from "astro:container"; +import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { + const renderers = await loadRenderers([getContainerRenderer(19)]) + const container = await AstroContainer.create({ - renderers: [ - { - name: '@astrojs/react', - clientEntrypoint: '@astrojs/react/client.js', - serverEntrypoint: '@astrojs/react/server.js', - }, - ], + renderers, }); const result = await container.renderToString(ReactWrapper); diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index 3083247cfc0f..401e0d0a8376 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -152,6 +152,10 @@ declare module 'astro:i18n' { export * from 'astro/virtual-modules/i18n.js'; } +declare module "astro:container" { + export * from "astro/virtual-modules/container.js"; +} + declare module 'astro:middleware' { export * from 'astro/virtual-modules/middleware.js'; } diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 877b77bd9d25..7ecf2ba58d1b 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -3290,3 +3290,17 @@ declare global { 'astro:page-load': Event; } } + +// Container types +export type ContainerImportRendererFn = (containerRenderer: ContainerRenderer) => Promise; + +export type ContainerRenderer = { + /** + * The name of the renderer. + */ + name: string, + /** + * The entrypoint that is used to render a component on the server + */ + serverEntrypoint: string, +} diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 724c426f39a6..eab8ecdcbd71 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -2,7 +2,7 @@ import { posix } from 'node:path'; import type { AstroRenderer, AstroUserConfig, - ComponentInstance, + ComponentInstance, ContainerImportRendererFn, ContainerRenderer, MiddlewareHandler, Props, RouteData, @@ -83,7 +83,6 @@ export type ContainerRenderOptions = { }; function createManifest( - renderers: SSRLoadedRenderer[], manifest?: AstroContainerManifest, middleware?: MiddlewareHandler ): SSRManifest { @@ -102,7 +101,7 @@ function createManifest( routes: manifest?.routes ?? [], adapterName: '', clientDirectives: manifest?.clientDirectives ?? new Map(), - renderers: manifest?.renderers ?? renderers, + renderers: manifest?.renderers ?? [], base: manifest?.base ?? ASTRO_CONFIG_DEFAULTS.base, componentMetadata: manifest?.componentMetadata ?? new Map(), inlinedScripts: manifest?.inlinedScripts ?? new Map(), @@ -138,21 +137,9 @@ export type AstroContainerOptions = { * @default [] * @description * - * List or renderers to use when rendering components. Usually they are entry points - * - * ## Example - * - * ```js - * const container = await AstroContainer.create({ - * renderers: [{ - * name: "@astrojs/react" - * client: "@astrojs/react/client.js" - * server: "@astrojs/react/server.js" - * }] - * }); - * ``` + * List or renderers to use when rendering components. Usually, you want to pass these in an SSR context. */ - renderers?: AstroRenderer[]; + renderers?: SSRLoadedRenderer[]; /** * @default {} * @description @@ -206,9 +193,14 @@ export class experimental_AstroContainer { */ #withManifest = false; + /** + * Internal function responsible for importing a renderer + * @private + */ + #getRenderer: ContainerImportRendererFn | undefined; + private constructor({ streaming = false, - renderers = [], manifest, resolve, }: AstroContainerConstructor) { @@ -217,10 +209,10 @@ export class experimental_AstroContainer { level: 'info', dest: nodeLogDestination, }), - manifest: createManifest(renderers, manifest), + manifest: createManifest(manifest), streaming, serverLike: true, - renderers, + renderers: [], resolve: async (specifier: string) => { if (this.#withManifest) { return this.#containerResolve(specifier); @@ -249,21 +241,7 @@ export class experimental_AstroContainer { containerOptions: AstroContainerOptions = {} ): Promise { const { streaming = false, renderers = [] } = containerOptions; - const loadedRenderers = await Promise.all( - renderers.map(async (renderer) => { - const mod = await import(renderer.serverEntrypoint); - if (typeof mod.default !== 'undefined') { - return { - ...renderer, - ssr: mod.default, - } as SSRLoadedRenderer; - } - return undefined; - }) - ); - const finalRenderers = loadedRenderers.filter((r): r is SSRLoadedRenderer => Boolean(r)); - - return new experimental_AstroContainer({ streaming, renderers: finalRenderers }); + return new experimental_AstroContainer({ streaming, renderers }); } // NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it. diff --git a/packages/astro/src/virtual-modules/container.ts b/packages/astro/src/virtual-modules/container.ts new file mode 100644 index 000000000000..74ff07903c82 --- /dev/null +++ b/packages/astro/src/virtual-modules/container.ts @@ -0,0 +1,33 @@ +import type {AstroRenderer, SSRLoadedRenderer} from "../@types/astro.js"; + +/** + * Use this function to provide renderers to the `AstroContainer`: + * + * ```js + * import { getContainerRenderer } from "@astrojs/react"; + * import { experimental_AstroContainer as AstroContainer } from "astro/container"; + * import { loadRenderers } from "astro:content"; // use this only when using vite/vitest + * + * const renderers = await loadRenderers([ getContainerRenderer ]); + * const container = await AstroContainer.create({ renderers }); + * + * ``` + * @param renderers + */ +export async function loadRenderers(renderers: AstroRenderer[]) { + const loadedRenderers = await Promise.all( + renderers.map(async (renderer) => { + const mod = await import(renderer.serverEntrypoint); + if (typeof mod.default !== 'undefined') { + return { + ...renderer, + ssr: mod.default, + } as SSRLoadedRenderer; + } + return undefined; + }) + ); + + return loadedRenderers.filter((r): r is SSRLoadedRenderer => Boolean(r)); + +} diff --git a/packages/integrations/lit/src/index.ts b/packages/integrations/lit/src/index.ts index 6c86bd740d2b..dc25c4fc9206 100644 --- a/packages/integrations/lit/src/index.ts +++ b/packages/integrations/lit/src/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs'; -import type { AstroIntegration } from 'astro'; +import type {AstroIntegration, ContainerRenderer} from 'astro'; function getViteConfiguration() { return { @@ -19,6 +19,14 @@ function getViteConfiguration() { }; } +export function getContainerRenderer(): ContainerRenderer { + return { + name: "@astrojs/lit", + serverEntrypoint: '@astrojs/lit/server.js', + } +} + + export default function (): AstroIntegration { return { name: '@astrojs/lit', diff --git a/packages/integrations/mdx/src/index.ts b/packages/integrations/mdx/src/index.ts index 3aaed8787585..579b20eeea1f 100644 --- a/packages/integrations/mdx/src/index.ts +++ b/packages/integrations/mdx/src/index.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import { markdownConfigDefaults } from '@astrojs/markdown-remark'; -import type { AstroIntegration, ContentEntryType, HookParameters } from 'astro'; +import type {AstroIntegration, ContainerRenderer, ContentEntryType, HookParameters} from 'astro'; import astroJSXRenderer from 'astro/jsx/renderer.js'; import type { Options as RemarkRehypeOptions } from 'remark-rehype'; import type { PluggableList } from 'unified'; @@ -28,6 +28,14 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & { addContentEntryType: (contentEntryType: ContentEntryType) => void; }; +export function getContainerRenderer(): ContainerRenderer { + return { + name: "astro:jsx", + serverEntrypoint: 'astro/jsx/server.js', + } +} + + export default function mdx(partialMdxOptions: Partial = {}): AstroIntegration { // @ts-expect-error Temporarily assign an empty object here, which will be re-assigned by the // `astro:config:done` hook later. This is so that `vitePluginMdx` can get hold of a reference earlier. diff --git a/packages/integrations/preact/src/index.ts b/packages/integrations/preact/src/index.ts index bcca01dd0b33..60c45b70c7c6 100644 --- a/packages/integrations/preact/src/index.ts +++ b/packages/integrations/preact/src/index.ts @@ -1,6 +1,6 @@ import { fileURLToPath } from 'node:url'; import { type PreactPluginOptions as VitePreactPluginOptions, preact } from '@preact/preset-vite'; -import type { AstroIntegration, AstroRenderer, ViteUserConfig } from 'astro'; +import type {AstroIntegration, AstroRenderer, ContainerRenderer, ViteUserConfig} from 'astro'; const babelCwd = new URL('../', import.meta.url); @@ -12,6 +12,13 @@ function getRenderer(development: boolean): AstroRenderer { }; } +export function getContainerRenderer(): ContainerRenderer { + return { + name: "@astrojs/preact", + serverEntrypoint: '@astrojs/preact/server.js', + } +} + export interface Options extends Pick { compat?: boolean; devtools?: boolean; diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index 838640239ee3..efe78b6a5cbe 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -1,5 +1,5 @@ import react, { type Options as ViteReactPluginOptions } from '@vitejs/plugin-react'; -import type { AstroIntegration } from 'astro'; +import type { AstroIntegration, ContainerRenderer } from 'astro'; import { version as ReactVersion } from 'react-dom'; import type * as vite from 'vite'; @@ -53,6 +53,13 @@ function getRenderer(reactConfig: ReactVersionConfig) { }; } +export function getContainerRenderer(reactVersion: ReactVersionConfig): ContainerRenderer { + return { + name: "@astrojs/react", + serverEntrypoint: reactVersion.server, + } +} + function optionsPlugin(experimentalReactChildren: boolean): vite.Plugin { const virtualModule = 'astro:react:opts'; const virtualModuleId = '\0' + virtualModule; diff --git a/packages/integrations/solid/src/index.ts b/packages/integrations/solid/src/index.ts index a779dea6083e..1d7131b26252 100644 --- a/packages/integrations/solid/src/index.ts +++ b/packages/integrations/solid/src/index.ts @@ -1,4 +1,4 @@ -import type { AstroIntegration, AstroIntegrationLogger, AstroRenderer } from 'astro'; +import type {AstroIntegration, AstroIntegrationLogger, AstroRenderer, ContainerRenderer} from 'astro'; import type { PluginOption, UserConfig } from 'vite'; import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid'; @@ -94,6 +94,15 @@ function getRenderer(): AstroRenderer { }; } + +export function getContainerRenderer(): ContainerRenderer { + return { + name: "@astrojs/solid", + serverEntrypoint: '@astrojs/solid-js/server.js', + } +} + + export interface Options extends Pick { devtools?: boolean; } diff --git a/packages/integrations/svelte/src/index.ts b/packages/integrations/svelte/src/index.ts index 9c38b9d0518f..772e4895215a 100644 --- a/packages/integrations/svelte/src/index.ts +++ b/packages/integrations/svelte/src/index.ts @@ -1,7 +1,7 @@ import { fileURLToPath } from 'node:url'; import type { Options } from '@sveltejs/vite-plugin-svelte'; import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -import type { AstroIntegration, AstroRenderer } from 'astro'; +import type {AstroIntegration, AstroRenderer, ContainerRenderer} from 'astro'; import { VERSION } from 'svelte/compiler'; import type { UserConfig } from 'vite'; @@ -15,6 +15,13 @@ function getRenderer(): AstroRenderer { }; } +export function getContainerRenderer(): ContainerRenderer { + return { + name: "@astrojs/svelte", + serverEntrypoint: isSvelte5 ? '@astrojs/svelte/server-v5.js' : '@astrojs/svelte/server.js', + } +} + async function svelteConfigHasPreprocess(root: URL) { const svelteConfigFiles = ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs']; for (const file of svelteConfigFiles) { diff --git a/packages/integrations/vue/src/index.ts b/packages/integrations/vue/src/index.ts index 6edb82526fa4..70365a2acee6 100644 --- a/packages/integrations/vue/src/index.ts +++ b/packages/integrations/vue/src/index.ts @@ -3,7 +3,7 @@ import type { Options as VueOptions } from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue'; import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx'; import { MagicString } from '@vue/compiler-sfc'; -import type { AstroIntegration, AstroRenderer, HookParameters } from 'astro'; +import type {AstroIntegration, AstroRenderer, ContainerRenderer, HookParameters} from 'astro'; import type { Plugin, UserConfig } from 'vite'; import type { VitePluginVueDevToolsOptions } from 'vite-plugin-vue-devtools'; @@ -32,6 +32,13 @@ function getJsxRenderer(): AstroRenderer { }; } +export function getContainerRenderer(): ContainerRenderer { + return { + name: "@astrojs/vue", + serverEntrypoint: '@astrojs/vue/server.js' + } +} + function virtualAppEntrypoint(options?: Options): Plugin { let isBuild: boolean; let root: string; From fd6c18878c97d3cb84a00d7f6abfeda4a795dd7d Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 24 May 2024 16:33:58 +0100 Subject: [PATCH 02/10] address feedback --- examples/container-with-vitest/package.json | 4 ++-- .../container-with-vitest/test/ReactWrapper.test.ts | 10 ++++++---- packages/astro/src/virtual-modules/container.ts | 2 +- packages/integrations/react/src/index.ts | 10 ++++++++-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/examples/container-with-vitest/package.json b/examples/container-with-vitest/package.json index 8f07d620c044..e8cb1536a96c 100644 --- a/examples/container-with-vitest/package.json +++ b/examples/container-with-vitest/package.json @@ -12,8 +12,8 @@ "test": "vitest run" }, "dependencies": { - "astro": "^4.9.3", - "@astrojs/react": "^3.4.0", + "astro": "experimental--container", + "@astrojs/react": "experimental--container", "react": "^18.3.1", "react-dom": "^18.3.1", "vitest": "^1.6.0" diff --git a/examples/container-with-vitest/test/ReactWrapper.test.ts b/examples/container-with-vitest/test/ReactWrapper.test.ts index dd357b3855dc..6a9e4726825d 100644 --- a/examples/container-with-vitest/test/ReactWrapper.test.ts +++ b/examples/container-with-vitest/test/ReactWrapper.test.ts @@ -4,12 +4,14 @@ import ReactWrapper from '../src/components/ReactWrapper.astro'; import { loadRenderers} from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; +const renderers = await loadRenderers([getContainerRenderer()]) +const container = await AstroContainer.create({ + renderers, +}); + + test('ReactWrapper with react renderer', async () => { - const renderers = await loadRenderers([getContainerRenderer(19)]) - const container = await AstroContainer.create({ - renderers, - }); const result = await container.renderToString(ReactWrapper); expect(result).toContain('Counter'); diff --git a/packages/astro/src/virtual-modules/container.ts b/packages/astro/src/virtual-modules/container.ts index 74ff07903c82..0550f18ea6c0 100644 --- a/packages/astro/src/virtual-modules/container.ts +++ b/packages/astro/src/virtual-modules/container.ts @@ -6,7 +6,7 @@ import type {AstroRenderer, SSRLoadedRenderer} from "../@types/astro.js"; * ```js * import { getContainerRenderer } from "@astrojs/react"; * import { experimental_AstroContainer as AstroContainer } from "astro/container"; - * import { loadRenderers } from "astro:content"; // use this only when using vite/vitest + * import { loadRenderers } from "astro:container"; // use this only when using vite/vitest * * const renderers = await loadRenderers([ getContainerRenderer ]); * const container = await AstroContainer.create({ renderers }); diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index efe78b6a5cbe..ebe8107f81f8 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -53,10 +53,16 @@ function getRenderer(reactConfig: ReactVersionConfig) { }; } -export function getContainerRenderer(reactVersion: ReactVersionConfig): ContainerRenderer { +export function getContainerRenderer(): ContainerRenderer { + const majorVersion = getReactMajorVersion(); + if (isUnsupportedVersion(majorVersion)) { + throw new Error(`Unsupported React version: ${majorVersion}.`); + } + const versionConfig = versionsConfig[majorVersion as SupportedReactVersion]; + return { name: "@astrojs/react", - serverEntrypoint: reactVersion.server, + serverEntrypoint: versionConfig.server, } } From 1bc8431d66eefb77fa2e065087d19cb8554dbda5 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Fri, 24 May 2024 17:08:58 +0100 Subject: [PATCH 03/10] chore: restore some default to allow to have PHP prototype working --- .../test/ReactWrapper.test.ts | 8 ++--- packages/astro/client.d.ts | 4 +-- packages/astro/src/@types/astro.ts | 10 ++++--- packages/astro/src/container/index.ts | 30 +++++++++++++------ .../astro/src/virtual-modules/container.ts | 9 +++--- packages/integrations/lit/src/index.ts | 7 ++--- packages/integrations/mdx/src/index.ts | 7 ++--- packages/integrations/preact/src/index.ts | 6 ++-- packages/integrations/react/src/index.ts | 6 ++-- packages/integrations/solid/src/index.ts | 13 ++++---- packages/integrations/svelte/src/index.ts | 6 ++-- packages/integrations/vue/src/index.ts | 8 ++--- 12 files changed, 63 insertions(+), 51 deletions(-) diff --git a/examples/container-with-vitest/test/ReactWrapper.test.ts b/examples/container-with-vitest/test/ReactWrapper.test.ts index 6a9e4726825d..70b938708332 100644 --- a/examples/container-with-vitest/test/ReactWrapper.test.ts +++ b/examples/container-with-vitest/test/ReactWrapper.test.ts @@ -1,17 +1,15 @@ import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import { expect, test } from 'vitest'; import ReactWrapper from '../src/components/ReactWrapper.astro'; -import { loadRenderers} from "astro:container"; -import { getContainerRenderer } from "@astrojs/react"; +import { loadRenderers } from 'astro:container'; +import { getContainerRenderer } from '@astrojs/react'; -const renderers = await loadRenderers([getContainerRenderer()]) +const renderers = await loadRenderers([getContainerRenderer()]); const container = await AstroContainer.create({ renderers, }); - test('ReactWrapper with react renderer', async () => { - const result = await container.renderToString(ReactWrapper); expect(result).toContain('Counter'); diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index 401e0d0a8376..0870d3dcc566 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -152,8 +152,8 @@ declare module 'astro:i18n' { export * from 'astro/virtual-modules/i18n.js'; } -declare module "astro:container" { - export * from "astro/virtual-modules/container.js"; +declare module 'astro:container' { + export * from 'astro/virtual-modules/container.js'; } declare module 'astro:middleware' { diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 7ecf2ba58d1b..ab1af4048750 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -3292,15 +3292,17 @@ declare global { } // Container types -export type ContainerImportRendererFn = (containerRenderer: ContainerRenderer) => Promise; +export type ContainerImportRendererFn = ( + containerRenderer: ContainerRenderer +) => Promise; export type ContainerRenderer = { /** * The name of the renderer. */ - name: string, + name: string; /** * The entrypoint that is used to render a component on the server */ - serverEntrypoint: string, -} + serverEntrypoint: string; +}; diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index eab8ecdcbd71..d72a6036fa4c 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -1,8 +1,11 @@ import { posix } from 'node:path'; import type { + AstroConfig, AstroRenderer, AstroUserConfig, - ComponentInstance, ContainerImportRendererFn, ContainerRenderer, + ComponentInstance, + ContainerImportRendererFn, + ContainerRenderer, MiddlewareHandler, Props, RouteData, @@ -84,6 +87,7 @@ export type ContainerRenderOptions = { function createManifest( manifest?: AstroContainerManifest, + renderers?: SSRLoadedRenderer[], middleware?: MiddlewareHandler ): SSRManifest { const defaultMiddleware: MiddlewareHandler = (_, next) => { @@ -101,7 +105,7 @@ function createManifest( routes: manifest?.routes ?? [], adapterName: '', clientDirectives: manifest?.clientDirectives ?? new Map(), - renderers: manifest?.renderers ?? [], + renderers: renderers ?? manifest?.renderers ?? [], base: manifest?.base ?? ASTRO_CONFIG_DEFAULTS.base, componentMetadata: manifest?.componentMetadata ?? new Map(), inlinedScripts: manifest?.inlinedScripts ?? new Map(), @@ -157,6 +161,9 @@ export type AstroContainerOptions = { * ``` */ astroConfig?: AstroContainerUserConfig; + + // TODO: document out of experimental + resolve?: SSRResult['resolve']; }; type AstroContainerManifest = Pick< @@ -182,6 +189,7 @@ type AstroContainerConstructor = { renderers?: SSRLoadedRenderer[]; manifest?: AstroContainerManifest; resolve?: SSRResult['resolve']; + astroConfig: AstroConfig; }; export class experimental_AstroContainer { @@ -202,20 +210,22 @@ export class experimental_AstroContainer { private constructor({ streaming = false, manifest, + renderers, resolve, + astroConfig, }: AstroContainerConstructor) { this.#pipeline = ContainerPipeline.create({ logger: new Logger({ level: 'info', dest: nodeLogDestination, }), - manifest: createManifest(manifest), + manifest: createManifest(manifest, renderers), streaming, serverLike: true, renderers: [], resolve: async (specifier: string) => { if (this.#withManifest) { - return this.#containerResolve(specifier); + return this.#containerResolve(specifier, astroConfig); } else if (resolve) { return resolve(specifier); } @@ -224,10 +234,10 @@ export class experimental_AstroContainer { }); } - async #containerResolve(specifier: string): Promise { + async #containerResolve(specifier: string, astroConfig: AstroConfig): Promise { const found = this.#pipeline.manifest.entryModules[specifier]; if (found) { - return new URL(found, ASTRO_CONFIG_DEFAULTS.build.client).toString(); + return new URL(found, astroConfig.build.client).toString(); } return found; } @@ -240,8 +250,9 @@ export class experimental_AstroContainer { public static async create( containerOptions: AstroContainerOptions = {} ): Promise { - const { streaming = false, renderers = [] } = containerOptions; - return new experimental_AstroContainer({ streaming, renderers }); + const { streaming = false, renderers = [], resolve } = containerOptions; + const astroConfig = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container'); + return new experimental_AstroContainer({ streaming, renderers, astroConfig, resolve }); } // NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it. @@ -249,9 +260,10 @@ export class experimental_AstroContainer { private static async createFromManifest( manifest: SSRManifest ): Promise { - const config = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container'); + const astroConfig = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container'); const container = new experimental_AstroContainer({ manifest, + astroConfig, }); container.#withManifest = true; return container; diff --git a/packages/astro/src/virtual-modules/container.ts b/packages/astro/src/virtual-modules/container.ts index 0550f18ea6c0..a4da62972d62 100644 --- a/packages/astro/src/virtual-modules/container.ts +++ b/packages/astro/src/virtual-modules/container.ts @@ -1,16 +1,16 @@ -import type {AstroRenderer, SSRLoadedRenderer} from "../@types/astro.js"; +import type { AstroRenderer, SSRLoadedRenderer } from '../@types/astro.js'; /** * Use this function to provide renderers to the `AstroContainer`: - * + * * ```js * import { getContainerRenderer } from "@astrojs/react"; * import { experimental_AstroContainer as AstroContainer } from "astro/container"; * import { loadRenderers } from "astro:container"; // use this only when using vite/vitest - * + * * const renderers = await loadRenderers([ getContainerRenderer ]); * const container = await AstroContainer.create({ renderers }); - * + * * ``` * @param renderers */ @@ -29,5 +29,4 @@ export async function loadRenderers(renderers: AstroRenderer[]) { ); return loadedRenderers.filter((r): r is SSRLoadedRenderer => Boolean(r)); - } diff --git a/packages/integrations/lit/src/index.ts b/packages/integrations/lit/src/index.ts index dc25c4fc9206..33aaf727d918 100644 --- a/packages/integrations/lit/src/index.ts +++ b/packages/integrations/lit/src/index.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs'; -import type {AstroIntegration, ContainerRenderer} from 'astro'; +import type { AstroIntegration, ContainerRenderer } from 'astro'; function getViteConfiguration() { return { @@ -21,12 +21,11 @@ function getViteConfiguration() { export function getContainerRenderer(): ContainerRenderer { return { - name: "@astrojs/lit", + name: '@astrojs/lit', serverEntrypoint: '@astrojs/lit/server.js', - } + }; } - export default function (): AstroIntegration { return { name: '@astrojs/lit', diff --git a/packages/integrations/mdx/src/index.ts b/packages/integrations/mdx/src/index.ts index 579b20eeea1f..bd0278933aea 100644 --- a/packages/integrations/mdx/src/index.ts +++ b/packages/integrations/mdx/src/index.ts @@ -1,7 +1,7 @@ import fs from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import { markdownConfigDefaults } from '@astrojs/markdown-remark'; -import type {AstroIntegration, ContainerRenderer, ContentEntryType, HookParameters} from 'astro'; +import type { AstroIntegration, ContainerRenderer, ContentEntryType, HookParameters } from 'astro'; import astroJSXRenderer from 'astro/jsx/renderer.js'; import type { Options as RemarkRehypeOptions } from 'remark-rehype'; import type { PluggableList } from 'unified'; @@ -30,12 +30,11 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & { export function getContainerRenderer(): ContainerRenderer { return { - name: "astro:jsx", + name: 'astro:jsx', serverEntrypoint: 'astro/jsx/server.js', - } + }; } - export default function mdx(partialMdxOptions: Partial = {}): AstroIntegration { // @ts-expect-error Temporarily assign an empty object here, which will be re-assigned by the // `astro:config:done` hook later. This is so that `vitePluginMdx` can get hold of a reference earlier. diff --git a/packages/integrations/preact/src/index.ts b/packages/integrations/preact/src/index.ts index 60c45b70c7c6..aab4f9925fbc 100644 --- a/packages/integrations/preact/src/index.ts +++ b/packages/integrations/preact/src/index.ts @@ -1,6 +1,6 @@ import { fileURLToPath } from 'node:url'; import { type PreactPluginOptions as VitePreactPluginOptions, preact } from '@preact/preset-vite'; -import type {AstroIntegration, AstroRenderer, ContainerRenderer, ViteUserConfig} from 'astro'; +import type { AstroIntegration, AstroRenderer, ContainerRenderer, ViteUserConfig } from 'astro'; const babelCwd = new URL('../', import.meta.url); @@ -14,9 +14,9 @@ function getRenderer(development: boolean): AstroRenderer { export function getContainerRenderer(): ContainerRenderer { return { - name: "@astrojs/preact", + name: '@astrojs/preact', serverEntrypoint: '@astrojs/preact/server.js', - } + }; } export interface Options extends Pick { diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index ebe8107f81f8..85d79eef88a6 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -59,11 +59,11 @@ export function getContainerRenderer(): ContainerRenderer { throw new Error(`Unsupported React version: ${majorVersion}.`); } const versionConfig = versionsConfig[majorVersion as SupportedReactVersion]; - + return { - name: "@astrojs/react", + name: '@astrojs/react', serverEntrypoint: versionConfig.server, - } + }; } function optionsPlugin(experimentalReactChildren: boolean): vite.Plugin { diff --git a/packages/integrations/solid/src/index.ts b/packages/integrations/solid/src/index.ts index 1d7131b26252..1bbfa741f078 100644 --- a/packages/integrations/solid/src/index.ts +++ b/packages/integrations/solid/src/index.ts @@ -1,4 +1,9 @@ -import type {AstroIntegration, AstroIntegrationLogger, AstroRenderer, ContainerRenderer} from 'astro'; +import type { + AstroIntegration, + AstroIntegrationLogger, + AstroRenderer, + ContainerRenderer, +} from 'astro'; import type { PluginOption, UserConfig } from 'vite'; import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid'; @@ -94,15 +99,13 @@ function getRenderer(): AstroRenderer { }; } - export function getContainerRenderer(): ContainerRenderer { return { - name: "@astrojs/solid", + name: '@astrojs/solid', serverEntrypoint: '@astrojs/solid-js/server.js', - } + }; } - export interface Options extends Pick { devtools?: boolean; } diff --git a/packages/integrations/svelte/src/index.ts b/packages/integrations/svelte/src/index.ts index 772e4895215a..b0db3505c83a 100644 --- a/packages/integrations/svelte/src/index.ts +++ b/packages/integrations/svelte/src/index.ts @@ -1,7 +1,7 @@ import { fileURLToPath } from 'node:url'; import type { Options } from '@sveltejs/vite-plugin-svelte'; import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'; -import type {AstroIntegration, AstroRenderer, ContainerRenderer} from 'astro'; +import type { AstroIntegration, AstroRenderer, ContainerRenderer } from 'astro'; import { VERSION } from 'svelte/compiler'; import type { UserConfig } from 'vite'; @@ -17,9 +17,9 @@ function getRenderer(): AstroRenderer { export function getContainerRenderer(): ContainerRenderer { return { - name: "@astrojs/svelte", + name: '@astrojs/svelte', serverEntrypoint: isSvelte5 ? '@astrojs/svelte/server-v5.js' : '@astrojs/svelte/server.js', - } + }; } async function svelteConfigHasPreprocess(root: URL) { diff --git a/packages/integrations/vue/src/index.ts b/packages/integrations/vue/src/index.ts index 70365a2acee6..81afe3a2eb5d 100644 --- a/packages/integrations/vue/src/index.ts +++ b/packages/integrations/vue/src/index.ts @@ -3,7 +3,7 @@ import type { Options as VueOptions } from '@vitejs/plugin-vue'; import vue from '@vitejs/plugin-vue'; import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx'; import { MagicString } from '@vue/compiler-sfc'; -import type {AstroIntegration, AstroRenderer, ContainerRenderer, HookParameters} from 'astro'; +import type { AstroIntegration, AstroRenderer, ContainerRenderer, HookParameters } from 'astro'; import type { Plugin, UserConfig } from 'vite'; import type { VitePluginVueDevToolsOptions } from 'vite-plugin-vue-devtools'; @@ -34,9 +34,9 @@ function getJsxRenderer(): AstroRenderer { export function getContainerRenderer(): ContainerRenderer { return { - name: "@astrojs/vue", - serverEntrypoint: '@astrojs/vue/server.js' - } + name: '@astrojs/vue', + serverEntrypoint: '@astrojs/vue/server.js', + }; } function virtualAppEntrypoint(options?: Options): Plugin { From 2f7deaaaae8cd9ad7a33fd409d99efd52a0606fc Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Fri, 24 May 2024 13:14:42 -0400 Subject: [PATCH 04/10] Thread through renderers and manifest --- packages/astro/src/container/index.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index d72a6036fa4c..490b1e7da034 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -164,6 +164,14 @@ export type AstroContainerOptions = { // TODO: document out of experimental resolve?: SSRResult['resolve']; + + /** + * @default {} + * @description + * + * The raw manifest from the build output. + */ + manifest?: SSRManifest; }; type AstroContainerManifest = Pick< @@ -222,7 +230,7 @@ export class experimental_AstroContainer { manifest: createManifest(manifest, renderers), streaming, serverLike: true, - renderers: [], + renderers: renderers ?? manifest?.renderers ?? [], resolve: async (specifier: string) => { if (this.#withManifest) { return this.#containerResolve(specifier, astroConfig); @@ -250,7 +258,7 @@ export class experimental_AstroContainer { public static async create( containerOptions: AstroContainerOptions = {} ): Promise { - const { streaming = false, renderers = [], resolve } = containerOptions; + const { streaming = false, manifest, renderers = [], resolve } = containerOptions; const astroConfig = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container'); return new experimental_AstroContainer({ streaming, renderers, astroConfig, resolve }); } From ad264918d4c1a47176b59d25192c9275ebadbd6b Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Fri, 24 May 2024 13:21:41 -0400 Subject: [PATCH 05/10] Pass manifest too --- packages/astro/src/container/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 490b1e7da034..5a260685374b 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -260,7 +260,7 @@ export class experimental_AstroContainer { ): Promise { const { streaming = false, manifest, renderers = [], resolve } = containerOptions; const astroConfig = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container'); - return new experimental_AstroContainer({ streaming, renderers, astroConfig, resolve }); + return new experimental_AstroContainer({ streaming, manifest, renderers, astroConfig, resolve }); } // NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it. From 53e5787e9318c2e33c758255dd9aa850e8f433f6 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 4 Jun 2024 09:49:29 +0100 Subject: [PATCH 06/10] update changeset --- .changeset/fair-singers-reflect.md | 4 ++-- .changeset/gold-mayflies-beam.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.changeset/fair-singers-reflect.md b/.changeset/fair-singers-reflect.md index 10a7d01ef2a7..64e8f94a5f95 100644 --- a/.changeset/fair-singers-reflect.md +++ b/.changeset/fair-singers-reflect.md @@ -14,11 +14,11 @@ The integration now exposes a function called `getContainerRenderer`, that can b ```js import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import ReactWrapper from '../src/components/ReactWrapper.astro'; -import { loadRenderers} from "astro:container"; +import { loadRenderers } from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { - const renderers = await loadRenderers([getContainerRenderer(19)]) + const renderers = await loadRenderers([getContainerRenderer()]) const container = await AstroContainer.create({ renderers, }); diff --git a/.changeset/gold-mayflies-beam.md b/.changeset/gold-mayflies-beam.md index 43e7256d7711..9a39e2f86d2f 100644 --- a/.changeset/gold-mayflies-beam.md +++ b/.changeset/gold-mayflies-beam.md @@ -9,11 +9,11 @@ The **type** of the `renderers` option of the `AstroContainer::create` function ```js import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import ReactWrapper from '../src/components/ReactWrapper.astro'; -import { loadRenderers} from "astro:container"; +import { loadRenderers } from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { - const renderers = await loadRenderers([getContainerRenderer(19)]) + const renderers = await loadRenderers([getContainerRenderer()]) const container = await AstroContainer.create({ renderers, }); From 90020407e993274fff372d2a30a9c36c239d501c Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 4 Jun 2024 13:43:13 +0100 Subject: [PATCH 07/10] add diff --- .changeset/fair-singers-reflect.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.changeset/fair-singers-reflect.md b/.changeset/fair-singers-reflect.md index 64e8f94a5f95..fcb4131be21f 100644 --- a/.changeset/fair-singers-reflect.md +++ b/.changeset/fair-singers-reflect.md @@ -11,14 +11,21 @@ The integration now exposes a function called `getContainerRenderer`, that can be used inside the Container APIs to load the relative renderer. -```js +```diff import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import ReactWrapper from '../src/components/ReactWrapper.astro'; import { loadRenderers } from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { - const renderers = await loadRenderers([getContainerRenderer()]) ++ const renderers = await loadRenderers([getContainerRenderer()]) +- const renderers = [ +- { +- name: '@astrojs/react', +- clientEntrypoint: '@astrojs/react/client.js', +- serverEntrypoint: '@astrojs/react/server.js', +- }, +- ]; const container = await AstroContainer.create({ renderers, }); From 3bf85c2547b22a08123a4791594600308714daf0 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 4 Jun 2024 13:43:54 +0100 Subject: [PATCH 08/10] Apply suggestions from code review Co-authored-by: Sarah Rainsberger --- .changeset/gold-mayflies-beam.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.changeset/gold-mayflies-beam.md b/.changeset/gold-mayflies-beam.md index 9a39e2f86d2f..125c6498c3a6 100644 --- a/.changeset/gold-mayflies-beam.md +++ b/.changeset/gold-mayflies-beam.md @@ -2,9 +2,11 @@ "astro": patch --- -**BREAKING CHANGE** +**BREAKING CHANGE to the experimental Container API only** -The **type** of the `renderers` option of the `AstroContainer::create` function has been changed. Now, in order to load the renderer, you can use a dedicated function: +Changes the **type** of the `renderers` option of the `AstroContainer::create` function and adds a dedicated function `loadRenderers()` to load the rendering scripts from renderer integration packages (`@astrojs/react`, `@astrojs/preact`, `@astrojs/solid-js`, `@astrojs/svelte`, `@astrojs/vue`, `@astrojs/lit`, and `@astrojs/mdx`). + +You no longer need to know the individual, direct file paths to the client and server rendering scripts for each renderer integration package. Now, there is a dedicated function to load the renderer from each package, which is available from `getContainerRenderer()`: ```js import { experimental_AstroContainer as AstroContainer } from 'astro/container'; @@ -24,4 +26,4 @@ test('ReactWrapper with react renderer', async () => { }); ``` -The `astro:container` is a virtual module that can be used when running the Astro container inside `vite`. +The new `loadRenderers()` helper function is available from `astro:container`, a virtual module that can be used when running the Astro container inside `vite`. From 72f1bdc45dad8e301dd43e13bfd422c2ceee0038 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Tue, 4 Jun 2024 13:44:46 +0100 Subject: [PATCH 09/10] fix diff --- .changeset/fair-singers-reflect.md | 23 ++++++++--------------- .changeset/gold-mayflies-beam.md | 23 +++++++++++++++-------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.changeset/fair-singers-reflect.md b/.changeset/fair-singers-reflect.md index fcb4131be21f..e18ec42f9cf8 100644 --- a/.changeset/fair-singers-reflect.md +++ b/.changeset/fair-singers-reflect.md @@ -11,27 +11,20 @@ The integration now exposes a function called `getContainerRenderer`, that can be used inside the Container APIs to load the relative renderer. -```diff +```js import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import ReactWrapper from '../src/components/ReactWrapper.astro'; import { loadRenderers } from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { -+ const renderers = await loadRenderers([getContainerRenderer()]) -- const renderers = [ -- { -- name: '@astrojs/react', -- clientEntrypoint: '@astrojs/react/client.js', -- serverEntrypoint: '@astrojs/react/server.js', -- }, -- ]; - const container = await AstroContainer.create({ - renderers, - }); - const result = await container.renderToString(ReactWrapper); + const renderers = await loadRenderers([getContainerRenderer()]) + const container = await AstroContainer.create({ + renderers, + }); + const result = await container.renderToString(ReactWrapper); - expect(result).toContain('Counter'); - expect(result).toContain('Count: 5'); + expect(result).toContain('Counter'); + expect(result).toContain('Count: 5'); }); ``` diff --git a/.changeset/gold-mayflies-beam.md b/.changeset/gold-mayflies-beam.md index 125c6498c3a6..d500b30b41c6 100644 --- a/.changeset/gold-mayflies-beam.md +++ b/.changeset/gold-mayflies-beam.md @@ -8,21 +8,28 @@ Changes the **type** of the `renderers` option of the `AstroContainer::create` f You no longer need to know the individual, direct file paths to the client and server rendering scripts for each renderer integration package. Now, there is a dedicated function to load the renderer from each package, which is available from `getContainerRenderer()`: -```js +```diff import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import ReactWrapper from '../src/components/ReactWrapper.astro'; import { loadRenderers } from "astro:container"; import { getContainerRenderer } from "@astrojs/react"; test('ReactWrapper with react renderer', async () => { - const renderers = await loadRenderers([getContainerRenderer()]) - const container = await AstroContainer.create({ - renderers, - }); - const result = await container.renderToString(ReactWrapper); ++ const renderers = await loadRenderers([getContainerRenderer()]) +- const renderers = [ +- { +- name: '@astrojs/react', +- clientEntrypoint: '@astrojs/react/client.js', +- serverEntrypoint: '@astrojs/react/server.js', +- }, +- ]; + const container = await AstroContainer.create({ + renderers, + }); + const result = await container.renderToString(ReactWrapper); - expect(result).toContain('Counter'); - expect(result).toContain('Count: 5'); + expect(result).toContain('Counter'); + expect(result).toContain('Count: 5'); }); ``` From 7a59701dbc608ff17977892ed0cd8bad2d4d9ee1 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 5 Jun 2024 10:16:24 +0100 Subject: [PATCH 10/10] rebase and update lock --- pnpm-lock.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2d24ea4f9487..72df592a74e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -155,10 +155,10 @@ importers: examples/container-with-vitest: dependencies: '@astrojs/react': - specifier: ^3.4.0 + specifier: experimental--container version: link:../../packages/integrations/react astro: - specifier: ^4.9.3 + specifier: experimental--container version: link:../../packages/astro react: specifier: ^18.3.1