本站有一塊叫沙盒的頁面,路徑 /playgrounds/(程式裡叫 Playgrounds)。目標很具體:在瀏覽器裡編輯多檔輕量 Web 專案、立刻在畫布看到結果,必要時再掛 edge functions 形的 /api/*,以及可選的 coding agent/REPL。資料權威在本機 OPFS,本站不當專案雲端硬碟。
這篇整理它怎麼疊起來。要手玩請直接開沙盒;這裡不逐步教學。
目錄
展開目錄
殼頁、工作專案、畫布
介面上大致三塊:
| 區塊 | 做什麼 |
|---|---|
| 殼頁 | CodeMirror 編輯、檔案樹、專案匯入/匯出、把當前專案快照餵給畫布 |
| 工作專案 | OPFS 裡的一組檔案;權威儲存,可含文字與二進位 |
| 畫布 | 同源 iframe,用 URL /playgrounds/canvas/<projectId>/… 載入,像從網路上開一個站 |
畫布入口固定專案根目錄的 index.html。相對路徑的 ESM、CSS、圖、字型走瀏覽器原生解析,不必每次在殼頁手改模組路徑。
早期若用 srcdoc+改寫 import,相對資源與快取行為都很彆扭。現況改成:專用 Service Worker(sw-canvas.js,scope 在 /playgrounds/,只攔截 /playgrounds/canvas/)在記憶體裡依殼頁 postMessage 過來的快照回 Response。HTML 回應帶一點 CSP(base-uri/object-src/frame-ancestors 等)。殼頁的離線 SW 不快取 canvas 路徑,避免跟這條虛擬站台搶。
信任模型也寫死:這是本機實驗場,畫布與殼頁同源,專案腳本碰得到同 origin 儲存與 parent。不做多租戶硬隔離;殼頁也不放秘密。
OPFS 當專案權威
每個專案一個 id,檔案進 Origin Private File System。重點:
- 文字/二進位都可存;編輯器只開判為文字的檔。
- ZIP import/export 原樣帶 binary;可自 GitHub public repo 拉檔寫入(之後與遠端無關)。
- 不支援 OPFS 的瀏覽器直接失敗,不默默退回 localStorage 假裝同一套儲存。
另外還有幾塊也落在 OPFS、但跟「專案原始碼樹」分開:模擬 KV、checkpoint、D1、Secrets 各有自己的前綴目錄。clone 專案時,KV/Secrets 不跟著複製——避免把 session 或密鑰當原始碼一起拷走。
functions.js:Workers 形的 /api/*
畫布裡的 fetch("/api/…") 會被橋到 /playgrounds/canvas/<projectId>/api/…,由殼頁執行該專案根目錄的 functions.js:
export default {
async fetch(request, env, ctx) {
// …
},
};
形狀對齊 Cloudflare Workers 的直覺:env 可注入模擬 KV(Durable:寫 OPFS)、以及(在現行 Agent 專案)env.HOST。另有模擬 D1(sql.js 子集)與 Secrets(殼頁 UI 寫入;HOST 只能列名、讀不到值)。沒有 functions.js 時 API 回 503。
這條路的用意是:靜態前端+一點 serverless 形後端,可以在分頁裡驗證;真要上線再部署到真正的 edge,而不是把沙盒當成正式託管。
Coding agent:雙執行面+env.HOST
若啟用 agent,殼頁維持兩條執行面:
- 工作專案:編輯器+原畫布,被改、被驗的那份程式。
- 現行 Agent:另一個沙盒專案,UI 跑在左側 Agent 區(同樣走 canvas SW/
index.html),不是殼頁手寫的 chat 元件。
Agent 跟環境互動的正式通道只有一條:
Agent UI → fetch("/api/…") → 該專案 functions.js → env.HOST
HOST 提供版本化能力(apiVersion/capabilities):列檔、讀寫(可選 expectedHash)、search、重載畫布、讀/等 console、checkpoint、建立/複製/開啟專案等。約束包括:
- 只有現行 Agent 專案才注入
HOST; - 禁止經 HOST 寫入現行 Agent 自己的檔案(避免熱改執行中的自己);
- 刪專案:HOST 只刪帶
agentManaged標記、由 agent create/clone 出來的專案。
LLM 走 BYOK:endpoint/model/key 留在 Agent 專案 UI 的儲存裡,本站不代打、不存 key。
下方面板:Console、Python、JavaScript
| 面板 | 實作要點 |
|---|---|
| Console | 畫布 runtime 的 log/error,殼頁轉送進 buffer;agent 也可經 HOST 讀 |
| Python | 隔離 Pyodide Worker(CDN 釘版);人類 xterm REPL 與 HOST.runPython 共用同一 Worker;%pip 允許清單、%run 可把專案 .py 同步進 Pyodide FS |
| JavaScript | 另一個 Worker 沙盒(與畫布 runtime 分開);REPL+%run 專案 .js(含相對 ESM);無 npm |
曾經試過在下方塞 v86/Alpine 當「真 Linux」。對「輕量 Web+functions」主軸槓桿低(慢、無網、無編譯鏈),後來整段拿掉;人類路徑改成上面兩個 REPL,也不做 HOST.shell。
邊界(技術上不做的)
- 不當部署環境、不當完整 Node/WebContainer。
- 不做通用 CORS proxy/站內代抓任意外網。
- 不承諾模擬 KV/D1 與雲端 Cloudflare 全相容。
- 頁面
noindex,也不進 XML sitemap——它是站內實驗頁,不是要靠搜尋引擎養流量的薄頁。
結構可以再拆細講(畫布 SW 協定、HOST 錯誤碼、Pyodide 與專案 FS 同步)。這篇先把骨架放在桌上;要按的從沙盒進去即可。