Skip to content

Commit 9bd4d4c

Browse files
committed
feat: add rippplejs
1 parent 9a28cb1 commit 9bd4d4c

1 file changed

Lines changed: 364 additions & 0 deletions

File tree

src/content/posts/ripplejs.md

Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
---
2+
title: Ripple.js - 优雅的 TypeScript UI 框架
3+
published: 2026-01-09
4+
description: 深入解析 Ripple.js 的设计原理、核心特性,以及与 React、Svelte、Solid 的对比分析
5+
tags: [TypeScript, UI Framework, Frontend, Reactive]
6+
category: Frontend
7+
draft: false
8+
---
9+
10+
## 简介
11+
12+
[Ripple](https://www.ripplejs.com/) 是一个优雅的、编译器驱动的 TypeScript UI 框架,由 Dominic Gannaway ([@trueadm](https://github.com/trueadm)) 创建。Dominic 是前端领域的资深专家,曾参与 Inferno、React Hooks、Lexical 以及 Svelte 5 的开发。
13+
14+
Ripple 结合了 React、Solid 和 Svelte 的优点,提供了一种基于 JSX 超集的全新开发体验。它使用独特的 `.ripple` 文件扩展名,原生支持 TypeScript,并引入了创新的响应式语法。
15+
16+
> **注意**: Ripple 目前仍处于早期开发阶段,尚未准备好用于生产环境。
17+
18+
## 核心特性
19+
20+
### 1. 响应式状态管理
21+
22+
Ripple 使用 `track()` 函数创建响应式变量,通过 `@` 符号访问和修改值:
23+
24+
```tsx
25+
import { track } from 'ripple';
26+
27+
export component Counter() {
28+
let count = track(0);
29+
let double = track(() => @count * 2); // 派生响应式值
30+
31+
<div>
32+
<p>{"Count: "}{@count}</p>
33+
<p>{"Double: "}{@double}</p>
34+
<button onClick={() => @count++}>{"Increment"}</button>
35+
</div>
36+
}
37+
```
38+
39+
这种设计的优势在于:
40+
- 显式的响应式追踪,避免意外的重渲染
41+
- `@` 语法清晰地标识响应式值的读写
42+
- 支持派生状态,自动追踪依赖
43+
44+
### 2. 组件定义语法
45+
46+
不同于 React 的函数返回 JSX,Ripple 使用 `component` 关键字定义组件,模板直接作为语句书写:
47+
48+
```tsx
49+
component Button(props: { text: string, onClick: () => void }) {
50+
<button onClick={props.onClick}>
51+
{props.text}
52+
</button>
53+
}
54+
55+
export component App() {
56+
<Button text="Click me" onClick={() => console.log("Clicked!")} />
57+
}
58+
```
59+
60+
**重要**: Ripple 中所有文本内容必须包裹在表达式 `{}` 中:
61+
62+
```tsx
63+
// 错误写法
64+
<div>Hello World</div>
65+
66+
// 正确写法
67+
<div>{"Hello World"}</div>
68+
```
69+
70+
### 3. 原生控制流
71+
72+
Ripple 支持在模板中直接使用 JavaScript 原生控制流语句:
73+
74+
```tsx
75+
component TodoList({ todos }) {
76+
<ul>
77+
for (const todo of todos; index i; key todo.id) {
78+
<li>{todo.text}{" at index "}{i}</li>
79+
}
80+
</ul>
81+
82+
if (todos.length === 0) {
83+
<p>{"No todos yet!"}</p>
84+
} else {
85+
<p>{"Total: "}{todos.length}</p>
86+
}
87+
}
88+
```
89+
90+
还支持 `switch` 语句和 `try-catch` 错误边界:
91+
92+
```tsx
93+
component StatusIndicator({ status }) {
94+
switch (status) {
95+
case 'loading':
96+
<p>{'Loading...'}</p>
97+
break;
98+
case 'success':
99+
<p>{'Success!'}</p>
100+
break;
101+
case 'error':
102+
<p>{'Error!'}</p>
103+
break;
104+
default:
105+
<p>{'Unknown status'}</p>
106+
}
107+
}
108+
```
109+
110+
### 4. 响应式集合
111+
112+
Ripple 提供了完整的响应式集合类型:
113+
114+
```tsx
115+
// 响应式数组
116+
const items = #[1, 2, 3];
117+
//
118+
const items = new TrackedArray(1, 2, 3);
119+
120+
// 响应式对象
121+
const obj = #{a: 1, b: 2};
122+
//
123+
const obj = new TrackedObject({a: 1, b: 2});
124+
125+
// 响应式 Map
126+
const map = new TrackedMap([[1, 'a'], [2, 'b']]);
127+
128+
// 响应式 Set
129+
const set = new TrackedSet([1, 2, 3]);
130+
```
131+
132+
### 5. 作用域样式
133+
134+
组件支持内置的作用域 CSS:
135+
136+
```tsx
137+
component StyledCard() {
138+
<div class="card">
139+
<h1>{"Styled Content"}</h1>
140+
</div>
141+
142+
<style>
143+
.card {
144+
background: #f0f0f0;
145+
padding: 1rem;
146+
border-radius: 8px;
147+
}
148+
h1 {
149+
color: #333;
150+
}
151+
</style>
152+
}
153+
```
154+
155+
## 工作原理
156+
157+
### 编译器驱动
158+
159+
Ripple 是一个编译器驱动的框架。`.ripple` 文件在构建时被编译成优化的 JavaScript 代码。这种方式带来了几个优势:
160+
161+
1. **细粒度更新**: 不使用虚拟 DOM,而是在编译时分析依赖关系,生成精确的 DOM 更新代码
162+
2. **更小的运行时**: 许多工作在编译时完成,运行时代码更精简
163+
3. **类型安全**: 编译器可以进行完整的 TypeScript 类型检查
164+
165+
### 响应式系统
166+
167+
Ripple 的响应式系统基于 `Tracked<V>` 对象:
168+
169+
```tsx
170+
// track() 创建一个 Tracked<V> 对象
171+
let count = track(0);
172+
173+
// @count 读取值(建立依赖追踪)
174+
console.log(@count); // 0
175+
176+
// @count++ 修改值(触发更新)
177+
@count++;
178+
```
179+
180+
这种设计确保了:
181+
- 只有实际被读取的值才会建立依赖关系
182+
- 更新是细粒度的,只影响真正依赖该值的 DOM 节点
183+
- 可以使用 `untrack()` 显式跳过依赖追踪
184+
185+
### 模板作为词法作用域
186+
187+
Ripple 的独特之处在于模板本身就是词法作用域,可以在其中声明变量和执行语句:
188+
189+
```tsx
190+
component TemplateScope() {
191+
<div>
192+
// 在模板内声明变量
193+
const message = "Hello";
194+
let count = 42;
195+
196+
console.log("This runs during render");
197+
198+
<h1>{message}</h1>
199+
<p>{"Count: "}{count}</p>
200+
201+
// 嵌套作用域
202+
<section>
203+
const sectionData = "Nested scope";
204+
<p>{sectionData}</p>
205+
</section>
206+
</div>
207+
}
208+
```
209+
210+
## 与其他框架对比
211+
212+
### vs React
213+
214+
| 特性 | Ripple | React |
215+
|------|--------|-------|
216+
| 响应式 | 内置 `track()` + `@` 语法 | useState/useEffect |
217+
| DOM 更新 | 细粒度直接更新 | 虚拟 DOM diff |
218+
| 样式 | 内置作用域 CSS | 需要 CSS-in-JS 库 |
219+
| 组件定义 | `component` 关键字 | 函数返回 JSX |
220+
| 控制流 | 原生 if/for/switch | JSX 表达式 / map() |
221+
| TypeScript | 原生支持 | 需要配置 |
222+
223+
**Ripple 优势**:
224+
- 无需学习 Hooks 规则
225+
- 更直观的响应式语法
226+
- 更好的性能(无虚拟 DOM 开销)
227+
- 更小的包体积
228+
229+
**React 优势**:
230+
- 成熟的生态系统
231+
- 大量社区资源和第三方库
232+
- SSR/SSG 完善支持
233+
- 稳定的生产就绪状态
234+
235+
### vs Svelte
236+
237+
| 特性 | Ripple | Svelte |
238+
|------|--------|--------|
239+
| 语法风格 | TypeScript/JSX 优先 | HTML 模板优先 |
240+
| 响应式语法 | `track()` + `@` | `$:` 和 runes |
241+
| 控制流 | 原生 JS 语句 | 特殊指令 `{#if}` `{#each}` |
242+
| 类型系统 | TypeScript 原生 | 需要额外配置 |
243+
244+
**Ripple 优势**:
245+
- TypeScript 优先设计
246+
- 使用原生 JS 控制流而非特殊语法
247+
- JSX 风格对 React 开发者更友好
248+
249+
**Svelte 优势**:
250+
- 更成熟稳定
251+
- 完善的 SSR (SvelteKit)
252+
- 更大的社区和生态
253+
254+
### vs Solid
255+
256+
| 特性 | Ripple | Solid |
257+
|------|--------|-------|
258+
| 组件定义 | `component` 关键字 | 普通函数 |
259+
| 响应式访问 | `@` 语法 | 函数调用 `count()` |
260+
| 集合 | 内置 TrackedArray/TrackedObject | 需要 createStore |
261+
| 模板 | 组件体内语句 | JSX 返回值 |
262+
263+
**Ripple 优势**:
264+
- 更简洁的响应式访问语法
265+
- 内置响应式集合类型
266+
- 模板词法作用域特性
267+
268+
**Solid 优势**:
269+
- 生产就绪
270+
- 标准 JSX 兼容性
271+
- 更成熟的生态
272+
273+
## 快速开始
274+
275+
### 安装
276+
277+
```bash
278+
# 从模板创建新项目
279+
npx degit Ripple-TS/ripple/templates/basic my-app
280+
cd my-app
281+
npm i && npm run dev
282+
283+
# 或在现有项目中安装
284+
npm install ripple
285+
npm install --save-dev @ripple-ts/vite-plugin
286+
```
287+
288+
### 基础示例
289+
290+
```tsx
291+
import { track } from 'ripple';
292+
293+
export component App() {
294+
let count = track(0);
295+
296+
<div class="container">
297+
<h1>{"Welcome to Ripple!"}</h1>
298+
<p>{"Count: "}{@count}</p>
299+
<button onClick={() => @count++}>{"Increment"}</button>
300+
</div>
301+
302+
<style>
303+
.container {
304+
text-align: center;
305+
padding: 2rem;
306+
}
307+
button {
308+
padding: 0.5rem 1rem;
309+
cursor: pointer;
310+
}
311+
</style>
312+
}
313+
```
314+
315+
### 挂载应用
316+
317+
```typescript
318+
import { mount } from 'ripple';
319+
import App from './App.ripple';
320+
321+
mount(App, {
322+
target: document.getElementById('root')
323+
});
324+
```
325+
326+
## 开发工具支持
327+
328+
Ripple 提供了完整的开发工具链:
329+
330+
- **VSCode 扩展**: 语法高亮、诊断、IntelliSense
331+
- **Prettier 插件**: 代码格式化支持
332+
- **ESLint 插件**: 代码检查支持
333+
- **Vite 插件**: 开发和构建支持
334+
335+
## 当前限制
336+
337+
作为早期开发阶段的框架,Ripple 目前存在一些限制:
338+
339+
1. **无 SSR 支持**: 目前仅支持 SPA 模式
340+
2. **生态系统不完善**: 第三方库和工具较少
341+
3. **可能存在 Bug**: 框架仍在快速迭代中
342+
4. **文档不完整**: 部分高级特性文档待完善
343+
344+
## 总结
345+
346+
Ripple 是一个充满创新的前端框架,它汇集了 Dominic Gannaway 多年前端框架开发经验的精华。其独特的响应式语法、编译器驱动的架构以及 TypeScript 优先的设计理念,为前端开发提供了一种新的可能性。
347+
348+
**适合尝试 Ripple 的场景**:
349+
- 对新技术感兴趣的个人项目
350+
- 想要学习现代响应式框架设计原理
351+
- 不需要 SSR 的小型应用
352+
353+
**暂不建议使用的场景**:
354+
- 生产环境的商业项目
355+
- 需要完善 SSR 支持的应用
356+
- 依赖大量第三方库的项目
357+
358+
随着框架的不断成熟,Ripple 有望成为前端开发的一个有力选择。如果你对现代前端框架的设计感兴趣,Ripple 绝对值得关注和尝试。
359+
360+
## 参考链接
361+
362+
- [Ripple 官网](https://www.ripplejs.com/)
363+
- [GitHub 仓库](https://github.com/Ripple-TS/ripple)
364+
- [官方文档](https://www.ripplejs.com/docs/introduction)

0 commit comments

Comments
 (0)