Skip to Content

Node.js終結者?青出於藍的Deno(二)

Node.js終結者?青出於藍的Deno(二)
Gordon Lau
2020-08-21

Deno 圖示

上回講到三個DenoNode.js優勝的地方,今次我們將會繼續介紹Deno這個初生之犢的優勢!

Node.js 使用NPM VS Deno 無中央資料庫

Node.js的模組(Module),主要是存在NPM之上,也許不少開發者不知道,其實NPM是一間公司,專為開發者提供存放私人模組(private module)的服務。而2020年3月時Github也收購了NPM,也就是代表現行大多數的Node.js 模組,都在Microsoft的控制之下。這無疑代表NPM本質也是一個中央資料庫,所以當間中NPM因技術問題而無法供開發者下載模組的話,Node.js開發者就會哀鴻遍野,因為NPM就是一個Single point of failure(單點故障)。

npmjs 圖示

Screen capture from npm.org

相較之下,Deno則完全沒有中央資料庫的概念,在Deno的設計之中。要安裝任何模組,有兩個不同的方法:

1. 使用URLimport模組,就像瀏覽器一樣,以下是一個由Opine程式庫的一段例子:

import {opine} from 'https://deno.land/x/opine@0.21.2/mod.ts';

const app = opine();

app.use((req,res)=>{
    res.send("Hello World");
});

app.listen(3000);

由這個例子可見,我們只需寫好URLDeno自動會從URL下載所需的程式碼,也會自動將程式碼存在快取(Cache),省卻下載時間。

2. 使用相對路徑(Relative Path)讀取其他本機檔案

import { sum } from './sum.ts'

sum(1,2);

因此,Deno的套件(Package)運作方式與瀏覽器很相似,沒有限制像必須使用NPM那樣的中央資料庫。

Node.js 使用node_modules VS Deno自動下載

Node_modules的問題很有名,每個Node.js 開發者都有這樣的經驗: 電腦磁碟空間快要耗盡了,原來是node_modules佔用了成GB的空間...網上還有這樣的meme:

node_modules 圖示

Source

Node_modules的質量比黑洞更甚:)!

Deno由於摒棄了中央資料庫的做法,變相只需要下載所需的模組,無須每次下載新專案,都要運行npm install。 那在何時才會開始自動下載呢?答案是在第一次運行的時候。

gordon➜ ~ deno run --allow-net --allow-read opine.ts
Download https://deno.land/x/opine@0.21.2/mod.ts
...
Download https://deno.land/x/evt@v1.8.7/tools/Deferred.ts
Download https://deno.land/x/evt@v1.8.7/lib/Evt.loosenType.ts
Download https://deno.land/x/evt@v1.8.7/tools/safeSetTimeout.ts
Download https://raw.githubusercontent.com/garronej/run_exclusive/v2.2.13/deno_dist/lib/runExclusive.ts
Check file:///home/gordon/opine.ts

以後,再運行這個檔案,就會直接使用已在快取之檔案,因此既有瀏覽器的簡便,也不會每次重新下載。

gordon➜ ~ deno run --allow-net --allow-read opine.ts
Check file:///home/gordon/opine.ts

剩餘兩個其實算是小問題,不過既然Ryan提到了,就一併解釋吧。

Node.js require無須副檔名 VS Deno import 必須副檔名

Node.js中的require是不須副檔名的,因此如果你想require一個名為myfile.js的檔案,你只需寫:

const myfile = require('./myfile');

這為Node.js平添了不必要的複雜性,因為myfile是甚麼呢?是myfile.js? 還是myfile.ts? 隨著Node.js的用途增多,這樣的「方便」,反而模糊了背後的意思。

index.js有JavaScript 入口的概念

這是完全無用的功能,因為在package.json就可以控制main是那個檔案了,因此這個功能沒有實際作用。

{
    ...
    "main":"index.js",
    ...
}

其他未提及的優勢

不過,筆者在用Deno小試牛刀之後,感到Deno還有其他明顯優勢,而Ryan並沒有提及。大概是因為2018年時發展尚早,未有這樣想法。

Deno能夠獨立執行

首先其中一個Deno的最大優勢,就是安裝Deno只是安裝了一個獨立的執行檔,也就是如果你去Deno的網站,運行以下的command:

# 如果你是用Mac/Linux
curl -fsSL https://deno.land/x/install/install.sh | sh

# 如果你是用 Windows PowerShell
iwr https://deno.land/x/install/install.ps1 -useb | iex

其實只是下載了一個二進位檔案(Binary file),也就是一個執行檔。在筆者的電腦,只是一個在~/.deno資料夾內的檔案。

gordon➜ ~ tree ~/.deno            
/home/gordon/.deno
└── bin
    └── deno

1 directory, 1 file

這個做法承襲自Golang(大概因為Ryan Dahl曾長時間運用Golang工作)而來,好處是使用deno,只有一個binary file的依賴,不會因為你有其他依賴未安裝,就無法使用deno,而且整個流程完全無須系統使用者權限(Administrator Right),實在令安裝過程簡單不少。

要運行Denocommand,只需打deno XXX。以下是deno help的輸出,

deno 1.3.0
A secure JavaScript and TypeScript runtime

...

USAGE:
    deno [OPTIONS] [SUBCOMMAND]

OPTIONS:
    -h, --help                     Prints help information
    -L, --log-level <log-level>    Set log level [possible values: debug, info]
    -q, --quiet                    Suppress diagnostic output
    -V, --version                  Prints version information

SUBCOMMANDS:
    bundle         Bundle module and dependencies into single file
    cache          Cache the dependencies
    completions    Generate shell completions
    doc            Show documentation for a module
    eval           Eval script
    fmt            Format source files
    help           Prints this message or the help of the given subcommand(s)
    info           Show info about cache or info related to source file
    install        Install script as an executable
    lint           Lint source files
    repl           Read Eval Print Loop
    run            Run a program given a filename or url to the module. Use '-' as a filename to read from stdin.
    test           Run tests
    types          Print runtime TypeScript declarations
    upgrade        Upgrade deno executable to given version

ENVIRONMENT VARIABLES:
    ...

由這裏可見,Deno有不少有用的subcommand,就等筆者介紹幾個特別令人感興趣的!

自帶測試工具

在寫Node.js的時候,開發者常常需要寫自動測試(Automated Tests),然而Node.js中有很多不同的測試程式庫: JestJasmineMochaChai都是其中的例子。因此要閱讀他人之Node.js專案時,如果別人正好用了你不常用的測試程式庫(Testing library),就變相要於不同專案使用不同之testing library,實在是不太方便。

Deno由於是後起之秀,今時今日自動測試早已是編程必要部份,因此原生支援testing,無需再思前想後要用那個library了。 以下是一個Deno測試的例子:

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";

Deno.test("1 + 1 should be 2", () => {
  assertEquals(1 + 1 , 2);
});

deno test直接運行,就會得到ok的結果。

gordon➜ ~ deno test test.ts 
Download https://deno.land/std/testing/asserts.ts
Warning Implicitly using latest version (0.65.0) for https://deno.land/std/testing/asserts.ts
Download https://deno.land/std@0.65.0/testing/asserts.ts
Download https://deno.land/std@0.65.0/fmt/colors.ts
Download https://deno.land/std@0.65.0/testing/diff.ts
Check file:///home/gordon/.deno.test.ts
running 1 tests
test 1 + 1 should be 2 ... ok (2ms)

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (3ms)

自帶Linter及formatter

Node.jsLinterFormatter都是需要額外安裝及設置,著名的prettier就是其中的好例子。Deno則早已包含在執行檔之內。

直接使用Linter:

gordon➜ ~ deno lint test.ts 

直接使用Formatter:

gordon➜ ~ deno fmt test.ts            
/home/gordon/test.ts

將這些本身是外部套件的功能加至原生支援(Native support),最大的好處在於開發者無須為選擇程式庫煩惱,而且程式碼的樣式也因而非常統一(Consistent), 非常方便維護。

自帶Bundler

還有一個筆者認為Deno非常強大的功能,就是deno的封裝(bundle)功能。現時要開發React應用時,Webpack是必不可少的一環,因為React當中大量使用了瀏覽器不支援的格式如JSXTypeScriptSCSS等。因此React開發一個必備的過程就是Build的步驟,也就是將程式碼由Node.js的世界﹐「封裝」(Bundle)成Browser的世界。

Webpack 網站banner很準確地概括了Bundler這個概念。

webpack 示範圖

Screen capture from webpack.js.org

Deno對此的解決方法如上面雷同,就是將封裝功能一併放到執行檔之中。 如果用deno bundle將剛才的test.ts封裝

gordon➜ ~ deno bundle test.ts  test-bundle.js 
Bundle file:///home/gordon/test.ts
Emit "test-bundle.js" (25.27 KB)

test-bundle.js的開頭大概是這樣:

/ Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.

// This is a specialised implementation of a System module loader.

"use strict";

// @ts-nocheck
/* eslint-disable */
let System, __instantiate;
(() => {
  const r = new Map();

  System = {
    register(id, d, f) {
      r.set(id, { d, f, exp: {} });
    },
  };
  async function dI(mid, src) {
    let id = mid.replace(/\.\w+$/i, "");
    if (id.includes("./")) {
      const [o, ...ia] = id.split("/").reverse(),
        [, ...sa] = src.split("/").reverse(),
        oa = [o];
      let s = 0,
        i;
    ...
    // 以下省略

這個檔案可以直接用deno.run運行,裏面有齊了整個test.ts的依賴,不過由於有Deno的依賴,這個檔案不能在瀏覽器內運行。

Deno的弱點

談了那麼多Deno的好處,那Deno相比起Node.js,有明顯的弱點嗎? 筆者想到兩點比較明顯的弱點,都與Deno 的兼容性有關的。

與現有Node.js專案不兼容

Deno完全摒棄package.jsonnode_modules的做法,因此你不可能直接使用deno去運行現有的Node.js專案,因為連import的運作模式,也不盡相同。 因此除非你是重新開始一個新專案,也是所謂的Green Field Project,否則你不能在一個專案中漸進使用Deno

筆者認為這是Deno成為主流的最大障礙,因為對大多數公司而言,大量由Node.js所寫成的程式碼有很大的商業價值,因此要由零開始乃是不切實際。我們可以由KotlinScala的發展觀察到這個現象,ScalaKotlin都是以Better Java的姿態面世,縱然兩者都是JVM LanguagesScala基本上與Java不相容,Java專案要變成Scala專案也很不容易,因此Scala一直都只是在Big Data方面得到長足發展。Kotlin則相反,設計之初就以漸進使用為賣點,更可以在一個Java專案只是少數幾個檔案使用Kotlin,結果今日的發展大家都知道,Kotlin因其兼容性,真正達到了Better Java的特點。 所以筆者認為Deno要得到更大成功,能夠漸進在Node.js中使用,是至為必要的。

Deno無法得益於Node.js龐大的套件庫

另外,DenoNPM本身不相容,因此Deno開發者無法在NPM上直接使用已存在的NPM套件。這也是對Deno的發展的另一障礙。因為NPM packages坐擁世上最多的套件數目,遠遠拋離其他程式語言的套件管理員,無法從此得益,實屬可惜。

Node.js 與其他語言的 module 數量

Screen capture from modulecounts.com

由網站Module CountsNPM有超過125萬個套件,如果Deno能夠運用套件,絕大多數的功能就已告齊備。

結語

返回文章的題目,Deno能否取代Node.js成為JavaScript的主要開發環境呢?筆者認為短期兩至三年內可能性都非常低,但如果未來Deno能夠解決筆者所言的兩個局限性,筆者也會躍躍欲試,將手頭上的Node.js專案加入Deno了。

Comments

Read More

到底React Hooks 有何特別?

到底React Hooks 有何特別?

到底React Hooks 有何特別?
Gordon Lau
2018-11-27

新近推出的React 16.7包括一個很有趣的功能,名字叫做React Hooks。看到這個名字,很多人會下意識認為是在講componentDidMount, componentDidUpdate等方法。但其實這些方法的正名是 React Lifecycle Method, 推出React Hooks是為了方便開發者多用functional component,但仍然能夠使用state及 props等重要功能。


Dart vs JavaScript vs TypeScript

Dart vs JavaScript vs TypeScript

Dart vs JavaScript vs TypeScript
Gordon Lau
2019-02-17

隨著Flutter受到開發者的重視,Google於2011年推出的Dart又重新進入大家關注的視野之內,不過除了Flutter以外,其實Google的開發者早在2016年也推出過Angular Dart,讓開發者以Dart開發網站應用,不過由於Angular Dart對比TypeScript版Angular文本長期不足,因此沒有引起太多關注。Google推出Flutter,可以說為大家對Dart的信心注入了一劑强心針,大家又重新開始關注這個已有8年歷史的程式語言。 本文想介紹的是,就是到底Dart有何特色?與JavaScript比較,又有何優劣?由於TypeScript開始於前端日漸盛行,我們亦可以趁機比較一下三種語言的異同。


SQL首部曲:NoSQL? No! SQL!

SQL首部曲:NoSQL? No! SQL!

SQL首部曲:NoSQL? No! SQL!
Gordon Lau
2019-10-08

由本篇開始,接連四篇都是與SQL有關的文章,會想寫SQL的原因,是因為SQL在現今軟件開發及數據科學佔有舉足輕重之地位,卻總是在背後默默無名,從未見得到像其他新興技術之關注,有見及此,筆者決定介紹SQL之特點,順便破除一些對使用SQL上常有的誤解。


Node.js終結者?青出於藍的Deno(一)

Node.js終結者?青出於藍的Deno(一)

Node.js終結者?青出於藍的Deno(一)
Gordon Lau
2020-08-06

有編程經驗的人,都一定會聽聞過Node.js,Node.js基于Chrome的V8引擎開發,本身能夠運行JavaScript,在前端開發(Frontend Development)、後端開發(Backend Development)、Android及iOS開發(Android & iOS Development),都有Node.js的蹤影,更帶起全JS開發的潮流,也就是大家常常在Youtube上看到的MEAN Stack(Mongodb,Express,Angular,Node.js),也是以Node.js為中心發展起來的。


Request Syllabus
Please check your email after submissions.
hello@tecky.iot.me/tecky_hub+852 9725 6400
green_org
Caring Company 2019-2022
TQUK Approved Centre
aws_partner
Reimagine Education Challenge Award
B Corp™ Certified B Corporation
Web Content Accessibility Guidelines (WCAG) 2.1 at Level AA
Web Accessibility Gold Award
© 2024 Tecky Academy Limited