deno+mongo實戰踩坑記
阿新 • • 發佈:2020-05-21
自從 deno 1.0 釋出以來,有關 deno 的文章很多,大多數都是在討論怎麼安裝 deno 、deno 有哪些特點 、deno 和 node 有哪些異同、deno是不是 node 的替代品等。咱們今天不討論這些,畢竟 Talk is cheap. Show me the code! 親自體驗一把 deno 開發帶來的快感、用 deno 搞一個“企業級”應用:[deno-supermarket](https://github.com/zhanyuzhang/deno-supermarket),難道不香嗎?
## deno 常見的一些坑
在實戰之前,還是先來介紹幾個我在剛接觸 deno 時遇到的小坑。
### 許可權標誌符位置的問題
我們都知道, deno 預設是安全的,就是導致了預設情況下是不允許訪問網路、讀寫檔案等。比如有個名為 index.ts 的檔案內容如下:
```
import { serve } from "https://deno.land/[email protected]/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 run index.ts`, 會報錯:
```
error: Uncaught PermissionDenied: network access to "0.0.0.0:8000", run again with the --allow-net flag
```
所以我們很自然的就會在啟動命令的最後加上 `--allow-net` ,如下:
```
deno run index.ts --allow-net
```
但是,這樣仍然會報錯。查了資料才知道 ,`--allow-net` 、`--allow-read` 之類的標誌是不可以放到檔名後面的,必須緊跟在 `deno run` 後面,比如,如下才是正確的:
```
deno run --alow-net index.ts
```
為什麼調換了位置就不行呢? issue 上的回答是,如果 `--allow-net` 跟在檔名後面,是傳給 js 指令碼的,而不是傳給 deno 的。想了解更多的,可以看這個 [confused by order of cli option flags](https://github.com/denoland/deno/issues/5450#issuecomment-629643310)。反正,記住一點就行:許可權標誌一定要跟在 `deno run ` 後面!
因為我們前端同學大多數平時很少寫後臺,不太清楚安全的重要性,為了避免遇到各種許可權問題,我建議平時在寫一些練手專案時,直接用 `deno run -A` 來啟用全部的許可權。(這只是方便除錯,在生產環境中一定要慎用!)
### 不穩定的 API
因為實戰過程中使用了 mongodb , 所以需要引入 Deno 的第三方模組 [mongo](https://deno.land/x/[email protected]/mod.ts),然而在啟動專案會報錯:
```
error: TS2339 [ERROR]: Property 'openPlugin' does not exist on type 'typeof Deno'.
```
查了一下,發現是因為 `openPlugin` 這個方法目前還不穩定。預設情況下,deno 只會提供穩定的 api。如果需要開啟不穩定 api,可以新增 `--stable` 標誌。比如:
```
deno run -A --unstable index.ts
```
可能有人會問,`-A` 和 `--unstable` 的位置調換會不會有問題。這個親測過不會有問題。只要標誌符在檔名稱之前就行了。
還有個問題,到底哪些是穩定 API,哪些是不穩定 API 呢?其實 deno 官方文件已經幫我們分好類的了,入口地址分別是:
- [穩定的 api 文件](https://doc.deno.land/https/github.com/denoland/deno/releases/latest/download/lib.deno.d.ts)
- [不穩定的 api 文件](https://doc.deno.land/https/raw.githubusercontent.com/denoland/deno/master/cli/js/lib.deno.unstable.d.ts)
如果你懷疑 `--unstable` 的作用,可以使用下面的方法打印出 `Deno` 上的所有成員:
```
console.log(Object.keys(Deno).length)
```
使用 `deno run --unstable index.ts` 輸出的結果是 117,使用 `deno run index.ts` 輸出的結果是 88 。說明穩定的 api 有 88 個,不穩定的有 29 個。
## deno 的一些使用技巧
從 node 切換到 deno, 我們的開發思維也要隨之轉變。所以,我們再來看看 deno 的一些和 node 不一樣的開發技巧。
### 如何管理版本?
剛開始我也很疑惑:沒有了 `package.json`, 那怎麼控制各依賴的版本呀?比如,我們有10個檔案都依賴了 `[email protected]`, 那每個檔案都使用以下程式碼進行引入:
```
import { init, MongoClient } from 'https://deno.land/x/[email protected]/mod.ts'
```
可是有一天,我突然想把 0.6.0 升級到 0.7.0, 那怎麼辦呢?一個個檔案的進行替換容易漏掉,當然也可以全域性搜尋批量替換 。但是這種效率都不是很高。
官方給出的推薦做法是,使用 `deps.ts` 檔案來引入遠端檔案,並管理版本。(當然 ,檔名稱不一定叫做 `deps.ts`, 你也可以改成其他的名稱)。具體做法就是,把所有用到的遠端依賴,都在 `deps.ts` 中引入 ,並且通過 `Re-export` 手段匯出各依賴,然後其他檔案就可以從 `deps.ts` 中拿到所需要的依賴了。
回到剛才說10個檔案都依賴到 `mongo` 的問題,如果改成 `deps.ts` 檔案來統一管理是這樣的:
```
export * from 'https://deno.land/x/[email protected]/mod.ts'
```
然後那些需要用到 mongo 的檔案,不要直接從遠端引入,而是從 `deps.ts` 中引入,如下:
```
import { init, MongoClient } from '../pathTo/deps.ts';
```
如果需要升級的話,我們可以直接把 `deps.ts` 裡面的 mongo 地址中的 `0.6.0` 改成 `0.7.0` 就行了。
另外,有一點和 npm 類似的是,如果沒有指定版本號,即遠端地址中沒有指定版本,比如:
```
export * from 'https://deno.land/x/mongo/mod.ts'
```
就會預設安裝最新版的依賴。
### 如何查詢一些對我有用的 deno 庫?
使用 node ,可以到 npm 上查詢一些庫。deno 也有類似的平臺,目前分為兩種庫,一種是官方標準的,另外一種是第三方的。標準庫可以到這裡查詢:[Deno Standard Modules](https://deno.land/std/)。第三方庫可以到這裡查詢: [Deno Third Party Modules](https://deno.land/x/)
## 實戰: 使用 deno 開發一個具備增刪查改的商城系統
OK, 具備以上的知識點,現在可以實戰了。首先,需要保證你的電腦安裝了 deno 1.0 。另外,由於用到了 mongodb ,所以需要你的電腦也要安裝 mongodb。
### 介面
先來看看我們的商城的介面:
![](https://user-gold-cdn.xitu.io/2020/5/21/17236acf0d65ad5d?w=1187&h=574&f=png&s=47484)
麻雀雖小五臟俱全哈!具備新增商品、查詢商品、刪除商品、修改商品的功能。這是典型的 REST API 風格的系統 。
### 專案結構
然後再來看看專案結構:
![](https://user-gold-cdn.xitu.io/2020/5/21/17236ad3ea9efe6e?w=457&h=349&f=png&s=17228)
- .deno_plugins: 這是 mongo 模組所下載的動態連結庫,不用關注它。
- congig/db.ts: 這是連線 mongodb 的相關配置檔案。目前寫死的埠號是 27017 , 如果你的 mongodb 埠不是這個,可以在這個檔案裡面修改。
- controllers/goods.ts: 這是實現增刪查改的邏輯程式碼
- public/index.html: 這是前端靜態頁面,跟 deno 無關的,我們只需要用 deno 來服務該目錄就行。
- deps.ts: 用來管理遠端依賴庫,然後 Re-export 出去給其他檔案使用。
- server.ts 入口檔案,跟我們用 epress 或 koa 時的入口 檔案 app.js 類似。
### 依賴模組的選擇
因為該專案涉及到了前後端,如果使用 node 的話,一般會選擇 express 或 koa。同樣的,我們使用 deno 也要選擇對應的框架 ,不然的話,http服務以及路由跳轉等都不是那麼容易處理的。deno 上的這類框架,比較多人 star 的是 [oak](https://deno.land/x/oak) 和 [abc](https://deno.land/x/oak),這裡我們選擇使用 abc。
另外,因為使用 mongodb , 所以還需要引入 [mongo](https://deno.land/x/oak)
## 結束語
好啦,對於 deno 初體驗就寫到這啦, 具體的程式碼這裡不打算貼出來了,有興趣的可以前往 github 檢視:
- [deno-supermarket](https://github.com/zhanyuzhang/deno-supermarket)
有問題的可以一起交流學習哈~