@typeset/vite-plugin-static-component-react
把 React 静态组件提前渲染为 HTML,并内联到调用方的 renderWrapper。组件内的计算发生在 Vite 模块转换阶段,浏览器运行外层 React wrapper。
本包是仓库内的私有 workspace 包。应用需声明对本包的 workspace:* 依赖,并具备 React、React DOM、Vite 和 @vitejs/plugin-react 环境;依赖约束见 package.json。
接入 Vite
在已有 React 应用的 vite.config.ts 中注册静态组件插件,并保留 React 编译插件:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import staticComponentReact from "@typeset/vite-plugin-static-component-react";
export default defineConfig({
plugins: [staticComponentReact(), react()],
});
staticComponentReact() 当前不接收配置参数。
定义静态组件
创建 Greeting.html.tsx:
import { staticComponent } from "@typeset/vite-plugin-static-component-react/runtime";
type GreetingProps = {
name: string;
children: string;
};
export default staticComponent(function Greeting(props: GreetingProps) {
return (
<p>
Hello {props.name}: {props.children}
</p>
);
});
.html.tsx 用于提示文件用途,插件实际通过 staticComponent() 标记识别组件。组件文件和调用方都应使用 .tsx。
在应用中使用
在同一目录的 App.tsx 中导入并提供 wrapper:
import Greeting from "./Greeting.html.tsx";
export default function App() {
return (
<Greeting
name="Typeset"
children="Welcome"
renderWrapper={(html) => <section dangerouslySetInnerHTML={{ __html: html }} />}
/>
);
}
插件将上述调用替换成等价的 wrapper JSX:
<section dangerouslySetInnerHTML={{ __html: "<p>Hello Typeset: Welcome</p>" }} />
原静态组件 import 被移除。静态内容没有 hydration,也不保留内部 React 事件处理器;需要交互时,将状态和事件放在外层普通 React 组件或 wrapper 中。
API 与渲染行为
- 包入口默认导出
staticComponentReact(),用于 Vite 配置。 /runtime导出staticComponent()和StaticComponent<Props>类型。staticComponent()为原组件增加要求传入renderWrapper的调用类型,运行时仍返回原函数。- 适配器直接调用并 await 组件函数;字符串结果作为 HTML 使用,其他结果交给
react-dom/server的renderToStaticMarkup。
可以标记具名导出,也可以传入异步函数。异步操作会影响模块转换所需的时间。直接返回的字符串被视为 HTML,需由生成端负责转义。
由于顶层静态函数在 React 渲染器外直接调用,不要在该函数中依赖 useState、useContext 等需要 React 渲染上下文的 hooks。
使用限制
- 每条 import 只导入一个静态组件,并直接从定义组件的模块导入。组件绑定只能作为 JSX 标签使用。
- props 使用字面量,不支持把调用方变量作为静态输入;spread 的求值规则尚未完善。
- children 使用文本或字面量,可以像示例一样显式传入
children。嵌套 JSX 不受支持。 - wrapper 必须是内联箭头函数,直接返回 JSX,不能使用块状函数体。
- 开发模式下,静态依赖修改通过整页刷新更新内容。
完整输入范围、资源行为和实现说明见核心包 README。
样式、图片和排查入口
组件可以导入 CSS Module,并把类名写入静态 JSX。图片使用 import photoUrl from "./photo.png?url",插件会保留资源依赖并尝试把 HTML 中的开发 URL 改写为 Vite 管理的构建 URL。
包含 CSS Module、PNG、共享 SVG 和具名组件的完整用例见 React 构建 fixture。
若浏览器出现 staticComponent() was evaluated in the browser 警告,说明标记函数进入了客户端执行。检查插件是否注册、文件是否为 .tsx、标记是否来自本包 /runtime,以及导出方式是否在支持范围内。标记函数自身不会执行 wrapper,不能作为插件缺失时的完整降级方案。
验证
在仓库根目录执行:
pnpm --filter @typeset/vite-plugin-static-component-react test
pnpm --filter @typeset/vite-plugin-static-component-react exec tsc --noEmit
pnpm --filter @typeset/vite-plugin-static-component-integration-test test
pnpm --filter @typeset/vite-plugin-static-component-integration-test test:types
本包单元测试检查适配配置及生成的模块源码;集成测试验证真实构建产物。