博客 / 詳情

返回

Ripple:一個現代的響應式 UI 框架

用最直觀的語法,構建最高效的 Web 應用

AI 時代,更需要精品框架

2026 年,AI 編程已經成為常態。Cursor、Claude、Copilot……開發者每天都在用 AI 生成大量代碼。

但這帶來了一個新問題:代碼量爆炸,質量卻在下降。

AI 可以快速生成代碼,但它生成的往往是"能跑就行"的代碼——冗餘的狀態管理、不必要的重渲染、臃腫的依賴。當項目規模增長,這些問題會被放大。

AI 時代不缺代碼,缺的是精品框架——能夠約束代碼質量、保證性能、減少出錯的框架。

現有框架的問題

// React: 樣板代碼太多
function Counter() {
  const [count, setCount] = useState(0)
  const increment = useCallback(() => {
    setCount(prev => prev + 1)
  }, [])
  return <button onClick={increment}>{count}</button>
}

// Vue: 需要記住 .value
const count = ref(0)
count.value++  // 忘記 .value 就出錯

// 這些"儀式感"代碼,AI 可能寫對,也可能寫錯
// 更重要的是:它們讓代碼變得臃腫

Ripple 的答案:少即是多

component Counter() {
  let count = track(0);
  <button onClick={() => @count++}>{@count}</button>
}

4 行代碼,零樣板。

  • 沒有 useState / ref / signal
  • 沒有 useCallback / useMemo
  • 沒有 .value / $:
  • 編譯器自動優化,運行時極致精簡
指標 React Vue Ripple
計數器代碼行數 6-8 行 4-5 行 3 行
運行時大小 ~40KB ~30KB ~5KB
更新粒度 組件級 組件級 節點級

為什麼這在 AI 時代更重要?

  1. 代碼審查成本:AI 生成的代碼需要人工審查,越簡潔越好審
  2. 錯誤概率:語法越簡單,AI(和人)出錯的機會越少
  3. 性能兜底:即使 AI 不考慮性能,編譯器會幫你優化
  4. 可維護性:三個月後回看代碼,還能一眼看懂

Ripple 的設計哲學:代碼應該讀起來像它做的事情。


為什麼選擇 Ripple?

Ripple 追求兩全其美——既要 React 的組件模型和 JSX 表達力,又要 Svelte 的編譯時優化和極致性能。

看看這段代碼:

component Counter() {
  let count = track(0);

  <button onClick={() => @count++}>
    {"點擊了 "}{@count}{" 次"}
  </button>
}

這就是 Ripple。沒有 useState,沒有 $:,沒有 .valuetrack() 創建狀態,@ 讀寫值,簡潔直觀。

核心理念

1. 編譯器優先

Ripple 不是一個運行時框架,而是一個編譯器。你寫的代碼會被轉換成高效的 JavaScript:

你寫的代碼                         編譯後的代碼
─────────────                     ─────────────
let count = track(0)    →        var count = _$_.tracked(0)
{@count}                →        _$_.get(count)
@count++                →        _$_.update(count)

這意味着:

  • 零運行時開銷:響應式追蹤在編譯時完成
  • 更小的包體積:沒有虛擬 DOM diff 算法
  • 更快的更新:直接操作需要更新的 DOM 節點

2. 組件即函數

在 Ripple 中,組件就是帶有 component 關鍵字的函數:

component Greeting({ name = "World" }) {
  <h1>{"Hello, "}{name}{"!"}</h1>
}

// 使用
<Greeting name="Ripple" />

3. 響應式狀態:track()@ 語法

track() 創建響應式變量,用 @ 讀寫值:

component Form() {
  let name = track("");
  let email = track("");

  <form>
    <input value={@name} onInput={(e) => @name = e.target.value} />
    <input value={@email} onInput={(e) => @email = e.target.value} />
    <p>{"你好,"}{@name}{"!我們會發郵件到 "}{@email}</p>
  </form>
}

4. 響應式集合:#[]#{}

數組和對象也可以是響應式的:

const items = #[];                          // 響應式數組
const user = #{ name: "Tom" };              // 響應式對象
const tags = new TrackedSet(["a", "b"]);    // 響應式 Set
const cache = new TrackedMap([["k", "v"]]); // 響應式 Map

對這些集合的任何修改都會自動觸發 UI 更新:

items.push("new item");   // UI 自動更新
user.name = "Jerry";      // UI 自動更新

實戰:構建一個 Todo 應用

讓我們用 Ripple 構建一個完整的 Todo 應用,體驗框架的核心特性。

完整代碼

import { track } from 'ripple';

component TodoInput({ onAdd }) {
  let value = track("");

  function handleKeyDown(e) {
    if (e.key === "Enter" && @value.trim()) {
      onAdd(@value.trim());
      @value = "";
    }
  }

  <div class="input-section">
    <input
      type="text"
      placeholder="Add a new todo..."
      value={@value}
      onInput={(e) => @value = e.target.value}
      onKeyDown={handleKeyDown}
    />
    <button onClick={() => { if (@value.trim()) { onAdd(@value.trim()); @value = ""; } }}>{"Add"}</button>
  </div>
}

component TodoItem({ todo, onToggle, onDelete }) {
  <li>
    <input type="checkbox" checked={todo.completed} onChange={onToggle} />
    <span class={todo.completed ? "done" : ""}>{todo.text}</span>
    <button onClick={onDelete}>{"×"}</button>
  </li>
}

export component App() {
  const todos = #[];

  function addTodo(text) {
    todos.push(#{ id: Date.now(), text, completed: false });
  }

  function toggleTodo(todo) {
    todo.completed = !todo.completed;
  }

  function deleteTodo(id) {
    const index = todos.findIndex(t => t.id === id);
    if (index > -1) todos.splice(index, 1);
  }

  const activeCount = () => todos.filter(t => !t.completed).length;

  <div class="app">
    <h1>{"Todo App"}</h1>

    <TodoInput onAdd={addTodo} />

    <ul>
      for (const todo of todos) {
        <TodoItem
          todo={todo}
          onToggle={() => toggleTodo(todo)}
          onDelete={() => deleteTodo(todo.id)}
        />
      }
    </ul>

    <p>{todos.length}{" total, "}{activeCount()}{" remaining"}</p>
  </div>

  <style>
    .app { max-width: 400px; margin: 40px auto; font-family: system-ui; }
    h1 { color: #e91e63; }
    .input-section { display: flex; gap: 8px; margin-bottom: 16px; }
    .input-section input { flex: 1; padding: 8px; }
    ul { list-style: none; padding: 0; }
    li { display: flex; gap: 8px; align-items: center; padding: 8px 0; }
    li span { flex: 1; }
    li span.done { text-decoration: line-through; color: #888; }
    p { color: #666; font-size: 14px; }
  </style>
}

代碼解析

1. 響應式數組 #[]

const todos = #[];

#[] 創建一個響應式數組。當你調用 pushsplicefilter 等方法時,Ripple 會自動追蹤變化並更新 UI。

2. 響應式對象 #{}

todos.push(#{ id: Date.now(), text, completed: false });

每個 todo 項也是響應式對象,這樣 todo.completed = !todo.completed 就能觸發更新。

3. 控制流:內聯 forif

for (const todo of todos) {
  <TodoItem todo={todo} ... />
}

if (todos.some(t => t.completed)) {
  <button>{"清除已完成"}</button>
}

Ripple 的控制流直接寫在 JSX 中,不需要 map 或三元表達式。編譯器會將其轉換為高效的 block 結構。

4. 作用域樣式

<style>
  .todo-item { ... }
</style>

組件內的 <style> 標籤會被自動添加作用域哈希,不會污染全局樣式。


編譯產物一覽

好奇 Ripple 編譯器做了什麼?來看看 @count++ 這行代碼的旅程:

源碼                     編譯階段               運行時
────                     ────────               ──────

let count = track(0)  →  解析為 AST     →    var count = _$_.tracked(0)
                         (TrackedExpression)

@count++              →  分析綁定類型    →    _$_.update(count)
                         (kind: 'tracked')

{@count}              →  轉換為渲染函數  →    _$_.render(() => {
                                               _$_.set_text(anchor, _$_.get(count))
                                             })

三階段編譯流程:

  1. 解析 (Parse):將源碼轉為 AST,識別 @#[]component 等特殊語法
  2. 分析 (Analyze):構建作用域、標記變量類型、裁剪未使用的 CSS
  3. 轉換 (Transform):生成客户端/服務端 JavaScript 代碼

與其他框架對比

特性 Ripple React Vue 3 Svelte
響應式語法 track() + @ useState ref().value $:
虛擬 DOM
編譯時優化 部分
包體積 ~5KB ~40KB ~30KB ~2KB
學習曲線
控制流 內聯語法 map/三元 v-if/v-for {#if}/{#each}
樣板代碼 極少

編譯器:質量的守護者

Ripple 的編譯器不只是"翻譯"代碼,它是代碼質量的守護者:

1. 自動依賴追蹤

// 你只需要寫業務邏輯
const fullName = () => `${@firstName} ${@lastName}`

// 編譯器自動分析依賴,生成優化代碼:
// _$_.render(() => set_text(anchor, `${get(firstName)} ${get(lastName)}`))

不需要 useMemo([dep1, dep2]),編譯器比你更清楚依賴關係。

2. CSS 死代碼消除

component Button() {
  <button class="primary">{"Click"}</button>

  <style>
    .primary { background: blue; }
    .secondary { background: gray; }  /* 編譯器自動移除 */
    .danger { background: red; }      /* 編譯器自動移除 */
  </style>
}

不用擔心 CSS 越寫越多,編譯器只保留真正用到的樣式。

3. 細粒度更新

component Profile() {
  const user = #{ name: "Tom", bio: "Developer" };

  <div>
    <h1>{user.name}</h1>      {/* 只在 name 變化時更新 */}
    <p>{user.bio}</p>         {/* 只在 bio 變化時更新 */}
  </div>
}

編譯器分析每個表達式的依賴,生成最精確的更新邏輯。


讓 AI 更懂 Ripple

Ripple 提供了 llms.txt,這是一份專為 AI 助手設計的框架説明文檔。

當你使用 Claude、ChatGPT 或其他 AI 助手時,可以讓它先閲讀這份文檔:

請先閲讀 https://www.ripplejs.com/llms.txt,然後幫我用 Ripple 框架實現一個 [功能描述]

llms.txt 包含:

  • Ripple 核心語法速查
  • 常見模式和最佳實踐
  • 易錯點和正確寫法
  • 完整示例代碼

這確保 AI 生成的代碼符合 Ripple 的設計理念,而不是用 React 的思維寫 Ripple。


快速開始

# 創建新項目
npx create-ripple-app my-app
cd my-app

# 啓動開發服務器
npm run dev

然後打開 src/App.ripple,開始編寫你的第一個 Ripple 組件!


寫在最後

AI 讓寫代碼變得更快了,但"更快"不等於"更好"。

當代碼生成的速度超過理解的速度,我們更需要:

  • 精簡的語法 — 讓代碼量回歸理性
  • 編譯時優化 — 讓性能有保障
  • 直觀的心智模型 — 讓維護不再痛苦

Ripple 不是為了追逐新概念而生,而是對"前端開發應該是什麼樣"的一次回答。

少寫代碼,寫好代碼。


Ripple — 讓響應式迴歸簡單

GitHub · 文檔 · llms.txt

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.