feat: return clientEntrypoint from getContainerRenderer (#14715)

* feat: return `clientEntrypoint` from `getContainerRenderer`

* ✂️
This commit is contained in:
Matt Kane
2025-11-05 07:35:28 +00:00
committed by GitHub
parent a4d284dad1
commit 3d55c5d0fb
12 changed files with 48 additions and 59 deletions

View File

@@ -0,0 +1,15 @@
---
'@astrojs/preact': patch
'@astrojs/svelte': patch
'@astrojs/react': patch
'@astrojs/solid-js': patch
'@astrojs/mdx': patch
'@astrojs/vue': patch
'astro': patch
---
Adds support for client hydration in `getContainerRenderer()`
The `getContainerRenderer()` function is exported by Astro framework integrations to simplify the process of rendering framework components when using the experimental Container API inside a Vite or Vitest environment. This update adds the client hydration entrypoint to the returned object, enabling client-side interactivity for components rendered using this function. Previously this required users to manually call `container.addClientRenderer()` with the appropriate client renderer entrypoint.
See [the `container-with-vitest` demo](https://github.com/withastro/astro/blob/main/examples/container-with-vitest/test/ReactWrapper.test.ts) for a usage example, and [the Container API documentation](https://docs.astro.build/en/reference/container-reference/#renderers-option) for more information on using framework components with the experimental Container API.

View File

@@ -2,4 +2,4 @@
import Counter from './Counter.jsx';
---
<Counter initialCount={5} />
<Counter initialCount={5} client:load />

View File

@@ -14,4 +14,7 @@ test('ReactWrapper with react renderer', async () => {
expect(result).toContain('Counter');
expect(result).toContain('Count: <!-- -->5');
expect(result, 'Includes client hydration reference').toContain(
'renderer-url="@astrojs/react/client.js"',
);
});

View File

@@ -28,7 +28,10 @@ import type {
} from '../types/public/internal.js';
import { ContainerPipeline } from './pipeline.js';
/** Public type, used for integrations to define a renderer for the container API */
/**
* Public type, used for integrations to define a renderer for the container API
* @deprecated Use `AstroRenderer` instead.
*/
export type ContainerRenderer = {
/**
* The name of the renderer.

View File

@@ -1,4 +1,4 @@
import type { AstroIntegration, AstroRenderer, ContainerRenderer } from 'astro';
import type { AstroIntegration, AstroRenderer } from 'astro';
const getRenderer = (): AstroRenderer => ({
name: 'custom-renderer',
@@ -6,10 +6,7 @@ const getRenderer = (): AstroRenderer => ({
serverEntrypoint: '@custom-renderer/server',
})
export const getContainerRenderer = (): ContainerRenderer => ({
name: 'custom-renderer',
serverEntrypoint: '@custom-renderer/server',
})
export { getRenderer as getContainerRenderer };
export default function (): AstroIntegration {
return {
@@ -20,4 +17,4 @@ export default function (): AstroIntegration {
},
},
};
}
}

View File

@@ -4,7 +4,7 @@ import { markdownConfigDefaults } from '@astrojs/markdown-remark';
import type {
AstroIntegration,
AstroIntegrationLogger,
ContainerRenderer,
AstroRenderer,
ContentEntryType,
HookParameters,
} from 'astro';
@@ -33,7 +33,7 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & {
addContentEntryType: (contentEntryType: ContentEntryType) => void;
};
export function getContainerRenderer(): ContainerRenderer {
export function getContainerRenderer(): AstroRenderer {
return {
name: 'astro:jsx',
serverEntrypoint: '@astrojs/mdx/server.js',

View File

@@ -1,6 +1,6 @@
import { fileURLToPath } from 'node:url';
import { preact, type PreactPluginOptions as VitePreactPluginOptions } from '@preact/preset-vite';
import type { AstroIntegration, AstroRenderer, ContainerRenderer, ViteUserConfig } from 'astro';
import type { AstroIntegration, AstroRenderer, ViteUserConfig } from 'astro';
const babelCwd = new URL('../', import.meta.url);
@@ -12,12 +12,7 @@ function getRenderer(development: boolean): AstroRenderer {
};
}
export function getContainerRenderer(): ContainerRenderer {
return {
name: '@astrojs/preact',
serverEntrypoint: '@astrojs/preact/server.js',
};
}
export const getContainerRenderer = (): AstroRenderer => getRenderer(false);
export interface Options extends Pick<VitePreactPluginOptions, 'include' | 'exclude'> {
compat?: boolean;

View File

@@ -1,11 +1,10 @@
import react, { type Options as ViteReactPluginOptions } from '@vitejs/plugin-react';
import type { AstroIntegration, ContainerRenderer } from 'astro';
import type { AstroIntegration, AstroRenderer } from 'astro';
import type * as vite from 'vite';
import {
getReactMajorVersion,
isUnsupportedVersion,
isSupportedReactVersion,
type ReactVersionConfig,
type SupportedReactVersion,
versionsConfig,
} from './version.js';
@@ -102,10 +101,10 @@ export default function ({
experimentalDisableStreaming,
}: ReactIntegrationOptions = {}): AstroIntegration {
const majorVersion = getReactMajorVersion();
if (isUnsupportedVersion(majorVersion)) {
if (!isSupportedReactVersion(majorVersion)) {
throw new Error(`Unsupported React version: ${majorVersion}.`);
}
const versionConfig = versionsConfig[majorVersion as SupportedReactVersion];
const versionConfig = versionsConfig[majorVersion];
return {
name: '@astrojs/react',
@@ -139,15 +138,10 @@ export default function ({
};
}
export function getContainerRenderer(): ContainerRenderer {
export function getContainerRenderer(): AstroRenderer {
const majorVersion = getReactMajorVersion();
if (isUnsupportedVersion(majorVersion)) {
if (!isSupportedReactVersion(majorVersion)) {
throw new Error(`Unsupported React version: ${majorVersion}.`);
}
const versionConfig = versionsConfig[majorVersion as SupportedReactVersion];
return {
name: '@astrojs/react',
serverEntrypoint: versionConfig.server,
};
return getRenderer(versionsConfig[majorVersion]);
}

View File

@@ -1,6 +1,6 @@
import { version as ReactVersion } from 'react-dom';
export type SupportedReactVersion = keyof typeof versionsConfig;
type SupportedReactVersion = keyof typeof versionsConfig;
export type ReactVersionConfig = (typeof versionsConfig)[SupportedReactVersion];
export function getReactMajorVersion(): number {
@@ -11,8 +11,10 @@ export function getReactMajorVersion(): number {
return Number(matches[0]);
}
export function isUnsupportedVersion(majorVersion: number) {
return majorVersion < 17 || majorVersion > 19 || Number.isNaN(majorVersion);
export function isSupportedReactVersion(
majorVersion: number,
): majorVersion is SupportedReactVersion {
return majorVersion in versionsConfig;
}
export const versionsConfig = {

View File

@@ -1,9 +1,4 @@
import type {
AstroIntegration,
AstroIntegrationLogger,
AstroRenderer,
ContainerRenderer,
} from 'astro';
import type { AstroIntegration, AstroIntegrationLogger, AstroRenderer } from 'astro';
import type { PluginOption, UserConfig } from 'vite';
import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid';
@@ -72,12 +67,7 @@ function getRenderer(): AstroRenderer {
};
}
export function getContainerRenderer(): ContainerRenderer {
return {
name: '@astrojs/solid',
serverEntrypoint: '@astrojs/solid-js/server.js',
};
}
export { getRenderer as getContainerRenderer };
export interface Options extends Pick<ViteSolidPluginOptions, 'include' | 'exclude'> {
devtools?: boolean;

View File

@@ -1,6 +1,6 @@
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 } from 'astro';
function getRenderer(): AstroRenderer {
return {
@@ -10,12 +10,7 @@ function getRenderer(): AstroRenderer {
};
}
export function getContainerRenderer(): ContainerRenderer {
return {
name: '@astrojs/svelte',
serverEntrypoint: '@astrojs/svelte/server.js',
};
}
export { getRenderer as getContainerRenderer };
export default function svelteIntegration(options?: Options): AstroIntegration {
return {

View File

@@ -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, HookParameters } from 'astro';
import type { Plugin, UserConfig } from 'vite';
import type { VitePluginVueDevToolsOptions } from 'vite-plugin-vue-devtools';
@@ -32,12 +32,7 @@ function getJsxRenderer(): AstroRenderer {
};
}
export function getContainerRenderer(): ContainerRenderer {
return {
name: '@astrojs/vue',
serverEntrypoint: '@astrojs/vue/server.js',
};
}
export { getRenderer as getContainerRenderer };
function virtualAppEntrypoint(options?: Options): Plugin {
let isBuild: boolean;