tsrx-org/tsrx · 上手攻略
- 仓库:tsrx-org/tsrx
- 链接:https://github.com/tsrx-org/tsrx
- 分类:前端工程 · 语言扩展 · 编译工具链
- 作者:Tom
- 更新:2026-08-28
是什么
TSRX(TypeScript Render Extensions)是一个 TypeScript 语言扩展,用于构建声明式 UI。它将 TypeScript 设置逻辑、JSX 形态的结构、模板控制流和作用域样式统一写在 .tsrx 文件中,再编译为所选运行时的惯用输出。
核心设计哲学:同一种语言,多种运行时。TSRX 先将源码解析为框架无关的 AST,再由目标编译器(如 @tsrx/react、@tsrx/solid)生成对应框架的代码——React、Preact、Solid、Vue、Ripple、Octane 六种目标,当前均已支持。语法上借鉴 JSX 但有自己独特的语法糖(@{ ... } 语句容器、&{ ... } 惰性解构、@if/@for/@switch/@try 模板控制流),由 @tsrx/typescript-plugin 提供编辑器级的类型检查与导航。
作者是 Dominic Gannaway(React 团队早期成员、React 18 concurrent mode 关键贡献者),MIT 许可证,当前处于活跃 beta 开发阶段。
解决什么问题
1. JSX 表达力受限
JSX 把控制流挤压到表达式槽位,三元嵌套、map 链、render helper 满天飞。TSRX 把控制流做成模板级一等语法(@if/@for/@switch/@try),写在模板里而不是 JavaScript 表达式里。
2. 样式与结构分离
传统方案:CSS 文件或 CSS-in-JS 与组件分离。TSRX 支持在同一个 .tsrx 文件里写 <style> 块,编译时自动做 class hashing(类似 CSS Modules),作用域封闭而不污染全局。
3. 组件局部状态与渲染结果割裂
React Hooks 要求把状态逻辑抽到函数顶层,逻辑与渲染目标物理分离。TSRX 的 @{ ... } 语句容器把"局部变量/派生值/副作用"和"最终输出节点"放在同一个词法作用域,代码共置更紧凑。
4. 多框架重复造轮子
每个框架都有自己的 JSX 方言、组件写法、样式方案。TSRX 用同一套语言写出组件,换目标框架只需要换编译插件,不需要重写组件代码。
5. AI 辅助编码友好
文档明确指出 TSRX 面向"AI 辅助编程时代"——代码结构显式(控制流非嵌套表达式)、共置(逻辑紧邻渲染目标)、无隐式 scope,LLM 更容易理解和生成。
快速安装(React + Vite)
# 1. 安装核心包和 Vite 插件
pnpm install @tsrx/react @tsrx/vite-plugin-react
# 2. 在 vite.config.ts 中注册插件
# import { defineConfig } from 'vite';
# import tsrxReact from '@tsrx/vite-plugin-react';
# export default defineConfig({ plugins: [tsrxReact()] });
# 3. 创建 .tsrx 文件,从 TSX 中正常 import
# import { Counter } from './Counter.tsrx';
# 即可使用
支持的目标 + 构建工具组合(截至 2026-08,基于官方文档):
| 目标 | 构建工具 | 安装命令摘要 |
|---|---|---|
| React | Vite | @tsrx/react + @tsrx/vite-plugin-react |
| React | Rspack | @tsrx/react + @tsrx/rspack-plugin-react |
| React | Turbopack(Next.js) | @tsrx/react + @tsrx/turbopack-plugin-react |
| React | Bun | @tsrx/react + @tsrx/bun-plugin-react |
| Preact | Vite / Rspack / Bun | @tsrx/preact + 对应插件 |
| Solid | Vite | @tsrx/solid + @tsrx/vite-plugin-solid |
| Vue | Vite | @tsrx/vue + @tsrx/vite-plugin-vue(依赖 vue-jsx-vapor) |
⚠️ 注意:npm registry 上 @tsrx/core 最新版本 0.1.60(第三方来源,可能非官方);@tsrx/typescript-plugin 版本 0.3.124;具体版本号建议以 npm view @tsrx/react versions 实际查询为准,下方不再逐一标注。
核心用法
语句容器 @{ ... }
export function Cart({ items }: { items: Item[] }) @{
const subtotal = items.reduce((sum, item) => sum + item.price, 0);
const discount = subtotal > 100 ? 0.1 : 0;
<div>
<h2>Your cart</h2>
<p>Subtotal: ${subtotal}</p>
<p>Save: ${(subtotal * discount).toFixed(2)}</p>
</div>
}
@{ 前面是 TypeScript 设置逻辑,} 后必须跟一个输出节点。设置逻辑与渲染结果共置,阅读时数据流方向清晰。
惰性解构 &{ ... }
// 普通解构在 Solid/Vue 等响应式运行时下会破坏响应性
// &{ ... } 编译时生成惰性 getter,运行时按需读取
function UserCard(&{ name, age }: { name: string; age: number }) {
return <div>
<h2>{name}</h2>
<p>Age: {age}</p>
</div>;
}
&{ ... } 对象解构和 &[ ... ] 数组解构编译到目标框架时,在 Solid/Vue/Ripple 下保留响应性追踪;在 React/Preact 下退化为直接属性访问,零开销。
模板控制流
// @if / @else if / @else
function StatusBadge({ status }: { status: 'active' | 'idle' | 'offline' }) @{
@if (status === 'active') {
<span class="badge active">Online</span>
} @else if (status === 'idle') {
<span class="badge idle">Away</span>
} @else {
<span class="badge">Offline</span>
}
}
// @for (... of ...) with index and key
function TodoList({ items }: { items: Todo[] }) @{
<ul>
@for (const item of items; index i; key item.id) {
<li>{i + 1}. {item.text}</li>
} @empty {
<li>No todos yet</li>
}
</ul>
}
// @switch
function StatusMessage({ status }: { status: string }) @{
@switch (status) {
@case 'loading': { <p>Loading...</p> }
@case 'success': { <p class="success">Done!</p> }
@default: { <p>Unknown status.</p> }
}
}
// @try / @catch(错误边界)
function ErrorBoundaryWrapper() @{
@try {
<RiskyComponent />
} @catch (error) {
<FallbackUI error={error} />
}
}
⚠️ 注意:@if、@for、@switch、@try 的分支 body 是模板级控制流,不是普通 JavaScript {} 块。普通函数体的 {} 内写 JSX 会触发编译错误——必须显式用 @{ ... } 包裹。
作用域样式 <style>
export function Button({ label, onClick }: {
label: string;
onClick: () => void;
}) @{
<>
<button class="btn" {onClick}>{label}</button>
<style>
.btn {
padding: 0.5rem 1rem;
border-radius: 4px;
}
</style>
</>
}
<style> 块编译时自动 hash 类名,作用域封闭,不污染全局 CSS。编译产物为标准 CSS(或 CSS Modules,取决于构建工具配置)。
Prop 简写 {name} 代替 name={name}
// 两者等价:
<Input value={value} onChange={onChange} />
<Input {value} {onChange} />
当 prop 名与变量名一致时可用简写,包括事件处理器。
典型适用场景
-
AI 辅助前端开发项目:TSRX 代码结构显式、逻辑与渲染共置,LLM 生成的可读性和可维护性高于手写复杂 JSX。文档明确以此为卖点。
-
多框架组件库:同一套组件源码需要同时支持 React、Preact、Solid、Vue 等多个目标,避免维护多套代码。⚠️ 注意:各目标框架的响应式模型不同(Solid/Vue 基于 Proxy/Signal,React 基于 Virtual DOM),复杂响应式逻辑在跨目标时仍需针对性调整。
-
中型企业内部工具 / 管理后台:样式共置减少文件切换;
@if/@for减少三元和 map 嵌套; scoped style 省去 CSS 架构决策(Tailwind / CSS Modules / Styled-Components)。 -
TypeScript 重度项目:已有 TSX 基础设施,渐进式引入
.tsrx文件,与现有 JS/TS/TSX 文件互操作,无需整体迁移。 -
声明式优先的 SSR 场景:Vue / Solid 目标支持服务端渲染,对需要首屏性能的页面有优势。
坑与注意
-
beta 状态,API 可能 breaking change:官方标注"active beta development",生产项目引入需锁定版本号并关注 changelog。建议不要在核心业务线上直接依赖最新版,建议至少隔一个 minor 版本滞后升级。
-
@{ ... }语法与普通{ }易混淆:在.tsrx文件里,普通{}是 JavaScript 表达式(不允许写 JSX);只有@{ ... }才能写 JSX。VS Code 插件和 TypeScript 插件会提示,但初期容易踩坑。 -
Solid/Vue 等响应式目标的行为边界:惰性解构
&{ ... }在 Solid/Vue 下保留响应性,但如果你在组件内直接做对象属性读写而不通过解构,响应性仍需手动处理。文档对这一边界说明较充分,建议先读目标框架的 TSRX 专有文档。 -
<style>块仅限组件级别:TSRX 的<style>块是组件级别的 scoped CSS,不支持跨组件共享样式(如 CSS custom properties 方案可以,但<style>块本身不会生成全局规则)。 -
@for循环体不是普通 JavaScript scope:@for (... of ...) { ... }循环体是模板渲染块,不允许continue/break/return等跳转语句。嵌套函数内可以用普通 JavaScript 控制流,但不能替代@for的渲染语义。 -
编译产物是 TSX/JS,而非运行时依赖:TSRX 是编译时工具,最终产物是目标框架的 TSX/JS 文件,运行时仍需要对应框架(React / Preact / Solid / Vue)。它不替代 React/Vue 等运行时。
-
@tsrx/typescript-plugin版本跳号(来源:npm search,@tsrx/typescript-pluginv0.3.124 vs@tsrx/corev0.1.60):不同@tsrx/*包可能版本独立演进,安装时不要假设版本对齐,建议逐包npm view @tsrx/<pkg> versions核实。 -
Vue 目标依赖 vue-jsx-vapor:Vue 目标需要额外安装
vue-jsx-vapor,不是原生 Vue SFC(Single File Component)——这意味着 TSRX Vue 组件形态与标准.vue文件不同,是 TSX 风格,对于习惯 Vue SFC 的团队有一定学习成本。
与同类对比
| 特性 | TSRX | Solid JSX | React JSX | Vue SFC |
|---|---|---|---|---|
| 控制流语法 | @if/@for 模板级 |
普通 JS 表达式 | 普通 JS 表达式 | 指令(v-if/v-for) |
| 样式共置 | <style> 块 |
CSS-in-JS / 外置 | CSS-in-JS / 外置 | <style> SFC 内 |
| 多框架目标 | ✅ 6 种 | ❌ 仅 Solid | ❌ 仅 React | ❌ 仅 Vue |
| 语句容器共置 | ✅ @{ ... } |
❌ | ❌ | ❌ |
| 惰性解构 | ✅ &{ ... } |
内联 computed | ❌ | computed() |
| 编辑器插件 | ✅ VS Code/Zed/Neovim | ✅ | ✅ | ✅ |
| 生产可用性 | beta | 稳定 | 稳定 | 稳定 |
| AI 友好度 | 高(显式结构) | 中 | 中 | 低 |
核心差异:TSRX 是唯一把"多框架编译目标 + 模板级控制流 + 语句容器共置 + 作用域样式"打包成一门语言的项目。SolidJS 放弃了 JSX 表达式嵌套但不支持多目标;Vue SFC 样式共置优秀但多框架为零;React JSX 生态最成熟但控制流嵌套问题无语言层解法。
一句话推荐结论
如果你的项目需要同时面向多个 UI 运行时(React / Solid / Vue / Preact),或者你在构建 AI 辅助编码友好的组件库,TSRX 是目前唯一在语言层做跨框架声明式 UI 的方案,值得关注其 beta 进展;如果是单一框架的已有项目,迁移成本需谨慎评估。
最小可跑命令
# 环境:Node.js ≥ 18,pnpm ≥ 8,TypeScript ≥ 5.0
# 硬件:无特殊要求,纯前端编译工具
pnpm create vite my-tsrx-app --template react-ts
cd my-tsrx-app
pnpm install @tsrx/react @tsrx/vite-plugin-react
# vite.config.ts 添加:
# import tsrxReact from '@tsrx/vite-plugin-react';
# export default defineConfig({ plugins: [tsrxReact()] });
# 创建 src/Counter.tsrx:
# export function Counter() @{
# let count = 0;
# <button onClick={() => count++}>Count: {count}</button>
# }
pnpm dev
⚠️ 最小可跑依赖实际安装 @tsrx/react + 对应构建插件版本;具体版本号以 npm view @tsrx/react versions 查询结果为准(web_fetch 无法读取完整 npm 版本列表)。
原始来源
- GitHub 仓库:https://github.com/tsrx-org/tsrx(README.md + 仓库描述)
- 官方文档:https://tsrx.dev/(Getting Started + Features 页面)
- InfoQ 报道:https://www.infoq.com/news/2026/06/tsrx-alternative-jsx(2026-06-19)
- npm:@tsrx/core v0.1.60 / @tsrx/typescript-plugin v0.3.124(npm search 结果,版本号 ⚠️ 待 npm view 核实)