mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
feat(container): provide a virtual module to load renderers (#11144)
* feat(container): provide a virtual module to load renderers * address feedback * chore: restore some default to allow to have PHP prototype working * Thread through renderers and manifest * Pass manifest too * update changeset * add diff * Apply suggestions from code review Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> * fix diff * rebase and update lock --------- Co-authored-by: Matthew Phillips <matthew@skypack.dev> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
587e75f47e
commit
803dd8061d
16 changed files with 233 additions and 59 deletions
30
.changeset/fair-singers-reflect.md
Normal file
30
.changeset/fair-singers-reflect.md
Normal file
|
@ -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()])
|
||||||
|
const container = await AstroContainer.create({
|
||||||
|
renderers,
|
||||||
|
});
|
||||||
|
const result = await container.renderToString(ReactWrapper);
|
||||||
|
|
||||||
|
expect(result).toContain('Counter');
|
||||||
|
expect(result).toContain('Count: <!-- -->5');
|
||||||
|
});
|
||||||
|
```
|
36
.changeset/gold-mayflies-beam.md
Normal file
36
.changeset/gold-mayflies-beam.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
"astro": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
**BREAKING CHANGE to the experimental Container API only**
|
||||||
|
|
||||||
|
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()`:
|
||||||
|
|
||||||
|
```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 = [
|
||||||
|
- {
|
||||||
|
- 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');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The new `loadRenderers()` helper function is available from `astro:container`, a virtual module that can be used when running the Astro container inside `vite`.
|
|
@ -12,8 +12,8 @@
|
||||||
"test": "vitest run"
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"astro": "^4.9.3",
|
"astro": "experimental--container",
|
||||||
"@astrojs/react": "^3.4.0",
|
"@astrojs/react": "experimental--container",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"vitest": "^1.6.0"
|
"vitest": "^1.6.0"
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
|
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
|
||||||
import { expect, test } from 'vitest';
|
import { expect, test } from 'vitest';
|
||||||
import ReactWrapper from '../src/components/ReactWrapper.astro';
|
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 () => {
|
test('ReactWrapper with react renderer', async () => {
|
||||||
const container = await AstroContainer.create({
|
|
||||||
renderers: [
|
|
||||||
{
|
|
||||||
name: '@astrojs/react',
|
|
||||||
clientEntrypoint: '@astrojs/react/client.js',
|
|
||||||
serverEntrypoint: '@astrojs/react/server.js',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
const result = await container.renderToString(ReactWrapper);
|
const result = await container.renderToString(ReactWrapper);
|
||||||
|
|
||||||
expect(result).toContain('Counter');
|
expect(result).toContain('Counter');
|
||||||
|
|
4
packages/astro/client.d.ts
vendored
4
packages/astro/client.d.ts
vendored
|
@ -152,6 +152,10 @@ declare module 'astro:i18n' {
|
||||||
export * from 'astro/virtual-modules/i18n.js';
|
export * from 'astro/virtual-modules/i18n.js';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module 'astro:container' {
|
||||||
|
export * from 'astro/virtual-modules/container.js';
|
||||||
|
}
|
||||||
|
|
||||||
declare module 'astro:middleware' {
|
declare module 'astro:middleware' {
|
||||||
export * from 'astro/virtual-modules/middleware.js';
|
export * from 'astro/virtual-modules/middleware.js';
|
||||||
}
|
}
|
||||||
|
|
|
@ -3290,3 +3290,19 @@ declare global {
|
||||||
'astro:page-load': Event;
|
'astro:page-load': Event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Container types
|
||||||
|
export type ContainerImportRendererFn = (
|
||||||
|
containerRenderer: ContainerRenderer
|
||||||
|
) => Promise<SSRLoadedRenderer>;
|
||||||
|
|
||||||
|
export type ContainerRenderer = {
|
||||||
|
/**
|
||||||
|
* The name of the renderer.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* The entrypoint that is used to render a component on the server
|
||||||
|
*/
|
||||||
|
serverEntrypoint: string;
|
||||||
|
};
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { posix } from 'node:path';
|
import { posix } from 'node:path';
|
||||||
import type {
|
import type {
|
||||||
|
AstroConfig,
|
||||||
AstroRenderer,
|
AstroRenderer,
|
||||||
AstroUserConfig,
|
AstroUserConfig,
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
|
ContainerImportRendererFn,
|
||||||
|
ContainerRenderer,
|
||||||
MiddlewareHandler,
|
MiddlewareHandler,
|
||||||
Props,
|
Props,
|
||||||
RouteData,
|
RouteData,
|
||||||
|
@ -83,8 +86,8 @@ export type ContainerRenderOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function createManifest(
|
function createManifest(
|
||||||
renderers: SSRLoadedRenderer[],
|
|
||||||
manifest?: AstroContainerManifest,
|
manifest?: AstroContainerManifest,
|
||||||
|
renderers?: SSRLoadedRenderer[],
|
||||||
middleware?: MiddlewareHandler
|
middleware?: MiddlewareHandler
|
||||||
): SSRManifest {
|
): SSRManifest {
|
||||||
const defaultMiddleware: MiddlewareHandler = (_, next) => {
|
const defaultMiddleware: MiddlewareHandler = (_, next) => {
|
||||||
|
@ -102,7 +105,7 @@ function createManifest(
|
||||||
routes: manifest?.routes ?? [],
|
routes: manifest?.routes ?? [],
|
||||||
adapterName: '',
|
adapterName: '',
|
||||||
clientDirectives: manifest?.clientDirectives ?? new Map(),
|
clientDirectives: manifest?.clientDirectives ?? new Map(),
|
||||||
renderers: manifest?.renderers ?? renderers,
|
renderers: renderers ?? manifest?.renderers ?? [],
|
||||||
base: manifest?.base ?? ASTRO_CONFIG_DEFAULTS.base,
|
base: manifest?.base ?? ASTRO_CONFIG_DEFAULTS.base,
|
||||||
componentMetadata: manifest?.componentMetadata ?? new Map(),
|
componentMetadata: manifest?.componentMetadata ?? new Map(),
|
||||||
inlinedScripts: manifest?.inlinedScripts ?? new Map(),
|
inlinedScripts: manifest?.inlinedScripts ?? new Map(),
|
||||||
|
@ -138,21 +141,9 @@ export type AstroContainerOptions = {
|
||||||
* @default []
|
* @default []
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* List or renderers to use when rendering components. Usually they are entry points
|
* List or renderers to use when rendering components. Usually, you want to pass these in an SSR context.
|
||||||
*
|
|
||||||
* ## Example
|
|
||||||
*
|
|
||||||
* ```js
|
|
||||||
* const container = await AstroContainer.create({
|
|
||||||
* renderers: [{
|
|
||||||
* name: "@astrojs/react"
|
|
||||||
* client: "@astrojs/react/client.js"
|
|
||||||
* server: "@astrojs/react/server.js"
|
|
||||||
* }]
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
renderers?: AstroRenderer[];
|
renderers?: SSRLoadedRenderer[];
|
||||||
/**
|
/**
|
||||||
* @default {}
|
* @default {}
|
||||||
* @description
|
* @description
|
||||||
|
@ -170,6 +161,17 @@ export type AstroContainerOptions = {
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
astroConfig?: AstroContainerUserConfig;
|
astroConfig?: AstroContainerUserConfig;
|
||||||
|
|
||||||
|
// TODO: document out of experimental
|
||||||
|
resolve?: SSRResult['resolve'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @default {}
|
||||||
|
* @description
|
||||||
|
*
|
||||||
|
* The raw manifest from the build output.
|
||||||
|
*/
|
||||||
|
manifest?: SSRManifest;
|
||||||
};
|
};
|
||||||
|
|
||||||
type AstroContainerManifest = Pick<
|
type AstroContainerManifest = Pick<
|
||||||
|
@ -195,6 +197,7 @@ type AstroContainerConstructor = {
|
||||||
renderers?: SSRLoadedRenderer[];
|
renderers?: SSRLoadedRenderer[];
|
||||||
manifest?: AstroContainerManifest;
|
manifest?: AstroContainerManifest;
|
||||||
resolve?: SSRResult['resolve'];
|
resolve?: SSRResult['resolve'];
|
||||||
|
astroConfig: AstroConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class experimental_AstroContainer {
|
export class experimental_AstroContainer {
|
||||||
|
@ -206,24 +209,31 @@ export class experimental_AstroContainer {
|
||||||
*/
|
*/
|
||||||
#withManifest = false;
|
#withManifest = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal function responsible for importing a renderer
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#getRenderer: ContainerImportRendererFn | undefined;
|
||||||
|
|
||||||
private constructor({
|
private constructor({
|
||||||
streaming = false,
|
streaming = false,
|
||||||
renderers = [],
|
|
||||||
manifest,
|
manifest,
|
||||||
|
renderers,
|
||||||
resolve,
|
resolve,
|
||||||
|
astroConfig,
|
||||||
}: AstroContainerConstructor) {
|
}: AstroContainerConstructor) {
|
||||||
this.#pipeline = ContainerPipeline.create({
|
this.#pipeline = ContainerPipeline.create({
|
||||||
logger: new Logger({
|
logger: new Logger({
|
||||||
level: 'info',
|
level: 'info',
|
||||||
dest: nodeLogDestination,
|
dest: nodeLogDestination,
|
||||||
}),
|
}),
|
||||||
manifest: createManifest(renderers, manifest),
|
manifest: createManifest(manifest, renderers),
|
||||||
streaming,
|
streaming,
|
||||||
serverLike: true,
|
serverLike: true,
|
||||||
renderers,
|
renderers: renderers ?? manifest?.renderers ?? [],
|
||||||
resolve: async (specifier: string) => {
|
resolve: async (specifier: string) => {
|
||||||
if (this.#withManifest) {
|
if (this.#withManifest) {
|
||||||
return this.#containerResolve(specifier);
|
return this.#containerResolve(specifier, astroConfig);
|
||||||
} else if (resolve) {
|
} else if (resolve) {
|
||||||
return resolve(specifier);
|
return resolve(specifier);
|
||||||
}
|
}
|
||||||
|
@ -232,10 +242,10 @@ export class experimental_AstroContainer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async #containerResolve(specifier: string): Promise<string> {
|
async #containerResolve(specifier: string, astroConfig: AstroConfig): Promise<string> {
|
||||||
const found = this.#pipeline.manifest.entryModules[specifier];
|
const found = this.#pipeline.manifest.entryModules[specifier];
|
||||||
if (found) {
|
if (found) {
|
||||||
return new URL(found, ASTRO_CONFIG_DEFAULTS.build.client).toString();
|
return new URL(found, astroConfig.build.client).toString();
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
@ -248,22 +258,9 @@ export class experimental_AstroContainer {
|
||||||
public static async create(
|
public static async create(
|
||||||
containerOptions: AstroContainerOptions = {}
|
containerOptions: AstroContainerOptions = {}
|
||||||
): Promise<experimental_AstroContainer> {
|
): Promise<experimental_AstroContainer> {
|
||||||
const { streaming = false, renderers = [] } = containerOptions;
|
const { streaming = false, manifest, renderers = [], resolve } = containerOptions;
|
||||||
const loadedRenderers = await Promise.all(
|
const astroConfig = await validateConfig(ASTRO_CONFIG_DEFAULTS, process.cwd(), 'container');
|
||||||
renderers.map(async (renderer) => {
|
return new experimental_AstroContainer({ streaming, manifest, renderers, astroConfig, resolve });
|
||||||
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 });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it.
|
// NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it.
|
||||||
|
@ -271,9 +268,10 @@ export class experimental_AstroContainer {
|
||||||
private static async createFromManifest(
|
private static async createFromManifest(
|
||||||
manifest: SSRManifest
|
manifest: SSRManifest
|
||||||
): Promise<experimental_AstroContainer> {
|
): Promise<experimental_AstroContainer> {
|
||||||
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({
|
const container = new experimental_AstroContainer({
|
||||||
manifest,
|
manifest,
|
||||||
|
astroConfig,
|
||||||
});
|
});
|
||||||
container.#withManifest = true;
|
container.#withManifest = true;
|
||||||
return container;
|
return container;
|
||||||
|
|
32
packages/astro/src/virtual-modules/container.ts
Normal file
32
packages/astro/src/virtual-modules/container.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
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));
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import type { AstroIntegration } from 'astro';
|
import type { AstroIntegration, ContainerRenderer } from 'astro';
|
||||||
|
|
||||||
function getViteConfiguration() {
|
function getViteConfiguration() {
|
||||||
return {
|
return {
|
||||||
|
@ -19,6 +19,13 @@ function getViteConfiguration() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getContainerRenderer(): ContainerRenderer {
|
||||||
|
return {
|
||||||
|
name: '@astrojs/lit',
|
||||||
|
serverEntrypoint: '@astrojs/lit/server.js',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default function (): AstroIntegration {
|
export default function (): AstroIntegration {
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/lit',
|
name: '@astrojs/lit',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { markdownConfigDefaults } from '@astrojs/markdown-remark';
|
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 astroJSXRenderer from 'astro/jsx/renderer.js';
|
||||||
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
import type { Options as RemarkRehypeOptions } from 'remark-rehype';
|
||||||
import type { PluggableList } from 'unified';
|
import type { PluggableList } from 'unified';
|
||||||
|
@ -28,6 +28,13 @@ type SetupHookParams = HookParameters<'astro:config:setup'> & {
|
||||||
addContentEntryType: (contentEntryType: ContentEntryType) => void;
|
addContentEntryType: (contentEntryType: ContentEntryType) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function getContainerRenderer(): ContainerRenderer {
|
||||||
|
return {
|
||||||
|
name: 'astro:jsx',
|
||||||
|
serverEntrypoint: 'astro/jsx/server.js',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroIntegration {
|
export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroIntegration {
|
||||||
// @ts-expect-error Temporarily assign an empty object here, which will be re-assigned by the
|
// @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.
|
// `astro:config:done` hook later. This is so that `vitePluginMdx` can get hold of a reference earlier.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { type PreactPluginOptions as VitePreactPluginOptions, preact } from '@preact/preset-vite';
|
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);
|
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<VitePreactPluginOptions, 'include' | 'exclude'> {
|
export interface Options extends Pick<VitePreactPluginOptions, 'include' | 'exclude'> {
|
||||||
compat?: boolean;
|
compat?: boolean;
|
||||||
devtools?: boolean;
|
devtools?: boolean;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import react, { type Options as ViteReactPluginOptions } from '@vitejs/plugin-react';
|
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 { version as ReactVersion } from 'react-dom';
|
||||||
import type * as vite from 'vite';
|
import type * as vite from 'vite';
|
||||||
|
|
||||||
|
@ -53,6 +53,19 @@ function getRenderer(reactConfig: ReactVersionConfig) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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: versionConfig.server,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function optionsPlugin(experimentalReactChildren: boolean): vite.Plugin {
|
function optionsPlugin(experimentalReactChildren: boolean): vite.Plugin {
|
||||||
const virtualModule = 'astro:react:opts';
|
const virtualModule = 'astro:react:opts';
|
||||||
const virtualModuleId = '\0' + virtualModule;
|
const virtualModuleId = '\0' + virtualModule;
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import type { AstroIntegration, AstroIntegrationLogger, AstroRenderer } from 'astro';
|
import type {
|
||||||
|
AstroIntegration,
|
||||||
|
AstroIntegrationLogger,
|
||||||
|
AstroRenderer,
|
||||||
|
ContainerRenderer,
|
||||||
|
} from 'astro';
|
||||||
import type { PluginOption, UserConfig } from 'vite';
|
import type { PluginOption, UserConfig } from 'vite';
|
||||||
import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid';
|
import solid, { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid';
|
||||||
|
|
||||||
|
@ -94,6 +99,13 @@ function getRenderer(): AstroRenderer {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getContainerRenderer(): ContainerRenderer {
|
||||||
|
return {
|
||||||
|
name: '@astrojs/solid',
|
||||||
|
serverEntrypoint: '@astrojs/solid-js/server.js',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface Options extends Pick<ViteSolidPluginOptions, 'include' | 'exclude'> {
|
export interface Options extends Pick<ViteSolidPluginOptions, 'include' | 'exclude'> {
|
||||||
devtools?: boolean;
|
devtools?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import type { Options } from '@sveltejs/vite-plugin-svelte';
|
import type { Options } from '@sveltejs/vite-plugin-svelte';
|
||||||
import { svelte, vitePreprocess } 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 { VERSION } from 'svelte/compiler';
|
||||||
import type { UserConfig } from 'vite';
|
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) {
|
async function svelteConfigHasPreprocess(root: URL) {
|
||||||
const svelteConfigFiles = ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'];
|
const svelteConfigFiles = ['./svelte.config.js', './svelte.config.cjs', './svelte.config.mjs'];
|
||||||
for (const file of svelteConfigFiles) {
|
for (const file of svelteConfigFiles) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Options as VueOptions } from '@vitejs/plugin-vue';
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from '@vitejs/plugin-vue';
|
||||||
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx';
|
import type { Options as VueJsxOptions } from '@vitejs/plugin-vue-jsx';
|
||||||
import { MagicString } from '@vue/compiler-sfc';
|
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 { Plugin, UserConfig } from 'vite';
|
||||||
import type { VitePluginVueDevToolsOptions } from 'vite-plugin-vue-devtools';
|
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 {
|
function virtualAppEntrypoint(options?: Options): Plugin {
|
||||||
let isBuild: boolean;
|
let isBuild: boolean;
|
||||||
let root: string;
|
let root: string;
|
||||||
|
|
|
@ -155,10 +155,10 @@ importers:
|
||||||
examples/container-with-vitest:
|
examples/container-with-vitest:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@astrojs/react':
|
'@astrojs/react':
|
||||||
specifier: ^3.4.0
|
specifier: experimental--container
|
||||||
version: link:../../packages/integrations/react
|
version: link:../../packages/integrations/react
|
||||||
astro:
|
astro:
|
||||||
specifier: ^4.9.3
|
specifier: experimental--container
|
||||||
version: link:../../packages/astro
|
version: link:../../packages/astro
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
|
|
Loading…
Reference in a new issue