Deno

Deno 的開發環境和 Deno 本身都很粗糙,不應將其用於生產環境。
從 Deno 的開發時間來考慮,Deno 團隊的表現不佳,
以至於 Node.js 已經逐漸趕上 Deno 的特性,還出現了 Bun 這樣相同生態位的競爭對手。
很難對 Deno 的未來有信心。
  • 用 Rust 開發。
  • API 盡可能與 Web 環境兼容。
  • 具有主見的 `=deno fmt=`, `=deno lint=`, `=deno test=`, `=deno bench=`。
  • 預設安全,具有細粒度的權限系統,支援動態請求權限。
    目前,由於 Deno 有許多內部使用的欄位,細粒度權限用起來可能很不方便,最後還是會被迫去使用粗粒度權限。
  • 原生支援 TypeScript,這點正變得越來越重要,因為 JavaScript 社群正在向 TypeScript 轉變。
  • Node.js 兼容性。
Deno 的內建功能普遍缺乏嚴謹的測試,依賴社群回饋錯誤。
儘管 LTS 在各種專案裡都有越來越短的跡象,但 Deno 2 在發佈時將 6 個月聲明為 LTS 仍然令人忍俊不禁。
Deno Land Inc. 熱衷於開發其他生態環境產品的克隆/替代品。
這些產品明顯缺乏深思熟慮,可維護性存疑。
這種傾向也影響了 Deno 本身,例如 Node.js 兼容性就是一個行銷炒作凌駕於實際交付的典型例子:
https://docs.deno.com/runtime/reference/node_apis/#fully-supported-modules
稍有規模的 Deno 專案就會導致 LSP 的響應速度變慢,很容易勸退想要使用 Deno 的開發人員。
相比之下,基於 Node.js 和 TypeScript 的專案則完全沒有類似的問題。
Deno 的 LSP 預設配置相當保守,例如,`=documentPreloadLimit=` 的預設值為 1000,實際開發中很容易超出。
WHATWG 流模型的設計相當簡陋,遠遠比不上 Node.js 的流。
舉例來說,使用者甚至無法知道一個流是否關閉,或是什麼時候關閉的。
模組會根據被導入的情況,決定其協定。
當模組作為本地模組被導入時,模組的 `=import.meta.url=` 為 file 協定。
當模組作為遠端模組被導入時,其 `=import.meta.url=` 為 http/https 協定。
問題在於相當多的 API 只支援一種協定,例如 `=Deno.readFile=` 僅支援 file 協定,不支援 http/https 協定。
這種情況導致開發者在使用 `=import.meta.url=` 時有更多的心智負擔。
根本問題出在 Deno 不暴露導入模組(快取)的本地路徑,而這本身是一個在設計層面就可以解決的問題。
https://github.com/denoland/deno/issues/5987
相當可悲地,Deno 透過讓 `fetch` 函數支援 file 協定來解決讀取檔案相關的問題。
https://github.com/denoland/deno/issues/3196
TypeScript 不支援將 `.ts` 擴展名的模組路徑編譯為 `.js` 擴展名,
而 Deno 的模組路徑一定是 `.ts` 擴展名。
因此,為 Node.js 模組設計的 TypeScript 專案的程式碼將無法在 Deno 裡運行。
TypeScript 5 開始支援 `allowImportingTsExtensions` 配置項,這允許在專案裡使用 `.ts` 擴展名,
但該配置項被限制為只能在配置為 `noEmit` 或 `emitDeclarationOnly` 的情況下使用,
這意味著使用 `.ts` 擴展名的同時不能生成可用於 Node.js 的程式碼。
Deno 官方推進的 JavaScript 套件註冊表。
儘管 JSR 在宣傳上標榜自己是一個現代 JavaScript 的套件註冊表,但它仍然只是 Deno 版本的 npm。
JSR 不是 npm 的超集,就像 TypeScript 不是 JavaScript 的超集一樣。
該註冊表很大程度上是為了解決 Deno 存在的依賴管理問題(Ryan Dahl 在 2018 年擲出的迴旋鏢終於打中了自己):
不同的模組會導入來自不同註冊表的依賴項,或是因為缺乏 SemVer 導致導入同一註冊表依賴項的不同子版本。
這導致專案的體積膨脹(會增加 LSP 負擔),導入的依賴項之間缺乏引用相等性。
Deno 官方聲稱原來的套件註冊表 deno.land/x仍可繼續使用,
但考慮到官方的標準庫 std 在 deno.land/x 上已經停更,預期繼續在 deno.land/x 發佈套件是沒有意義的。
現在可以(像 Deno 1.28 添加的對 npm 模組的支援那樣)使用專用前綴 `=jsr:=`,簡化了 URL。
https://github.com/oakserver/oak
https://fresh.deno.dev/
Deno 官方於 2022 年推出的全棧 Web 框架,對標 Next.js。
不建議使用它,因為:
  • 幾乎沒有 React 函式庫為 Deno 支援做測試。
  • 內部使用的是 React 的輕量變體 Preact,這是一個沒有前途的技術路線。
Deno 可以透過 CDN 導入 JSDOM。
import { JSDOM } from 'https://esm.sh/jsdom@22.1.0'
https://github.com/b-fuze/deno-dom
該專案是 Rust 的 html5ever 套件的綁定。
使用 Deno FFI 的 SQLite。
優點:
  • 介面與 better-sqlite3 基本相同。
  • 高性能。
編譯為 WASM 的 SQLite。
優點:
  • 最小權限。
  • 跨平台。
缺點:
  • 受到 Deno 檔案系統 API 的限制。
  • 預設啟用的編譯選項非常少,很可能需要自己編譯。
自 Deno 1.21 開始,標準庫提供了相當多的測試功能,
這使得在大多數情況下不需要使用第三方函式庫就可以完成測試。
Deno 的這種技術選擇有效避免了 Node.js 測試的供應商綁定問題。
當前標準庫已經支援 BDD 風格、mock/stub、快照匹配、計時器模擬:
https://deno.land/std@0.181.0/testing
https://github.com/denoland/deno_std/issues/1779
Deno 提供一個內建的命令 `=deno bundle=` 用於將專案打包成一個腳本檔案。
Ryan Dahl 曾提議刪除此命令,但這個想法後來被撤回。
然而,在 v1.31 裡,該命令仍在沒有經過社群討論的情況下被列為棄用,官方手冊建議改用 esbuild。
在 v2.4,deno bundle 莫名其妙回歸,其底層使用 esbuild。
在 v2.5,支援以 HTML 檔案作為打包的入口點。
用 `=deno run=` 命令運行腳本時,會載入 TypeScript 類型檢查器,這會導致 Deno 進程使用更多的記憶體。
如果先透過 `=deno compile=` 編譯後再運行,腳本的記憶體用量會有明顯改善。