一個完全在瀏覽器中運作的 JavaScript 線上編輯器替代方案,是一個沙箱化的頁面,你可以在其中輸入簡短的程式碼、點擊執行,然後讀取控制台輸出、回傳值、錯誤或逾時指示,而無需開設帳號、安裝 Node.js,或將你的程式碼片段傳送到遠端建置服務。JavaScript Playground 完全採用這種模式:編輯器是你裝置上的一個單一頁面,每次點擊 Run 都會建立一個全新的獨立來源沙箱化 iframe 和一個專屬的 Web Worker,而使用者程式碼會在 Worker 內執行,而不是在 UI 執行緒上。這個沙箱化 iframe 帶有內容安全政策 (Content Security Policy),預設拒絕所有外部資源並封鎖所有網路連線,因此 Worker 沒有 DOM、沒有 document、沒有 window、沒有 cookie、沒有 localStorage,也沒有 fetch 管道。一個嚴格的 1,500 毫秒牆鐘時間上限會終止任何執行時間過長的程式碼片段,這代表一個意外發生的無限迴圈無法凍結編輯器,也永遠不會連線到伺服器。這種隔離機制,正是讓 JavaScript 線上編輯器替代方案在快速演算法、正則表達式實驗、JSON 解析、數學運算和語言測試方面實用的原因,而這些正是託管式線上編輯器往往過度配備的工作。

javascript playground alternative
javascript playground alternative

為什麼開發者會尋找 JavaScript 線上編輯器替代方案

像 CodePen、JSFiddle、CodeSandbox 和 RunJS 這類託管式線上編輯器是功能強大的環境,但它們的強大伴隨著快速測試不一定需要的功能。它們大多需要帳號、會將你的工作儲存到專案中、對使用者程式碼開放網路存取,並在與編輯器共用儲存空間的同源環境中執行腳本。對於演算法草圖、一行程式碼的正則表達式或字串解析實驗來說,這樣的接觸面比實際需要更為龐大:它會將你的程式碼片段拉進雲端專案、留下痕跡,而且無法保證能防範 cookie、父頁面,或因你程式碼中的疏忽而發出的外部請求。

圍繞每次執行隔離 worker 所打造的 JavaScript 線上編輯器替代方案,解決的是不同的問題。它將每次點擊 Run 視為一個一次性的容器:新 iframe 搭配獨立來源、新 Worker、新密碼學權杖,以及程式碼片段的全新空白狀態。執行之間不會儲存任何東西,worker 沒有可存取的宿主頁面參照,網路會在 iframe 的 CSP 層級被封鎖,而不是靠禮貌性的慣例來約束。這讓它成為快速瀏覽器控制台和完整託管開發環境之間,一個務實的中間地帶。

這種形式也適合注重隱私的工作流程。這個工具的承諾是使用者程式碼永遠不會逃出沙箱:它無法讀取你的 cookie、無法沿著已儲存的工作階段前進、無法用你的憑證擷取 URL,也無法將任何東西持久化到磁碟。你不需要信任遠端平台來隔離你的程式碼片段,因為隔離是由你自己瀏覽器中的沙箱屬性和內容安全政策強制執行的。

本機沙箱如何隔離你的程式碼

三個層次相互配合,以確保使用者程式碼受到限制。首先,程式碼片段在被插入沙箱之前會進行 JSON 編碼,字串字面值內的任何小於字元都會被跳脫,因此看起來像結尾 script 標籤的字串無法突破啟動標記。其次,每次執行都會取得一個新的 iframe,其沙箱屬性僅設定為 allow-scripts:腳本可以執行,但同源存取、表單、導覽、彈出視窗和下載都會被拒絕。這個 iframe 也會取得獨立來源,這代表它無法讀取或寫入託管編輯器之頁面的 cookie、儲存空間或 DOM。第三,套用預設拒絕的內容安全政策:default-src 'none'、connect-src 'none'、沒有基礎 URI、沒有 form 動作,而且只有內嵌啟動程式碼和以 Blob 建構的 Worker 被允許載入。

在該 iframe 內,程式碼根本不在 UI 執行緒上執行。編輯器會改為建立一個 Blob URL Worker、將編碼後的程式碼片段發送至其中,並等待訊息回傳。每則訊息會同時對照三項條件進行檢查:它必須來自 iframe 自己的 window、必須帶有編輯器能識別的固定標記,而且必須包含這次執行所產生的同一組密碼學權杖。若其中任何一項不符,該訊息會被靜默丟棄。這能阻止同層級的 iframe、第三方腳本或殘留的訊息通道,將偽造的輸出注入到控制台面板。

Worker 也帶有嚴格的 1,500 毫秒逾時。當計時器觸發時,iframe 會終止 Worker、擷取它所收集到的任何控制台輸出,並回報逾時以代替結果。由於執行作業位於 Worker 內而非頁面上,無限迴圈或失控遞迴無法鎖定編輯器本身 —— UI 會保持回應,同時程式碼片段會被終止。這個模式在 MDN 的 Web Workers API 文件中有詳細說明,該文件解釋了為什麼獨立的執行緒能讓你在不干擾宿主頁面的情況下終止失控的工作。

在 Playground 中執行程式碼片段

下面的三個步驟會逐步介紹在 JavaScript Playground 頁面上執行一般程式碼片段的典型流程。相同的流程在 how to run code in a JavaScript Playground 指南中也有說明,如果你想要更詳細的操作說明,可以參考該指南。

  1. 輸入一個不需要 DOM 或 Node.js API 的有限 JavaScript 程式碼片段。編輯器接受最多 30,000 個字元,所以大多數演算法、解析器和正則表達式實驗都能從容容納。由於 Worker 沒有 document、window、fetch 或 process 等全域物件,請將它視為一般的 JavaScript 執行階段,並跳過任何涉及瀏覽器或伺服器的程式碼。
  2. 選擇 Run JavaScript 以建立全新的隔離 worker 和沙箱。編輯器會產生新的密碼學權杖、以預設拒絕的 CSP 建構獨立來源的 iframe、將你的程式碼片段編碼為 JSON,並在 iframe 內啟動 Blob Worker。先前的沙箱會在新沙箱啟動之前被銷毀。
  3. 在更改並重新執行程式碼之前,先檢視控制台、結果、錯誤或逾時輸出。Console.log 和 console.error 項目會出現在控制台面板中;若可格式化,最後一個運算式會回報為結果;擲回的錯誤會顯示在錯誤面板中;而任何在 1,500 毫秒內未完成的程式碼片段都會被回報為逾時。

兩個實用的注意事項能幫助大多數程式碼片段乾淨地完成。請讓迴圈保持有限 —— 優先採用硬式結束而非 while (true) 模式 —— 因為 1,500 毫秒上限是牆鐘防護,而不是效能目標。另外,如果你回傳物件,請記住循環或不常見的值會被簡化:格式化器會在可行時使用 JSON,否則退而採用字串。

沙箱允許什麼,又拒絕什麼

思考 JavaScript 線上編輯器替代方案時,一個有用的方式是寫下沙箱所開放的確切接觸面,以及它所拒絕的確切接觸面。下面的清單是取自該工具的承諾,而不是對線上編輯器的一般性假設。

功能沙箱內的狀態
陣列、字串、物件、數字、數學允許
Console.log、console.error擷取並顯示在控制台面板中
Promise、async/await允許;Promise 會被等待直到它們解決 (settle) 或 worker 被終止
DOM、document、window、localStorage、cookie在 Worker 環境中無法使用
fetch、XMLHttpRequest、WebSocket、EventSource被 iframe 的內容安全政策封鎖
import()、require()、Node.js 模組未提供套件執行階段
原始碼大小上限每個程式碼片段最多 30,000 個字元
失控迴圈的處理在 1,500 毫秒後終止 Worker
跨執行狀態每次執行時都會替換;不會持久化任何東西
機密、密碼、API 權杖、客戶資料絕對不要將它們貼到任何線上編輯器中

沙箱是合適工具的情境

快速實驗最適合這種風格的線上編輯器。沙箱特別適合於:

  • 演算法工作:排序變體、搜尋樹、遞迴深度、記憶化模式、使用普通數字和 BigInt 的 BigInteger 技巧。
  • 字串與解析任務:正則表達式迭代、CSV 和 JSON 結構測試、不需要呼叫網路的 URL 解析器實驗。
  • 數學與算術:數字格式化、四捨五入的邊界情況、IEEE 754 好奇心的檢查、整數溢出的防護。
  • 語言功能測試:optional chaining、結構化複製、弱參照、Proxy 與 Reflect 行為、產生器 (generator) 語意。
  • 非同步模式試驗:Promise 組合子、AbortController 邏輯、queueMicrotask 排程,所有這些都在 Worker 內執行,並享有相同的逾時安全網。

這個替代方案並非為任何需要瀏覽器功能的用途所設計。UI 元件、Canvas 或 WebGL 渲染、Service Workers、IndexedDB、剪貼簿讀取、音訊播放、地理位置和表單提交,這些全都無法存取,因為 Worker 沒有 document,也沒有宿主頁面的參照。如果程式碼片段涉及 DOM,你需要的是一般的 HTML 預覽或完整的 IDE,而不是 worker 沙箱。如果程式碼片段需要相依套件,你需要的是帶有套件管理工具和真正執行階段的本機專案。

貼上之前值得知道的限制

這個 JavaScript 線上編輯器替代方案有幾個特性很容易被誤讀:

  • 1,500 毫秒的逾時是安全網,而不是基準。瀏覽器的排程會有所變動,因此非同步工作可能在解決之前就被終止。只要 worker 還活著,Promise 就會被等待,但無法保證一長串的 setTimeout 鏈會執行到底。
  • 30,000 字元的上限雖然寬鬆,但並非無限大。冗長的產生式測試案例或大型內嵌測試資料應該放在編輯器之外;只有要測試的演算法才屬於程式碼片段的範圍。
  • 輸出格式化會在可行時使用 JSON,否則退而採用字串。循環結構、類別實例和不常見的原型會被簡化,而不是完整呈現,因此列印結果的目的是用於快速的視覺確認,而不是作為可交付的值。
  • 沙箱是防禦邊界,而不是通行證。請像對待任何其他線上編輯器一樣對待它:檢視程式碼片段、不要貼上機密,而且永遠不要假設隔離就能讓任意程式碼安全地執行。
  • 對於正式環境的程式碼,請使用帶有版本控制的本機專案,其中包含測試、程式碼檢查、相依套件審查,以及實際會執行它的執行階段。線上編輯器是用來自言自語思考的;真正的程式碼住在真正的儲存庫中。

使用這個工具最乾淨的方式,是讓程式碼片段保持自給自足:相當於一個檔案份量的邏輯、沒有外部資料、沒有機密資料,以及對演算法應該花費多少時間有一個誠實的上限。養成這些習慣後,沙箱就能提供一個快速、可預測的地方來測試想法,再將其提升到真正的專案中。

如果你正在權衡各種選項,JSON to CSV Alternative With Built-In Formula Protection 對此有詳細說明。