精讀《Deno 1.0 你需要了解的》

黃子毅發表於2020-05-11

1 引言

Deno 是什麼?Deno 和 Node 有什麼關係?Deno 和我有什麼關係?

Deno 將於 2020-05-13 釋出 1.0,如果你還有上面的疑惑,可以和我一起通過Deno 1.0: What you need to know這篇文章一起了解 Deno 基礎知識。

希望你帶著疑問思考,未來 10 年看今天,會不會出現 Deno 官方生態壯大,完全替代 Node 進而影響到 Web 生態的局面呢?這個思考結果會影響到你未來職業發展,你需要學會自己思考,並對這個思考結果負責。

2 介紹 & 精讀

Deno 的作者是 Ryan Dahl,他是 Nodejs 背後的策劃者,曾經說過我對 Nodejs 感到遺憾的 10 件事。這也是為什麼新開一個坑的原因,但 Deno 並不定位為 Nodejs 的替代品,從整體功能來看,Deno 有更大的野心,據我的推測是想要取代現在陳舊的前後端開發模式,讓 Deno 一統前後端開發全流程。

Nodejs 是由 C++ 寫的,而 Deno 則是由 Rust 寫的,並選擇了Tokio這個非同步程式設計框架,並使用 V8 引擎解析 Javascript,並內建了對 Ts 的解析。

安裝

Deno 支援如下安裝方式:

Shell:

curl -fsSL https://deno.land/x/install/install.sh | sh

PowerShell:

iwr https://deno.land/x/install/install.ps1 -useb | iex

Homebrew:

brew install deno

Chocolatey:

choco install deno

指令碼執行方式為deno run,可以類比為node,但功能不同且支援遠端檔案,實際上遠端依賴是 Deno 的一大特色,也是有爭議的地方:

deno run https://deno.land/std/examples/welcome.ts

在 ts 檔案中允許用遠端指令碼載入資源,這個後面還會提到:

import { serve } from "https://deno.land/std@v0.42.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  req.respond({ body: "Hello World\n" });
}

安全性

Deno 是預設安全的,這體現在預設沒有環境、網路訪問許可權、檔案讀寫許可權、執行子程式的能力。所以如果直接執行一個依賴許可權的檔案會報錯:

deno run file-needing-to-run-a-subprocess.ts

# error: Uncaught PermissionDenied: access to run a subprocess, run again with the --allow-run flag

可以通過引數方式允許許可權的執行,有--allow-read--allow-write--allow-net等:

deno --allow-read=/etc

上面表示/etc資料夾下的檔案擁有檔案讀許可權。

除了直接加引數呼叫、Bash 指令碼呼叫外,還可以用 Make 執行,或者使用類似的drake啟動。

或者使用deno install命令,將指令碼轉化為一個快捷指令:

deno install --allow-net --allow-read -n serve https://deno.land/std/http/file_server.ts

-n表示--name,可以對這個指令碼進行重新命名,比如上面的例子中,serve命令就等同於deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts

標準庫

Deno 在標準庫上很有特點,對常用功能提供了官方版本,保證可用性與穩定性。原文中列出了一些與 Npm 三方庫的對比:

image.png

從這個點上來看,Deno 既做執行環境又做基礎生態,緩解了 Npm 生態下選擇困難症,這件事需要辯證來看:整合了官方包對功能確定的模組來說是很有必要的,而且提高了底層庫的穩定性;但 Deno 生態也有三方庫,而且本質上三方庫和官方庫在功能上沒有任何壁壘,因為實現程式碼都類似,唯一區別是誰能為其穩定性站臺,假設微軟和 Deno 同時出了基於 Npm 生態與 Deno 生態官方庫,都保證會持續維護,你更相信誰呢?官方是否有優勢要取決於官方自身的實力。

內建 Typescript

Deno 內建支援了 TS,因此不需要ts-node我們就可以用deno run test.ts執行 Typescript 檔案。值得注意的是,Deno 內部也是利用 Typescript 引擎解析為 Js 後交由 V8 引擎解析,因此本質上沒太大的變化,只是這樣 Deno 的生態會更規範。

由於內建了 TS 支援,自然也不需要寫tsconfig.json配置了,但你依然可以定製它:

deno run -c tsconfig.json [file-to-run.ts]

Deno 預設還開啟了 TS 嚴格模式,所以看到這裡,可以認為 Deno 是為了構建高質量理想庫而誕生的執行環境,基於已有的生態來做,但做了更多內建技術選型,這和 Facebook 的rome很像,但做的卻更徹底。

其實從實現上來看,我們基於 Javascript 生態也能寫出deno run test.ts這樣類似的引擎,只不過是由 JS 驅動執行,可能編譯還會選擇 Webpack,但 Deno 本身基於 Rust 實現,並重新實現了一套模組載入標準,可以說從更底層的方式重新解讀了 W3C 標準規範,以期望解決 Javascript 生態的各種痛點問題。

支援 Web 標準

Deno 還支援 W3C 標準規範,因此像fetchsetTimeout等 API 都可以被直接使用,如果你按照 Deno 支援的那幾個函式寫程式碼,可以保證在 Deno、Node、Web 三個平臺實現跨平臺執行。

雖然距離完全實現 W3C 所有標準規範還有一些路要走,但我們看到了 Deno 相容規範的決心。

ESModule

模組化是 Deno 的亮點,Deno 使用官方 ESModule 規範,但引用路徑必須加上字尾:

import * as log from "https://deno.land/std/log/mod.ts";
import { outputToConsole } from "./view.ts";

Deno 不需要申明依賴,程式碼的引用路徑就是依賴申明,會包括完整的路徑以及檔案字尾,也支援網路資源,可以擺脫 NPM 中心化的包管理模式,因為這個路徑可以是任何網路地址。

包管理

對於import * as log from "https://deno.land/std/log/mod.ts";這行程式碼,Deno 會下載到一個快取資料夾,使用者不會感知到這個資料夾與這個過程的存在,也就是說,Deno 環境中是沒有node_modules的。

也可以通過deno --reload的方式強制重新整理快取。

但這裡也要辯證的看待 “Deno 去中心化” 這件事,雖然引用了網路源,但會引發下面幾個問題:

  1. 實際上還存在一個 "node_modules",只是使用者看不到。
  2. 網路下載速度放到執行時,第一次啟動還是很慢。
  3. 普通模式下無 lock,必須配合deps.ts使用,這個後面會提到。

即使被打上 “中心化惡人” 的 npm 也有去中心化的一面,因為 npm 支援私有化部署,無論是速度還是穩定性都可以由公司自己掌控,從穩定性來說還是 npm 擁有壓倒性優勢。

三方庫

Deno 還有第三方庫生態,截止目前共有221 個三方庫 "%5B%5D(https://deno.land/x/)")。

由於 Deno 走網路資源,我們可以藉助Pika提供的 CDN 服務直接引用網路資源包:

import * as pkg from "https://cdn.pika.dev/preact@^10.3.0";

雖然這樣看上去很輕量,但對公司來說還是需要自建一個 “Pika” 保障穩定性,以及做全球 CDN 快取等的工作。

告別 package.json

npm 生態下包資訊存放在package.json,包含但不限於下面的內容:

  • 專案元資訊。
  • 專案依賴和版本號。
  • 依賴還進行分類,比如dependenciesdevDependencies甚至peerDependencies
  • 標記入口,mainmodule,還有 TS 用的typestypings,腳手架的bin等等。
  • npm scripts。

隨著標準的不斷更新,package.json資訊已經非常臃腫了。

對於 Deno 來說,則使用deps.ts集中管理依賴:

export { assert } from "https://deno.land/std@v0.39.0/testing/asserts.ts";
export { green, bold } from "https://deno.land/std@v0.39.0/fmt/colors.ts";

deps.ts就是一個普通檔案,只是將專案的依賴精確描述出來,這樣其他地方引用assert時,就可以這麼寫了:

// import { assert } from "https://deno.land/std@v0.39.0/testing/asserts.ts";
import { assert } from "./deps.ts";

如果需要鎖定依賴,可以通過deno --lock=lock.json方式申明。

deno doc

deno doc <filename>命令可以根據檔案按照 JS Doc 規則生成文件,同時也支援 TS 語法,比如下面這段程式碼:

/** Asynchronously fulfill a response with a file from the local file
 * system. */
export async function send(
  { request, response }: Context,
  path: string,
  options: SendOptions = { root: "" }
): Promise<string | undefined> {
  // ...
}

生成文件如下:

function send(_: Context, path: string, options: SendOptions): Promise<string | undefined>
Asynchronously fulfill a response with a file from the local file system.

deno 本身文件就是用這個命令生成的,可以訪問官方文件檢視使用效果。

內建工具鏈

前端 Javascript 工具鏈相當混亂,雖然業界已有 Umi 等框架做了開箱即用的封裝,但回到 Javascript 設計的初衷就是可以在瀏覽器直接使用的,包括瀏覽器對不依賴構建工具的模組化支援,註定了未來 Webpack 一定會被消滅。

Deno 通過內建一套工具鏈的方式解決這個問題,包括:

  • 測試:提供deno test命令與Deno.test()測試函式。
  • 格式化:提供vscode 外掛
  • 編譯:提供deno bundle命令。

不過值得注意的是,在最重要的編譯環節,deno bundle目前提供的能力是相對欠缺的,比如還不支援 Tree Shaking。

用 Rust 等語言提升構建效率是業界一直在嘗試的事,比如 @陳成 就基於esbuild做了@umijs/plugin-esbuild外掛用於提升 Umi 構建速度,但為了防止生產構建產物與 Webpack 預設規則不一致,僅使用了其壓縮(minifier)功能。

對 deno 來說也一樣,目前其實沒有任何證據表明 deno 的構建結果可以完美適配 webpack 環境,所以請勿認為 deno 釋出了 1.0 版本就等於可以在生產環境使用。

3 總結

正如原文結尾所說的,Deno 雖然將要釋出 1.0 版本,但仍不能完全替代 Nodejs,這背後的原因主要是歷史相容成本,也就是完整支援整個 Node 生態不只是設計的問題,更是一個體力活,需要一個個高地去攻克。

同樣 Deno 對 Web 的支援也讓人耳目一新,但仍不能放到生產環境使用,除了官方和三方生態還在逐漸完善外,deno bundle對 Tree Shaking 能力的缺失以及構建產物無法保證與現在的 Webpack 完全相同,這樣會導致對穩定性要求極高的大型應用遷移成本非常高。

最亮眼的改動是模組化部分,依賴完全去中心化從長遠來看是一個非常好的設計,只是基礎設施和生態要達到一個較為理想的水平。

最後,讓我們站在一個預言者角度思考一下 Deno 到底會不會火吧:

Deno 做的初心是做一個更好的 Node,但很不信,對於這種級別的生態底層工具來說,重新做一個並重新火起來的難度,不亞於重新做一個阿里巴巴並取代現在阿里的難度。也就是不同的時間點做同一件事,哪怕後者可以吸取教訓,大概率也無法複製以前成功的路線。

從 Deno 的功能來看,解決了 Node 很多痛點,其中就包括去中心化管理,有點雲開發的意思,但在 2020 年,基於 Nodejs 和 Webpack 的雲開發都搞出來了,說實話是沒有 Deno 什麼空間的。從功能上來看,開篇就說了 Deno 基於 V8 解析 Javascript,對於效能和功能都沒有革命性提升,從技術上作出突破也幾乎不可能了。

Deno 的思想確實比 Node 先進,但不能說比 Node 好十倍,則無法撼動 Node 的生態,即便是 Node 作者自己可能也不行。

然而我上面說的可能都是錯的。

相關文章