内容
# 太阳
一个为人工智能生成代码而构建的运行时UI框架。
当人工智能代理使用React或Vue构建UI时,它会进行猜测。它会猜测属性名称、类型和有效值。当它猜错时,会得到一个堆栈跟踪。堆栈跟踪不是机器可读的反馈。
太阳给代理提供了一条清晰的路径。调用`registry.manifest()`,你会得到一个JSON模式,包含所有已注册的组件,包括它接受的属性和有效值。以错误的属性安装组件时,你会得到一个`ContractError`,一个具有`expected`、`received`和`fix`字段的结构化对象。代理读取`fix`并重试。不需要人类介入。
## 核心原则
- **明确的契约优于约定:** 属性在组件边界处被类型化和验证,而不是被推断
- **组件注册表:** 模型在生成任何组合代码之前读取机器可读的清单
- **结构化错误:** 验证失败返回可解析的JSON,代理可以直接操作
- **声明的副作用:** 副作用声明它们依赖于什么和影响什么;没有隐含的订阅
- **类型化组合:** 插槽属性强制执行哪些组件可以填充它们,具有运行时验证
- **基于运行时:** 不需要编译器;可以直接在浏览器中调试
- **小表面积:** 更少的原始类型意味着更少的生成错误的方式
## 工作原理
### 定义组件
每个组件都明确声明其形状。注册它,以便其他组件和模型可以发现它。
```javascript
import { createElement, defineComponent, registry } from './framework/index.js'
const Button = defineComponent({
name: 'Button',
props: {
label: { type: 'string', required: true },
onClick: { type: 'function', required: true },
variant: { type: 'string', enum: ['primary', 'secondary'], default: 'primary' },
},
render({ label, onClick, variant }) {
return createElement('button', { class: variant, onclick: onClick }, label)
}
})
registry.register(Button)
```
### 结构化错误
传递错误的类型时,你会得到一个结构化错误,而不是字符串。代理可以解析并自我纠正,而无需正则表达式。
```javascript
Button({ label: 42, onClick: () => {} })
// throws ContractError:
{
"error": "ContractError",
"component": "Button",
"prop": "label",
"expected": "string",
"received": "number",
"fix": "Pass a string value for \"label\""
}
```
### 组件注册表
在生成组合代码之前,模型读取完整的目录:
```javascript
registry.manifest()
// →
[
{
"name": "Button",
"props": {
"label": { "type": "string", "required": true },
"onClick": { "type": "function", "required": true },
"variant": { "type": "string", "enum": ["primary", "secondary"], "default": "primary" }
}
},
...
]
```
### 类型化插槽(组件组合)
父组件声明哪个组件类型可以填充插槽。传递其他内容会抛出`ContractError`。
```javascript
const Card = defineComponent({
name: 'Card',
props: {
title: { type: 'string', required: true },
action: { type: 'slot', accepts: 'Button', required: true },
},
render({ title, action }) {
return createElement('div', { class: 'card' },
createElement('h3', {}, title),
action,
)
}
})
// valid
Card({ title: 'Hello', action: Button({ label: 'Go', onClick: () => {} }) })
// throws: Card: prop "action": expected slot(Button), got vnode with no _source
Card({ title: 'Hello', action: createElement('button', {}, 'Go') })
```
### 紧凑的h()表示法
`h()`将密集的数组格式解析为虚拟节点树。它是注册表感知的,因此组件名称会自动解析。
```javascript
import { h } from './framework/index.js'
// plain DOM nodes
h(['div', { class: 'row' },
['p', {}, 'Hello'],
['button', { class: 'btn' }, 'Click'],
])
// registered component by name, dispatches to Button()
h(['Button', { label: 'Save', onClick: handleSave, variant: 'primary' }])
```
### 钩子和副作用
状态是`useState`。副作用使用三个明确的原始类型,而不是通用的`useEffect`:
- **`useResource:`** 异步数据获取,在键更改时自动AbortController取消
- **`useSubscription:`** 事件监听器,在源/事件/处理程序更改时附加和分离
- **`onMount` / `onUnmount:`** 生命周期回调,仅运行一次,而不是每次渲染
```javascript
const UserCard = defineComponent({
name: 'UserCard',
props: { userId: { type: 'number', required: true } },
render({ userId }) {
const [width, setWidth] = useState(window.innerWidth)
// cancels the previous fetch automatically when userId changes
const { data, loading, error } = useResource({
key: userId,
fetch: async (signal) => {
const res = await fetch(`/api/user/${userId}`, { signal })
return res.json()
},
})
// attaches once, re-attaches only if source/event/handler changes
useSubscription({ source: window, event: 'resize', handler: () => setWidth(window.innerWidth) })
onMount(() => analytics.track('UserCard mounted'))
onUnmount(() => analytics.track('UserCard unmounted'))
if (loading) return createElement('p', {}, 'Loading...')
return createElement('p', {}, `${data.name} - viewport: ${width}px`)
}
})
```
## 架构
```
framework/
├── core/
│ ├── createElement.js # vnode factory
│ ├── render.js # mount vnode tree to DOM
│ ├── diff.js # reconcile old and new vnode trees
│ ├── hooks.js # useState, useMemo, useResource, useSubscription, onMount, onUnmount
│ └── scheduler.js # batch and defer re-renders
├── contract/
│ ├── defineComponent.js # strict component definition with prop schema
│ ├── ContractError.js # structured error class with toJSON()
│ ├── validate.js # runtime prop validation
│ └── types.js # primitive type definitions + slot type
├── runtime/
│ ├── reconciler.js # component lifecycle and mount/unmount
│ └── events.js # delegated event handling
├── registry.js # component catalog and manifest
├── h.js # compact array notation parser
└── index.js # public API
```
组件位于`components/`,每个文件一个,默认导出是`defineComponent`调用,导入时自动注册。模型可以遵循的规则,无需推断。
## 现场演示
[在StackBlitz中打开](https://stackblitz.com/github/Stahlwalker/framework-solar/tree/main/stackblitz) — 在浏览器中运行一个3步代理循环:通过`registry.manifest()`发现组件,在错误的安装时捕获`ContractError`,使用`fix`字段自我纠正。
## 入门指南
```bash
npm create solarbuild@latest my-app
cd my-app
npm run dev
```
**光标插件:** [cursor.directory/plugins/framework-solar](https://cursor.directory/plugins/framework-solar) — 将太阳规则添加到光标中,以便您的AI助手可以直接了解API。
或者直接使用CDN。无需安装,无需构建步骤:
```html
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
<script type="module">
import {
defineComponent, mountComponent, registry,
useState, createElement
} from 'https://cdn.jsdelivr.net/npm/solarbuild/framework/index.js'
const Counter = defineComponent({
name: 'Counter',
props: {},
render() {
const [count, setCount] = useState(0)
return createElement('button', { onclick: () => setCount(n => n + 1) }, `Clicked ${count} times`)
}
})
registry.register(Counter)
mountComponent(Counter, {}, document.getElementById('app'))
</script>
</body>
</html>
```
## 运行演示
```bash
npm run dev
```
打开`http://localhost:3456/demo/`(需要尾部斜杠;这是静态服务器的怪癖)。
演示涵盖了框架的所有功能:静态渲染、差异、钩子、契约验证、声明的副作用、批量更新、注册表清单、紧凑的h()表示法和类型化的插槽。
## MCP服务器
`solarbuild-mcp`是一个MCP服务器,公开您的太阳能组件注册表作为可调用工具。 AI代理可以发现组件、验证属性并在运行时自我纠正,而无需阅读静态文档。
```bash
npm install solarbuild-mcp
```
```json
{
"mcpServers": {
"solarbuild": {
"command": "npx",
"args": ["solarbuild-mcp", "--components", "./components"]
}
}
}
```
**工具:** `manifest`(完整的注册表模式)、`component`(单个组件模式)、`validate`(属性验证,带有修复指令)。
→ [MCP服务器文档](https://docs.solarbuild.dev/docs/integrations/mcp) · [npm](https://www.npmjs.com/package/solarbuild-mcp)
## 文档
[docs.solarbuild.dev](https://docs.solarbuild.dev)上的完整文档
- [安装](https://docs.solarbuild.dev/docs/installation)
- [用例](https://docs.solarbuild.dev/docs/use-cases)
- [API参考](https://docs.solarbuild.dev/docs/api/define-component)
## 这不是什么
- 不是元框架。没有SSR,没有路由,没有构建管道。
- 不是React的替代品。范围更窄,约束不同。
- 不是为人类手动编写组件而优化的,但也适用于这种情况。
论文:下一代框架将不会为开发者设计。它们将为开发者用来编写代码的模型而设计。这是早期尝试。