跳至主內容

Deno終於有NPM Support!

Deno終於有NPM Support!
Gordon Lau 劉偉中
2022-12-16

筆者兩年前連續寫了兩篇Node.js終結者,分別介紹了Deno 的設計理念,以及Deno比Node.js優勝的地方。 筆者亦在第二篇文中寫了Deno的弱點,主要在於DenoNode.js龐大的NPM套件庫並不兼容,令現有的Node.js專案難以 轉會。而在11月13日推出的Deno版本1.28,就正正是推出了廣泛之NPM Support! 馬上支援超過130萬的npm套件。

deno_blog.png

在這篇文章之中,筆者會嘗試用Deno,加上常見的npm套件expresspg套件去建立一個簡單Restful應用。

安裝

要安裝Deno是非常簡單,只需要從官方網站直接運行安裝command。

MacLinux的安裝方法如下:

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

Windows的安裝方法如下:

irm https://deno.land/install.ps1 | iex

安裝deno 之後,就可以直接運行deno,得到以下結果。

$ deno
Deno 1.28.3
exit using ctrl+d, ctrl+c, or close()
> 

deno本身已支援TypeScriptJavaScript,無須再安裝任何其他軟件。

Express 伺服器

要完成一個簡單expressRestful應用,Deno project 最終只需要幾個檔案。

project_structure.png

整個專案簡潔得多,沒有package.json也沒有tsconfig.json!

index.ts

先由index.ts開始,Deno現在可以用npm:XXX的寫法直接使用 npm套件。

import  express  from "npm:express";
import { Express} from 'npm:@types/express'


const app: Express = express()

app.get('/',(req, res)=>{
    res.json({"msg":"Hello World!"})
})

app.listen(8080)

由這段Code可見,在Deno中使用expressnode.js中並不相同,因為Node.js使用CommonJS module,而Deno本身就運用較新的標準ES module。 而且Deno並不會將DefinitelyTyped的type@types/express 與本來的express連上關係,變相要開發者自己處理。

要運行這個index.ts,只須直接以deno run

$ deno run index.ts
⚠️  ┌ Deno requests read access to <CWD>.
   ├ Requested by `Deno.cwd()` API
   ├ Run again with --allow-read to bypass this prompt.
   └ Allow? [y/n] (y = yes, allow; n = no, deny) > 

發生何事呢?因為Deno本身的沙盒式設計,我們需要逐個權限設定。

$ deno run --allow-net --allow-read --allow-env index.ts

不同的flag的意思代表如下,

  • --allow-net 代表容許index.ts存取網絡
  • --allow-read 代表容許index.ts讀取本機檔案
  • --allow-env 代表容許index.ts存取環境變數

然後就成功運行了一個express 伺服器。

hello_world.png

deps.ts

不過,根據通常Deno的開發慣例,我們並不會將所有dependencies都放在index.ts。 而是放在一個名為deps.ts的檔案,這個檔案與package.json的作用有些類似,但卻只是一個普通的Typescript file,而非像package.json一樣是每個npm 專案的必備檔案。

我們可以將兩句import抽出來,再放到deps.ts

export { default as express } from 'npm:express'
export type { Request, Response, Express } from 'npm:@types/express'

index.ts,就只需直接從deps.ts import 就可以了。

import { express, Express } from "./deps.ts";

const app: Express = express()

app.get('/',(req, res)=>{
    res.json({"msg":"Hello World!"})
})

app.listen(8080)

有需要的話,在deps.ts亦可以直接加上版本,容易控制套件版本。

export { default as express } from 'npm:express@^4.17'
export type { Request, Response, Express } from 'npm:@types/express@^4.17.15'

存取資料庫

為了簡單起見,我們會用非常受歡迎的PostgreSQL資料庫。我們亦可以運用常用的npm 套件pgdotenv

export { default as express } from 'npm:express'

export type { Request, Response, Express } from 'npm:@types/express'

export { default as pg } from 'npm:pg'

export type {Client } from 'npm:@types/pg'

export { default as dotenv } from 'npm:dotenv'

這種寫法稱為Re-export,將由npm套件export出來的值再重新命名。

假設我們有一個.env檔案,裏面有連接資料庫需要的usernamepassword

POSTGRES_DB=deno-test
POSTGRES_USER=tecky
POSTGRES_PASSWORD=tecky

然後就是平常的pg設定寫法。

import { Client, Express, express, pg, dotenv } from "./deps.ts";

dotenv.config()

const app:Express = express()
const config = {
    database: Deno.env.get('POSTGRES_DB'),
    user: Deno.env.get('POSTGRES_USER'),
    password: Deno.env.get('POSTGRES_PASSWORD')
}
const client: Client = new pg.Client(config)

await client.connect()

Deno本身支援top level await,因此直接運用await client.connect()就可以連接資料庫。 當有了連接資料庫的client,剩餘就只是簡單的express Restful應用程式碼。

app.use(express.json())

app.get('/todos', async(req, res)=>{
    const data = (await client.query("SELECT * from todos")).rows
    res.json(data)
})

app.post('/todos',async (req ,res)=>{
    const content = req.body.content
    await client.query("INSERT INTO todos (content) values ($1)",[content])
    res.json("Hello World")
})

app.listen(8080, ()=>{
    console.log("Listening at http://localhost:8080")
})

再用deno run重新運行,不論GET /todosPOST /todos都可以成功運行了!

todos.png

這段程式碼,已經開源在Github Deno NPM Example 之上

局限性

你可能讀到這裏,覺得Deno實在太方便了! 既不需要用到npm,又不需要用到package.jsontsconfig.json,是否想馬上轉會呢? 筆者在此潑個小小的冷水,Deno在套件上確實還是有一些局限:

例如Deno在資料庫存取上的套件比較欠缺,欠缺像knex一樣可以跨資料庫的Database Migration套件庫,運用knex的npm套件庫是一個選擇,但現在時間尚早,網上資源亦比較欠奉。 大家亦可以選擇運用一些支援Deno的套件,例如Postgres.jsnessie,但就可能需要找尋一下了。

總結

Deno 1.28加入了npm support,確實令Deno的實用性大大增強,可以活用有數百萬套件的npm套件庫。 要將現有Node.js專案,改為Deno專案,難度亦已降低很多。實際是想轉會的Node.js用戶之喜訊。 展望未來,運用Deno的開發者會以npm套件為主,deno本身的套件為輔,才是最有效的做法。

留言

閱讀更多

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為中心發展起來的。


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

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

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

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


索取課程大綱
提交後, 請檢查你的電郵
hello@tecky.iot.me/TeckyAcademy
+852 9725 6400+44 07570 549084+1 (647) 556-3084
商界展關懷 2019-2022
英國頒證機構 TQUK 認可中心
aws_partner
薯片叔叔共創社 重塑教育挑戰大獎
© 2023 Tecky Academy Limited