Astro 多框架集成实战:一个项目同时使用 React、Preact、Solid、Svelte 与 Vue
【免费下载链接】astroThe web framework for content-driven websites. ⭐️ Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/as/astro
本篇基于 Astro 官方示例 examples/framework-multiple("Kitchen Sink: Microfrontends with Astro")展开,演示如何在一个 Astro 项目中同时接入五种前端框架的组件。读完后你将掌握:如何通过 integrations 配置让多框架共存、include/exclude过滤器如何避免 Vite 插件之间的文件处理冲突,以及各框架组件在 Astro 页面中导入与客户端加载的完整写法。
一、示例定位:Astro 的多框架原生支持
该示例的核心主张只有一句话:Astro 内置了对多个前端框架的支持,可以在同一个项目中同时使用 React、Preact、Svelte 和 Vue(v3.x),甚至还能加上 Solid。README 中的关键说明是:
No configuration is needed to enable these frameworks—just start writing components in
src/components.
也就是说,框架集成能力来自 Astro 生态的官方集成包(@astrojs/react、@astrojs/preact等),只需在astro.config.mjs中注册即可,不需要额外脚手架或构建工具改造。
用一条命令创建项目
官方提供了framework-multiple模板,可以直接创建此示例项目:
npm create astro@latest -- --template framework-multiple项目目录结构如下(摘自本仓库 examples/framework-multiple 实际文件):
examples/framework-multiple/ ├── astro.config.mjs # 注册五个框架集成 ├── package.json # 依赖:五个框架 + 五个官方集成包 ├── tsconfig.json # 继承 astro/tsconfigs/strict └── src/ ├── components/ │ ├── preact/PreactCounter.tsx │ ├── react/ReactCounter.tsx │ ├── solid/SolidCounter.tsx │ ├── svelte/SvelteCounter.svelte │ └── vue/VueCounter.vue ├── pages/index.astro # 同页混用五种框架组件 └── styles/global.css每个框架组件都是一个结构相同的计数器:一个-/+按钮、一个<pre>显示计数,外加一个接收插槽内容的消息区。五个组件在同一个首页上并排渲染,直观验证"多框架共存"的可行性。
二、核心配置:integrations 与 include 过滤器
多框架项目最关键的配置文件是 examples/framework-multiple/astro.config.mjs:
// @ts-check import preact from '@astrojs/preact'; import react from '@astrojs/react'; import solid from '@astrojs/solid-js'; import svelte from '@astrojs/svelte'; import vue from '@astrojs/vue'; import { defineConfig } from 'astro/config'; // https://astro.build/config export default defineConfig({ // Enable many frameworks to support all different kinds of components. integrations: [ preact({ include: ['**/preact/*'] }), solid({ include: ['**/solid/*'] }), react({ include: ['**/react/*'] }), svelte(), vue(), ], });这里有几个值得注意的要点:
- 每个框架对应一个官方集成包,通过
integrations数组注册。从 examples/framework-multiple/package.json 可以看到当前示例使用的版本组合:@astrojs/preact@^6.0.5、@astrojs/react@^6.0.5、@astrojs/solid-js@^7.0.2、@astrojs/svelte@^9.0.1、@astrojs/vue@^7.0.2,同时安装了框架本体(preact、react/react-dom、solid-js、svelte、vue),Node 要求为>=22.12.0。 - 用
include把各 JSX 类框架的文件隔离到独立目录。示例中react({ include: ['**/react/*'] })、preact({ include: ['**/preact/*'] })、solid({ include: ['**/solid/*'] })各管各的目录。这一设计的原因在于:React、Preact、Solid 三者都使用.tsx扩展名且 JSX 语义相近(如onClick),若不限制文件范围,Vite 插件可能把 Preact 文件交给 React 编译器处理,导致运行时错误。 - Svelte 和 Vue 不需要 include。Svelte 组件是独立的
.svelte文件、Vue 是.vue文件,扩展名天然不冲突,因此直接svelte()、vue()即可。
从源码结构看,include参数确实会透传给底层的 Vite 框架插件:在 packages/integrations/react/src/index.ts 中,集成接收include/exclude选项后分别传给 Vite 的 React 插件(编译范围控制)与 Astro 的客户端岛处理链路;该文件还会自动将.astro文件加入exclude(注释说明在 Vite 8 中@vitejs/plugin-react需要显式排除.astro文件),保证 Astro 模板本身不会被 React 编译器误处理。
三、页面层:一个页面同时渲染五个框架的组件
examples/framework-multiple/src/pages/index.astro 展示了五种框架组件在同一个 Astro 页面中的完整用法:
--- // Style Imports import '../styles/global.css'; import { PreactCounter } from '../components/preact/PreactCounter'; // Component Imports // For JSX components, all the common ways of exporting (under a namespace, // specific export, default export etc) are supported! import * as react from '../components/react/ReactCounter'; import SolidCounter from '../components/solid/SolidCounter'; import SvelteCounter from '../components/svelte/SvelteCounter.svelte'; import VueCounter from '../components/vue/VueCounter.vue'; --- <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <link rel="icon" href="/favicon.ico" /> </head> <body> <main> <react.Counter client:visible> <h1>Hello from React!</h1> </react.Counter> <PreactCounter client:visible> <h1>Hello from Preact!</h1> </PreactCounter> <SolidCounter client:visible> <h1>Hello from Solid!</h1> </SolidCounter> <VueCounter client:visible> <h1>Hello from Vue!</h1> </VueCounter> <SvelteCounter client:visible> <h1>Hello from Svelte!</h1> </SvelteCounter> </main> </body> </html>其中体现的两类要点:
- JSX 组件的导入方式非常灵活。源码注释明确写道:"For JSX components, all the common ways of exporting (under a namespace, specific export, default export etc) are supported!"。示例中 React 组件用了命名空间导入(
import * as react,页面上写作<react.Counter>),Preact/Solid 用常规命名/默认导入,Svelte/Vue 直接按扩展名导入。 client:visible客户端指令。五个计数器都需要交互,统一使用client:visible:当组件滚动进入视口时才加载对应的框架运行时并水合,比无条件加载更省首屏成本。各框架的运行时(React、Preact 等)会被打包成独立的客户端岛,只有在需要时才下载执行。
页面样式由 examples/framework-multiple/src/styles/global.css 提供,.counter用 CSS Grid 三列布局排列-、计数、+。
四、五个框架组件的实现对照
每个组件都是一个"计数器 + 插槽",实现方式恰好覆盖各自框架的惯用语法,适合作为跨框架速查对照。
React:显式指定 JSX 来源
examples/framework-multiple/src/components/react/ReactCounter.tsx 第一行是/** @jsxImportSource react */——在多框架项目中这一行至关重要:TypeScript 需要知道该.tsx文件的 JSX 应编译为React.createElement而非其他框架的运行时。
/** @jsxImportSource react */ import { type ReactNode, useState } from 'react'; export function Counter({ children }: { children?: ReactNode }) { const [count, setCount] = useState(0); const add = () => setCount((i) => i + 1); const subtract = () => setCount((i) => i - 1); return ( <> <div className="counter"> <button onClick={subtract}>-</button> <pre>{count}</pre> <button onClick={add}>+</button> </div> <div className="counter-message">{children}</div> </> ); }Preact 的写法几乎一致(PreactCounter.tsx),只是@jsxImportSource preact、hooks 从preact/hooks导入;Solid(SolidCounter.tsx)则换成@jsxImportSource solid-js和createSignal响应式原语。
Svelte 5:runes 语法
SvelteCounter.svelte 使用 Svelte 5 的 runes:$props()接收插槽(类型Snippet),$state(0)声明响应式计数,模板中{@render children?.()}渲染插槽。
Vue 3:setup() + 一个已知的类型提示噪音
VueCounter.vue 使用组合式 API 的 Options 风格setup(),ref(0)声明计数。该文件里还保留了一条很有价值的注释:如果 Vue 模板中的class出现类型错误,原因是@types/react的 JSX 定义是全局声明、会泄漏到项目所有文件,在 React 与 Vue 共用 TypeScript 的项目中目前没有完全规避的办法。这提示在混合项目中若遇到此类编辑器误报,属于已知现象而非配置错误。
五、TypeScript 配置:让 Vue 模板获得智能提示
examples/framework-multiple/tsconfig.json 只有一处特殊配置:
{ "extends": "astro/tsconfigs/strict", "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"], "compilerOptions": { // Needed for TypeScript intellisense in the template inside Vue files "jsx": "preserve" } }继承 Astro 官方的strict预设,jsx: "preserve"则是为了让 Vue 单文件组件的<template>部分(内含 JSX 风格的模板语法)获得 TypeScript 智能提示。
六、运行验证:官方 e2e 测试如何覆盖多框架场景
Astro 仓库自带一套 Playwright e2e 测试来验证多框架场景,即 packages/astro/e2e/multiple-frameworks.test.ts,它对每个框架的计数器做了一致的断言:
- 页面加载后对应
#react-counter、#preact-counter、#solid-counter、#vue-counter、#svelte-counter均可见且初始计数为0; - 点击
.increment按钮后计数变为1,证明各框架组件的客户端事件绑定真正生效; - 还包含一组HMR 用例:分别修改各框架组件源码(如 React 的
useState(0)改为useState(5)、Vue 的ref(0)改为ref(5)、Svelte 的let count = 0改为let count = 5),断言开发服务器热更新后计数器初始值变化——说明多框架集成下各框架的热替换能力同样可用。
该测试基于独立的 fixture(packages/astro/e2e/fixtures/multiple-frameworks/)运行,验证的是 Astro 核心与集成层的组合行为,与本文示例目录互为印证。
小结
把这篇示例的要点浓缩成可复用的实践清单:
- 注册集成:在
astro.config.mjs的integrations中加入需要的@astrojs/*集成包,无需其他配置; - 目录隔离:JSX 类框架(React/Preact/Solid)建议通过
{ include: ['**/框架名/*'] }限定处理范围,.svelte/.vue组件可免配置; - 显式 JSX 来源:每个
.tsx组件文件首行用@jsxImportSource注释指明所属框架; - 按需水合:交互组件配合
client:visible等指令,只在需要时加载对应框架运行时; - TS 兼容:使用
astro/tsconfigs/strict预设,并视 Vue 提示需求开启jsx: "preserve"。
这套机制使"微前端"式的多技术栈共存成为可能——团队可以按组件维度选择最合适的框架,而整个站点仍由 Astro 的构建、路由与渲染管线统一托管。
【免费下载链接】astroThe web framework for content-driven websites. ⭐️ Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/as/astro
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考