---
title: "JavaScript Runtime 是什麼？怎麼選擇 Node / Deno / Bun / Edge？"
description: "Runtime = JS engine + host API。附上用 AI agent 學習 JavaScript Runtime 的 prompts。"
lang: "zh-Hant-TW"
tags: ["JavaScript", "runtime", "Node.js", "Deno", "Bun", "edge-runtime"]
pubDate: 2026-06-05T00:00:00.000Z
updatedDate: 2026-06-09T00:00:00.000Z
---

我們每天寫 JS / TS，它到底跑在什麼上面？答案是某個 **runtime**，而 runtime 就是**一個 JS 引擎**（V8、JavaScriptCore…）**＋ 一組 host API**（決定 JS 看得到檔案、網路、process，還是只看得到 DOM）。一旦搞懂「引擎 + host API」這個架構，很多本來要硬記的問題會從同一個模型自然推出來：為什麼 Cloudflare Workers 沒有 `fs`、為什麼 React SSR 有兩個串流 API、Node / Deno / Bun / Edge 到底差在哪、哪些 code 換個環境就跑不動。

## 為什麼值得學

- **前端開發早就在用 Node.js，只是不一定會注意到。** `npm install`、`next dev`、`vite`、`tsc`、`eslint`、`prettier`，前端工具鏈幾乎全都是「跑在 Node 上的程式」。即使不寫 server，dev loop 也已經建立在 Node 上。
- **SSR、邊緣部署、build tooling 都站在 runtime 上。** 講「React SSR」其實是「React 在某個 JS runtime 上 render HTML」；講「邊緣部署」其實是「我的 code 跑在 Edge runtime 上」。runtime 是這些東西的共同底層。不了解這層的話，上面的選型討論就像在猜。
- **Web 標準正在跨 runtime 收斂，這兩年才真正成立。** [WinterTC](https://wintertc.org/)（Ecma TC55，前身為 W3C 的 [WinterCG](https://wintercg.org/)）正在把 fetch、Streams、Web Crypto、`AbortController`…這些原本是「瀏覽器專屬」的 API，訂成「所有 server-side runtime 都該有的最小共同集」，參與者包含 Node、Deno、Cloudflare、Vercel 等。程式碼越多採用 Web 標準 API，就越能跨 Node / Deno / Bun / Edge 跑。
- **AI agent 時代，runtime 是 agent 跑工具的家。** Claude Code 自己是 Node 應用、MCP server 多半是 Node、agent 在本機跑的 JS / TS 腳本也都靠這層。無論是寫工具給 agent 用，或讀懂 agent 在做什麼，都繞不開 runtime 這一層。

## 定位與脈絡

### 一句話：什麼是 JavaScript runtime

**JS 引擎 + 一組 host API。** 引擎負責把 JS 文字 parse、編譯、執行；host API 是引擎之外、host 額外給 JS 用的東西。差別不在引擎——**幾乎全在 host API**：

| Runtime          | 引擎                    | 提供的 Host API                                            |
| ---------------- | ----------------------- | ---------------------------------------------------------- |
| 瀏覽器           | V8 / JSC / SpiderMonkey | DOM、`window`、`document`、Web API（fetch、Streams…）      |
| **Node.js**      | V8                      | `fs`、`net`、`http`、`child_process`、`process`、`Buffer`… |
| **Deno**         | V8                      | Web API 優先（fetch、Streams…）＋ `Deno.*`                 |
| **Bun**          | JavaScriptCore          | Web API ＋ `Bun.*` ＋ 大部分 Node API（相容層）            |
| **Edge runtime** | V8 isolates             | Web API only——**沒有 `fs`、沒有 `child_process`**          |

瀏覽器本身其實就是一種 JS runtime。所以「不在瀏覽器跑 JS」的真正意思是：**換一組 host API**，換成看得到檔案系統、網路 socket、process 的那組。

### 四個玩家

- **[Node.js](https://nodejs.org/)（2009-）** by Ryan Dahl。第一個把 V8 接到 server 環境、催生了整個 npm 生態的東西，現在還是業界預設。歷史包袱是 CommonJS（`require`）和 ESM（`import`）並存的問題、`node_modules` 大、TS 之前只能靠外掛工具編譯。LTS 走 [Node 20 → 22 → 24](https://nodejs.org/en/about/previous-releases)。
- **[Deno](https://deno.com/)（2020-）** by Ryan Dahl（同一個人，[“10 things I regret about Node.js”](https://www.youtube.com/watch?v=M3BM9TB-8yA) 演講後做的「do-over」）。主要特色是 Web 標準 API 優先（fetch / Streams / Crypto 內建）、TypeScript 原生不用編譯、有 [permission model](https://docs.deno.com/runtime/fundamentals/security/)（明確允許才能讀檔/連網）、單一執行檔。Deno 1 時代生態小、跑不了大量 npm 套件是最大的問題；[Deno 2（2024/10）](https://deno.com/blog/v2) 起原生理解 `package.json` 與 `node_modules`、支援 npm workspace，好用很多。
- **[Bun](https://bun.sh/)（v1.0 於 [2023/09](https://bun.sh/blog/bun-v1.0)）** by Jarred Sumner。引擎換成 **JavaScriptCore**（Safari 那個，不是 V8），主打「比 Node 快數倍」，並把 runtime / package manager / bundler / test runner [整套綁在一個 binary](https://bun.sh/blog/bun-v1.0)：裝一個 Bun，就能包辦整條 dev loop。代價是還在補齊 Node 相容性、生態比 Node 小、`node_modules` 邊角偶有相容性問題。
- **Edge runtime**，包括 [Cloudflare Workers](https://developers.cloudflare.com/workers/runtime-apis/)、[Vercel Edge Functions](https://vercel.com/docs/functions/runtimes/edge)、[Deno Deploy](https://docs.deno.com/deploy/manual/)。這不是「再一個 Node」，是**部署型態**：把 V8 切成輕量 isolates 分散到全球節點、冷啟動毫秒級、按請求計費。代價是 API 大幅縮減（**沒有檔案系統、沒有 long-running process、執行時間和記憶體有上限**），只能用 Web 標準 API 寫。

### 值得學的 host API（學 runtime，很大一部分就是學這些）

既然引擎大同小異、差別幾乎全在 host API，那**「學會一個 runtime」很大一部分就是「學會它的 host API」**。下面這幾類是最該熟悉的，而且它們天然分成「Node 專屬」與「Web 標準」兩半，剛好就是「能不能跨 runtime / 能不能上 Edge」的分界線：

| Host API                                                                                                        | 做什麼                                        | 跨 runtime 可攜性                           |
| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------- |
| [`node:fs`](https://nodejs.org/api/fs.html)                                                                     | 讀寫檔案系統                                  | Node/Deno/Bun ✓、**Edge ✗**                 |
| [`node:child_process`](https://nodejs.org/api/child_process.html)                                               | 跑別的程式（**AI agent 在本機跑指令的底層**） | Node/Deno/Bun ✓、**Edge ✗**                 |
| [`node:http`](https://nodejs.org/api/http.html) / [`node:net`](https://nodejs.org/api/net.html)                 | 開 HTTP server、TCP socket                    | Node ✓、Deno/Bun 走相容層、**Edge ✗**       |
| [`node:process`](https://nodejs.org/api/process.html)                                                           | env / argv / stdin·stdout / exit code         | Node/Deno/Bun ✓、Edge 受限                  |
| [Node Streams](https://nodejs.org/api/stream.html) + `Buffer`                                                   | 串流大資料、pipe；二進位                      | Node ✓；跨 runtime 建議改用下面的 Web 版    |
| [`node:crypto`](https://nodejs.org/api/crypto.html)                                                             | 雜湊、簽章、加解密                            | Node/Deno/Bun ✓；跨 runtime 改用 Web Crypto |
| [`fetch` / `Request` / `Response`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)                  | 發/收 HTTP（Web 標準）                        | **全部 ✓**                                  |
| [Web Streams（`ReadableStream`…）](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) + `Uint8Array` | 串流、二進位（Web 標準）                      | **全部 ✓**                                  |
| [Web Crypto（`crypto.subtle`）](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)                | 雜湊、簽章（Web 標準）                        | **全部 ✓**                                  |
| [`AbortController` / `AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)           | 取消請求 / 操作 / timeout（Web 標準）         | **全部 ✓**                                  |

這張表的讀法是：**上半部（`node:` 命名空間）就是 Edge 沒有、跨 runtime 容易出事的那群；下半部（Web 標準、瀏覽器也有）才是「換 runtime 不換 code」的本錢。** 所以學 host API 和學「runtime 可攜性」根本是同一課的兩面。下一節會講為什麼這兩年特別值得多學下半部。

### Web 標準收斂：這兩年最重要的事

2024–2026 年最大的變化不是「誰最快」，而是**所有非瀏覽器 runtime 同時把 fetch、Streams、`Request` / `Response`、`AbortController`、Web Crypto 等 Web API 補齊**。這件事由 [WinterTC](https://wintertc.org/) 在推，實務上的影響有三個：

- **同一段 code 越用 Web 標準 API、越能跨 runtime 跑。** 用 `fetch` 而不是 Node 的 `http.request`、用 `Request` / `Response` 而不是 Express 的 `req` / `res`，同一個 handler 在 Node、Deno、Bun、Edge 上的行為會更一致。
- **這也解釋了 React SSR 為什麼有兩個串流 API。** [`renderToPipeableStream`](https://react.dev/reference/react-dom/server/renderToPipeableStream) 用 Node Stream，**只能在 Node 跑**；[`renderToReadableStream`](https://react.dev/reference/react-dom/server/renderToReadableStream) 用 Web Streams，**Edge / Deno / Bun 都能跑**。兩個 API 不是冗餘、是 host 差異逼出來的。
- **越靠 Web 標準，越能「換 runtime 不換 code」。** 想從 Node 遷到 Bun、從 Vercel 換到 Cloudflare，這條捷徑就在這。

### 常見混淆：runtime ≠ package manager ≠ bundler

這三層被 Bun 綁在一起後，初學者常分不清：

- **Runtime**：跑 JS 的引擎 + host：Node、Deno、Bun、Edge。
- **Package manager**：管 `node_modules`：npm、pnpm、yarn、bun。**它們本身都是「跑在 Node 上的程式」**（bun 例外，因為內建在 Bun 裡）。
- **Bundler**：把多檔 JS / TS 打成可發布的包：Vite、esbuild、Rolldown、Webpack。**也都是跑在 Node（或 Bun）上**。

[Bun 特別之處](https://bun.sh/blog/bun-v1.0)是它一個 binary 把這三件事全做了。便利歸便利，但別把「`bun install` 比 `npm install` 快」當成「Bun runtime 比 Node runtime 快」，這是兩件事。

### TypeScript 是「runtime 自己解」還是「工具鏈解」

「我寫 TS 能不能直接跑」這件事，目前各家 runtime 的做法不同：

- **Node**：[v22.6 開始實驗性支援 type stripping](https://nodejs.org/api/typescript.html)、v22.18 / v23.6 起預設可以直接 `node script.ts`、v24.12 / v25.2 後標為 stable。但 Node 的做法只是**把型別擦掉**，**不做型別檢查**，仍要靠 `tsc --noEmit` 才有檢查。
- **Deno / Bun**：原生跑 `.ts`，零配置。

### 附註：真要選，怎麼選

理解了上面那層，選型反而是小事，而且多數時候根本不用選：**沒有特殊理由就用 Node**，生態最大、職缺最多，常見的坑也幾乎都有現成答案，雲端與教學文件預設也都是它。只有少數情境會讓選擇偏離 Node：

- **想要 TS / runtime / PM / test 一條龍、也能接受框架還比較新的風險 → Bun。** 比 Node 快不是錯（多數 micro-benchmark 確實如此），但「快」幾乎從來不是選型最麻煩的地方；真正的風險在相容性：某個 npm 相依（或它依賴的某個 Node API）可能在 Bun 上有不完全相同的行為，而且往往要等到它**壞掉**才會發現。生態夠主流的套件多半沒事，用到 Node 底層或冷門原生模組的才是地雷。
- **想走 Web 標準的乾淨路線、想要 sandbox / 權限模型 → Deno。** Deno 2 後可用度大幅改善，但生態還是小一圈，主要取決於專案能否接受「比 Node 少一些邊緣套件」。
- **要全球 low-latency、低冷啟動 → Edge runtime。** 共同的前提是它走 Web-only 的 isolate 模型：通常沒有真正的檔案系統、不適合跑長時間的 process。但**確切的限制和計費方式（CPU／wall time 上限、記憶體、可用的 API、價格、分不分方案）每家差很多**，別記死任何數字，挑定哪家後直接讀那家的文件，例如 [Cloudflare Workers limits](https://developers.cloudflare.com/workers/platform/limits/)、[Vercel Functions limits](https://vercel.com/docs/functions/limitations)、[Deno Deploy](https://docs.deno.com/deploy/)。

## 怎麼入手

runtime 是個底層概念，與其塞進一個大 session 一次做完，不如拆成幾個各自獨立的 agent session，順序也有意義：**先讀懂概念 → 把 runtime 裝好設好 → 再用幾個真實小專案，分頭把最常用的 host API 各摸一遍**。下面每段 code block 都是一個獨立 session 的 prompt，開新對話、照順序貼給 agent。

### 第 1 步：把「runtime 這一層」讀懂（一個 session）

這篇給了「JS 引擎 + host API」的架構，建議**至少再從外部把同一個概念讀過一遍**才扎實。要找的是針對「runtime 這層」的資源，不是泛論 JS 語言、不是 event loop / async 這些相關但更上層的主題。找資料時**作者的權威性比「講得淺白」更重要**：簡化沒問題，但得是「真懂之後的簡化」，不是含糊的近似。對「JS 寫得熟、但還沒蹲過 server-side 底層」的人來說，下面兩篇權威入門剛好互補，一個是中文 narrative、一個是官方參考：

- **[Huli — 從「為什麼不能用這個函式」談執行環境（runtime）](https://blog.huli.tw/2022/02/09/javascript-runtime/)**（資深前端工程師 [Huli](https://blog.huli.tw/about/)；亦有[英文版](https://blog.huli.tw/2022/02/09/en/javascript-runtime/)）。從「在 browser 跑 `btoa` 沒事、在 Node 卻報 `btoa is not defined`」這個具體故事切入，順勢帶出「JS 核心、browser host、Node host」的分層，是中文圈最好的入門 narrative。
- **[MDN — JavaScript execution model](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model)**（Mozilla 官方參考；Mozilla 自己維護 SpiderMonkey 引擎）。開頭第一段就用了跟本文同一組詞：「JavaScript execution requires the cooperation of two pieces of software: the JavaScript engine and the host environment.」可以當英文參照，順便對齊術語。

想再深一格：[Cloudflare — How Workers works](https://developers.cloudflare.com/workers/reference/how-workers-works/)，從 V8 isolate 角度補一筆「為什麼 Edge 也是一種 runtime、但跟 Node 不同層」。

👉 複製這段 prompt 開一個 session：

```
我想真正理解「JavaScript runtime」這層——尤其「JS 引擎 + host API」的分層，
以及為什麼 Node / Deno / Bun / Edge 是同一個概念的不同實作。請帶我做這件事，
不確定就先問我：
1. 讓我自己先讀下面兩篇權威入門（請不要憑記憶複述、不要先總結，我讀完再來討論）：
   - Huli: https://blog.huli.tw/2022/02/09/javascript-runtime/
   - MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model
   如果你判斷還需要 1–2 個權威、不誤導、針對「runtime 這層」（不是 event loop /
   async）的資源來補強，列出來並各附「為什麼可信」一句話——作者要在 runtime 領域有
   verifiable 的深度（runtime / 引擎核心貢獻者、官方標準文件、研討會講者之類），
   別給內容農場或 AI 拼湊的文章。
2. 我讀完後，用一段話跟我對齊重點：runtime = JS 引擎 + host API、為什麼差別幾乎
   全在 host API、這個分層怎麼直接解釋「同一段 code 在某個 runtime 跑得了、在另一個
   跑不了」——例如 Cloudflare Workers 沒有 fs、Node 與 Bun 的 npm 邊角相容性、
   React SSR 為什麼有兩個串流 API。
3. 出幾題問我（「V8 ≠ Node」是什麼意思、Bun 換 JSC 對 Node 相容的影響、為什麼 Edge
   的限制不能用「再加些 Node API 就好」解決），我答完後依官方文件或上面列的權威資源
   （不要憑你的記憶）幫我訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

### 第 2 步：把 runtime 裝好、設好（一個 session）

概念有了，先把環境弄對再寫 code。runtime 的裝法這幾年一直在變（版本管理器、LTS 政策、原生 TS 支援陸續變動），**別照舊文章硬裝**，可以讓 agent 查當下官方與社群最推薦的做法，並先檢查機器上已有的工具與潛在衝突。

👉 複製這段 prompt 開一個 session：

```
我要把一個 JS runtime（Node / Deno / Bun，請先幫我評估或問我該用哪個）裝好、設定好，
當作後面練習的環境。請依「當下最新」的官方與社群建議帶我，不要照你記憶中的舊裝法，不確定就問我：
1. 先看我機器現況：幫我跑並解讀 `node -v`、`which -a node`、有沒有裝 nvm / fnm / Volta、
   有沒有 Homebrew 裝的 node 跟版本管理器打架、PATH 有沒有問題。
2. 查目前官方 + 社群最推薦的裝法並給我推薦與理由：例如 Node 該用版本管理器（nvm / fnm / Volta）
   還是官方安裝檔、該裝哪個 LTS、要不要開原生 TS 執行；若選 Deno / Bun 則各自的官方裝法。
3. 帶我裝好、設好一個乾淨基準（版本管理器、預設版本、確認能不能直接 `node script.ts`），
   每個設定都說明在幹嘛。
4. 出兩題問我（為什麼用版本管理器而不是系統全域裝一個、LTS 跟 Current 差在哪），依官方文件訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

### 第 3 步：用真實小專案，分頭把常用 host API 摸過（每個 POC 一個 session）

這步是重點，規劃方式刻意**反過來想**：先列出「初學者非懂不可的 host API 有哪幾群」，再為每群挑一個最能讓人體會它在解什麼的真實小專案。下表就是這樣排出來的，**每個 POC 是一個獨立 session，挑還不熟的那群做就好，不必全做**：

| 真實小專案（POC）                                          | 會摸到的 host API                                        | 實作中會碰到的核心觀念                                                                |
| ---------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| **檔案處理器 / 迷你 bundler**（讀一堆檔 → 轉換 → 輸出）    | `fs` / `fs/promises`、`path`、Node Streams               | 檔案系統、**同步 vs 非同步**（`readFileSync` 為何卡死 server）、用串流處理大檔        |
| **Express 式 HTTP 伺服器 + 路由**                          | `node:http`（或 `Bun.serve`）、`Request` / `Response`    | server 怎麼收發請求、路由、handler 天生非同步                                         |
| **網頁爬蟲（web scraper）**                                | 全域 `fetch`、`AbortController`、Web Streams、Web Crypto | 對外網路呼叫、**並發控制**（`Promise.all` vs 逐一 await）、timeout 取消、用 hash 去重 |
| **包一個指令的 CLI dev tool**（lint / format runner 之類） | `process`（argv / env / stdio）、`child_process.spawn`   | 程式怎麼讀參數與環境、**跑子程序並即時串流它的輸出**（AI agent 在本機跑指令的底層）   |

下面是四個 POC 的完整 prompt。每個是一個獨立的 agent session，挑想做的那個複製整段去開新對話；不必全做。

#### POC ① 檔案處理器 / 迷你 bundler

👉 複製這段 prompt 開一個 session：

```
我想透過做一個最小的「檔案處理器 / 迷你 bundler」——讀進一個資料夾的多個 .ts 檔、
做簡單轉換（譬如把 import 接成單一字串）、寫出一個合併檔——來搞懂 JS runtime 裡跟
「檔案系統」相關的 host API：fs / fs/promises、path、以及 Node Streams。
不確定就先問我：
1. 入門：用一段話講這幾個 host API 各自在解什麼問題；尤其把「為什麼 server 端不該用
   readFileSync」（同步呼叫卡住 event loop、整個 process 停在這裡）這件事講清楚。
2. 動手 v1：帶我從零做到能跑——讀資料夾、逐檔處理、寫出 bundle。第一版**故意用同步
   API**（readFileSync / writeFileSync），先跑通。
3. 進階：把同步版改成非同步（fs/promises）。然後用一個「會卡」情境讓我親眼比較兩者
   差別——例如在同支腳本裡也起一個小 HTTP server，跑同步版時 server 對請求停止回應、
   跑非同步版時不會。
4. 大檔：當輸入是數百 MB 的單檔，readFile 把整檔讀進記憶體都不划算——帶我把讀寫改成
   Node Streams（createReadStream / createWriteStream + pipe），講清楚 stream 解決的是
   哪個問題、什麼時候根本不用 stream。
5. 可攜性：指出這支工具哪些段只能在 Node 跑、為什麼 Edge runtime 不可能跑——並用這個
   例子說明「沒有 fs」這條限制不是 API 還沒補，是 sandbox 模型決定的。
6. 檢查：出幾題問我（readFileSync 為什麼在 server 是地雷、stream 解決的是哪個問題、
   path.join 為什麼不該用字串相加代替），我答完後依 Node 官方文件
   （不要憑你的記憶）幫我訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

#### POC ② Express 式 HTTP 伺服器 + 路由

👉 複製這段 prompt 開一個 session：

```
我想透過從零做一個最小的「Express 式 HTTP 伺服器 + 路由」（**不用 Express、不用任何
framework**）——支援幾條路由（GET /、GET /api/items、POST /api/items）並回 JSON——
來搞懂 JS runtime 裡跟「server 收發網路請求」相關的 host API。不確定就先問我：
1. 入門：用一段話講一個 HTTP server 在 runtime 裡到底在做什麼——listen socket、接連線、
   parse 出 request、把 response 寫回去——以及為什麼 handler 幾乎都是 async。
2. 動手 A：用 Node 的 `node:http` 從零寫一遍。自己 parse URL、用 if / switch 寫一個小
   路由表、用 JSON.stringify 回 response，讓我看到「沒有框架時 handler 長什麼樣」。
3. 動手 B：把同一支 server 改寫成 Web 標準的「fetch handler」形式——一個
   (request: Request) => Promise<Response>——部到 Bun（用 Bun.serve）或 Deno（用 Deno.serve）跑。
4. 對照：並排告訴我 (A) `node:http` 是 Node 專屬 host API；(B) `Request` / `Response`
   是 Web 標準、跨 runtime 可攜；後者也是 Cloudflare Workers / Vercel Edge / Next.js
   Route Handlers 的同一個模型——一旦寫成這形狀，code 幾乎不用改就能上 Edge。
5. 親手感受單執行緒：在 handler 裡故意塞一個 5 秒的同步 CPU 迴圈，用 ab / curl 連發
   幾個請求看會發生什麼——讓我親眼看到「一個 handler 卡住 = 整個 server 卡住」。
6. 檢查：出幾題問我（為什麼 `node:http` 的 server 不能直接上 Cloudflare Workers、
   Request / Response 的好處到底是什麼、handler 為什麼幾乎都是 async），我答完後依
   Node、Bun、MDN 官方文件（不要憑你的記憶）幫我訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

#### POC ③ 網頁爬蟲

👉 複製這段 prompt 開一個 session：

```
我想透過做一個最小的「網頁爬蟲」——給一份 URL 清單，逐一抓回 HTML、抽出 <title>、
存成 JSON——來搞懂 JS runtime 裡跟「對外網路呼叫」相關的 Web 標準 host API：
全域 fetch、AbortController、Web Crypto。不確定就先問我：
1. 入門：用一段話講為什麼這幾個 API 是 Web 標準（瀏覽器、Node、Deno、Bun、Edge 都有），
   以及「同步 fetch」為什麼根本不存在——能用 fetch 是因為 runtime 給了 event loop +
   promise 排程。
2. 動手 v1：用最樸素的方式做出來——一個 for loop、每個 URL 逐一 await fetch，
   抓 response.text()、用 regex 抽 <title>。先跑通。
3. 並發控制：把所有 fetch 改成一次發出（Promise.all），我跑一次告訴你結果；然後帶我
   加「同時最多 N 個」的並發上限，並解釋「all at once」、「逐一」、「有上限的並發」這
   三種在真實世界各會踩到什麼問題（rate limit、總時長、記憶體 / file descriptor 爆掉）。
4. Timeout / 取消：每個 fetch 加 3 秒 timeout，**親手用 AbortController + setTimeout
   寫一次**（不要包好的 library），讓我看清 AbortController 是泛用的取消機制、不是
   fetch 的選項。
5. 去重：用 Web Crypto 的 `crypto.subtle.digest()` 對每頁內容算 SHA-256，把「不同網址
   但內容一樣」的頁面去重；順便讓我認識 Web Crypto 跟 Node 的 node:crypto 是兩個不同
   的 API、什麼時候該用哪個。
6. 可攜性實驗：整支爬蟲幾乎全用 Web 標準。帶我把它原封不動丟到 Bun 跑、再部到一個
   Cloudflare Worker 上跑——讓我親眼看到「code 不改、跨 runtime 直接跑」。
7. 檢查：出幾題問我（為什麼沒有同步 fetch、Promise.all 的失敗模式、AbortController 跟
   timeout 的關係、Web Crypto 為什麼是 async），我答完後依 MDN、Node、Cloudflare
   Workers 官方文件（不要憑你的記憶）幫我訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

#### POC ④ 包一個指令的 CLI dev tool

👉 複製這段 prompt 開一個 session：

```
我想透過做一個最小的「CLI dev tool」——譬如包一個 typecheck runner，跑
`mytool ./src` 會找這個資料夾的 tsconfig.json、起一個 child process 跑 `tsc --noEmit`、
把錯誤即時印出來——來搞懂 JS runtime 裡跟「程式怎麼讀參數、怎麼跑別的程式」相關的
host API：process、child_process.spawn、stdio 的串流。**這正是 AI agent 在本機跑指令
的縮影。** 不確定就先問我：
1. 入門：用一段話講 process 物件給了你什麼（argv / env / cwd / stdin / stdout / stderr /
   exit code），以及 child_process 裡 spawn / exec / execSync 的差別——為什麼幾乎永遠該用
   spawn（不要 buffer 全部輸出）。
2. 動手：用 process.argv 解參數、用 process.env 讀環境變數、用 child_process.spawn 起
   一個 child 跑 `npx tsc --noEmit`，並把 child 的 stdout / stderr **即時** pipe 到自己的
   process.stdout / process.stderr——讓使用者看到 tsc 的輸出一行一行冒出來，不是等整個
   跑完一次吐。
3. Timeout / 取消：加一個 --timeout 參數，用 AbortController（spawn 接受 signal）讓子
   程序超時就被中止；child 結束後依它的 exit code 決定自己的 exit code。
4. 親手感受 buffer 為什麼壞：拿一個會輸出超大量 stdout 的指令（譬如一個故意印百萬行
   的腳本）打進去，先跑串流版；接著請你解釋如果改用 execSync 或 exec、為什麼這支工具
   會把記憶體吃光甚至 OOM。
5. AI agent 視角：請告訴我這個結構（讀 args → 起 child → 串流 stdout → 控 timeout →
   處理 exit code）正是 Claude Code / MCP server / agent 在本機跑指令的同一個 host API
   組合，也是 Edge runtime「永遠」不可能跑這種工具的原因——不是 API 沒補，是 sandbox
   模型不允許 spawn 子程序。
6. 檢查：出幾題問我（spawn vs exec 為什麼選 spawn、為什麼 child 的 stdout 要 pipe 不要
   等全部 buffer 完、process.exit() 為什麼可能截斷還沒寫完的 stdout），我答完後依 Node
   官方文件（不要憑你的記憶）幫我訂正。

若這個 session 過長、方向變過幾次，或你判斷 context 壓縮可能影響你的理解，提醒我：換新 session 通常會更穩、更準。提醒時一併把目前狀態、決策、待辦、關鍵檔案路徑整理成一份專案內的交接 Markdown 給下一輪 agent 用；沒有合適專案資料夾或任務很輕，就直接把摘要貼進新對話。不要頻繁提醒，只在真的會影響品質時提。
```

## 延伸主題

- **[React + TypeScript + SSR](/articles/frontend-to-fullstack/react-ssr-frameworks)**：JS runtime 最常被用到的場景。SSR 的整個討論（從 raw Vite 接 SSR、到 Next.js 的快取模型、到 Edge 部署的限制）其實都建在這篇的「runtime 是什麼」之上。
- **[Web app architecture](/articles/frontend-to-fullstack/web-app-architecture)**：runtime 只是 production stack 裡的一個部分，這頁把其他部分（DNS、CDN、LB、DB、object storage、queue、secrets、observability）鋪開，看一個人怎麼把一個 web app 端到端送上雲。讀完 runtime、想知道「我寫的這段 code 上線那天還會跟誰共處」，這頁是地圖。
- **回頭補「引擎」那半（選讀）：[Lydia Hallie — JavaScript Visualized: the JavaScript Engine](https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf)**（知名 JS 視覺化教學作者，以 Keynote 手繪動畫拆解 JS internals）。本篇刻意把引擎當成大同小異的黑盒、重點放在 host API；但若「引擎到底在 parse、compile、執行什麼，heap、call stack 是什麼」仍然模糊，這篇圖解是很好的補充。（偏好影片、想把 JS 底層一次看過的話，她的個人頻道 [@theavocoder](https://www.youtube.com/@theavocoder) 有整個 JavaScript Visualized 視覺化系列，包括 execution context、closures、[event loop](https://www.youtube.com/watch?v=eiC58R16hb8)、promise 等；範圍比本篇的「引擎 + host API」更廣，偏 JS 語言內部與 async 排程。）
