콘텐츠로 이동

Experimental Astro Vite plugin

이 콘텐츠는 아직 번역되지 않았습니다.

@astrojs/vite-plugin-astro lets you use Astro components in any Vite project, without an Astro project around them. Your own server decides what to render: a Hono route, an Express handler, or a worker’s fetch() that renders a component and returns the HTML.

Components work as they do in Astro: scoped styles, <script> tags, and islands of React, Preact, Solid, Svelte, or Vue components that hydrate in the browser.

Install the plugin and the runtime:

Terminal window
npm install @astrojs/vite-plugin-astro @astrojs/runtime

Then add the plugin to your Vite config:

vite.config.js
import astro from '@astrojs/vite-plugin-astro';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [astro()],
});

You can now import .astro files from your server code.

Import a component in your server code, and render it with renderToResponse() or renderToString() from @astrojs/runtime.

The following example uses a Hono route to render a Page.astro component, with a name prop taken from the URL:

src/app.ts
import { renderToResponse } from '@astrojs/runtime';
import { Hono } from 'hono';
import Page from './components/Page.astro';
const app = new Hono();
app.get('/hello/:name', (c) =>
renderToResponse(Page, { props: { name: c.req.param('name') } }),
);
export default app;

Page.astro receives the name prop and can use component props as in any Astro project:

src/components/Page.astro
---
const { name } = Astro.props;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello, {name}</title>
</head>
<body>
<h1>Hello, {name}!</h1>
</body>
</html>
<style>
h1 { color: rebeccapurple; }
</style>

By default, the result is a full HTML document: <!DOCTYPE html> is added, and the stylesheets of the component and its children are added to the <head>. To render part of a page, such as a fragment for htmx or a component inside a page your server renders some other way, pass partial: true.

The following example renders a Card.astro component as an HTML fragment:

src/app.ts
import { renderToString } from '@astrojs/runtime';
import Card from './components/Card.astro';
const html = await renderToString(Card, { props: { title: 'Hello' }, partial: true });

Rendering happens on the server only: call these functions from server code that Vite loads, not from code that runs in the browser.

To render components from a UI framework, pass its renderer to astro() and add the framework’s own Vite plugin.

The following example installs the React renderer, the React Vite plugin, and React:

Terminal window
npm install @astrojs/react-renderer @vitejs/plugin-react react react-dom

Then, add the renderer and the Vite plugin to your Vite configuration file:

vite.config.js
import react from '@astrojs/react-renderer';
import astro from '@astrojs/vite-plugin-astro';
import viteReact from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [astro({ renderers: [react()] }), viteReact()],
});

The renderer tells Astro how to render and hydrate the framework’s components. The framework’s Vite plugin compiles its files, as it would in any Vite project.

You can now use the framework components with any client directive. The following example adds a React Counter to an Astro component, and hydrates it as soon as the page loads:

src/components/Page.astro
---
import Counter from './Counter.tsx';
const { name } = Astro.props;
---
<body>
<h1>Hello, {name}!</h1>
<Counter client:load />
</body>

The rendered HTML includes everything needed to hydrate the island: you don’t need to add any scripts yourself.

The following table lists the renderer and the Vite plugin to use for each framework:

Framework Renderer Vite plugin
React react() from @astrojs/react-renderer @vitejs/plugin-react
Preact preact() from @astrojs/preact-renderer @preact/preset-vite
Solid solid() from @astrojs/solid-js-renderer vite-plugin-solid, with ssr: true
Svelte svelte() from @astrojs/svelte-renderer @sveltejs/vite-plugin-svelte
Vue vue() from @astrojs/vue-renderer @vitejs/plugin-vue

The order of the plugins doesn’t matter.

To use several JSX frameworks together, tell each one which files are its own with an include option. Pass it to each framework’s Vite plugin, and also to the react() and preact() renderers. solid() takes no options. The following example uses React and Solid components from separate folders:

vite.config.js
import react from '@astrojs/react-renderer';
import solid from '@astrojs/solid-js-renderer';
import astro from '@astrojs/vite-plugin-astro';
import viteReact from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import viteSolid from 'vite-plugin-solid';
export default defineConfig({
plugins: [
astro({ renderers: [react({ include: ['**/react/*'] }), solid()] }),
viteReact({ include: ['**/react/*'] }),
viteSolid({ include: ['**/solid/*'], ssr: true }),
],
});
See how to use framework components in Astro components. In a Vite project, skip the installing integrations step.

Run your server with vite dev, the same way as in any Vite project, for example with @hono/vite-dev-server or your platform’s Vite plugin. Components are compiled when they are requested, and the dev server serves the client code of your islands.

Editing a component updates the page in the browser: style changes are applied without a reload, and other changes reload the page.

To build your project, tell Vite where your server code starts with the build input of the ssr environment. You can also choose the output directory of each build.

The following example sets src/app.ts as the entrypoint of the server build, and writes the server and client builds to separate folders:

vite.config.js
import astro from '@astrojs/vite-plugin-astro';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [astro()],
environments: {
ssr: {
build: {
outDir: 'dist/server',
rolldownOptions: { input: { app: 'src/app.ts' } },
},
},
client: { build: { outDir: 'dist/client' } },
},
});

Running vite build then writes your server code to dist/server/, and the browser code of your components to dist/client/. The client build contains the stylesheets, the islands, the framework’s client code, and the components’ <script> tags. The rendered HTML links to these files.

Serve dist/client/ as static files, as you would for any Vite project with a server. Hosting platforms that deploy a Vite project’s client output as static assets do this for you.

In a component rendered by renderToResponse() or renderToString(), the Astro global has the properties that only depend on the component and the render call:

Property Value
Astro.props The props passed to the render function, or by the parent component.
Astro.slots The component’s slots.
Astro.self The component itself, for recursive components.
Astro.request The request passed to the render function. Defaults to a GET request for http://localhost/.
Astro.url The URL of Astro.request.
Astro.site The site option of astro(), as a URL.
Astro.generator The Astro version.

To make request data available to a component, pass the request, or pass the data as props:

app.get('/profile', async (c) => {
const user = await getUser(c);
return renderToResponse(Profile, { request: c.req.raw, props: { user } });
});

The following Astro features are not available in components rendered with @astrojs/vite-plugin-astro:

  • Pages and routing: src/pages/, getStaticPaths(), and prerendering. Your server decides which component to render for each request.
  • Request-level APIs: Astro.cookies, Astro.params, Astro.redirect(), Astro.locals, actions, sessions, and internationalization helpers.
  • Server islands (server:defer).
  • View transitions (<ClientRouter />).
  • Astro’s built-in modules, such as astro:assets, astro:content, and astro:env.
  • Content Security Policy, inlining of scripts and stylesheets, and build.assetsPrefix.
  • Integrations. Use Vite plugins instead.

Stylesheets are always linked in production, and scoped styles use the attribute strategy.

To import .astro files from TypeScript, declare their type:

src/env.d.ts
declare module '*.astro' {
import type { AstroComponentFactory } from '@astrojs/runtime/types';
const Component: AstroComponentFactory;
export default Component;
}

The astro() plugin accepts an optional configuration object whose properties are all also optional.

astro({
site: 'https://example.com',
renderers: [react()],
});

Type: string

The URL your site is deployed to, available as Astro.site.

Type: AstroRenderer[]
Default: []

The renderers of the UI frameworks your components use. When a component could be handled by more than one renderer, they are tried in this order.

Type: { name: string; entrypoint: string | URL }[]
Default: []

Custom client directives, in the same shape as the integration API’s addClientDirective().

Type: boolean | 'jsx'
Default: 'jsx'

How whitespace in component templates is compressed. See compressHTML.

Type: 'always' | 'never' | 'ignore'
Default: 'ignore'

See trailingSlash.

Type: string
Default: './public'

The directory of files served as-is, relative to root. A <script src> that points to a file in this directory must use is:inline.

Type: string
Default: Vite’s root

The project root, relative to Vite’s root.

The base URL is Vite’s base: astro() has no base option.

Type: (Component: AstroComponentFactory, options?: RenderOptions) => Promise<Response>

Renders a component to a Response with a Content-Type: text/html header.

Type: (Component: AstroComponentFactory, options?: RenderOptions) => Promise<string>

Renders a component to an HTML string.

renderToResponse() and renderToString() accept an optional object with the following properties.

Type: Record<string, any>
Default: {}

The component’s props, available as Astro.props.

Type: Record<string, string>
Default: {}

HTML for each slot, by slot name. Use default for the default slot.

Type: Request
Default: a GET request for http://localhost/

Available as Astro.request and Astro.url.

Type: boolean
Default: false

When false, renders a full document: <!DOCTYPE html> is added, and the stylesheets of the component tree are added to the <head>. When true, renders the component’s HTML only.

기여하기 커뮤니티 후원하기