上周某個普通的一天,deno 1.0發佈了。於是利用業餘時間寫了一個服務端的程式。 GIT:https://github.com/shinku/deno-demokoa 之於 node,相當於oak就之於deno了。 雖然是奇怪的設定,不過僅僅換了個字母順序而已,koa 和 oak 就是一個同父異母 ...
上周某個普通的一天,deno 1.0發佈了。於是利用業餘時間寫了一個服務端的程式。 GIT:https://github.com/shinku/deno-demokoa 之於 node,相當於oak就之於deno了。 雖然是奇怪的設定,不過僅僅換了個字母順序而已,koa 和 oak 就是一個同父異母的雙胞胎呀。
router .get("/", (context) => { context.response.body = "Hello world!"; })
以及
app.use((ctx) => {// Will throw a 500 on every request. ctx.throw(500);});
koa 與oak有著幾乎一致的kpi,所以對於有node經驗的開發人員來說,是非常友好的。 我嘗試著用deno 寫了一個靜態資源伺服器。koa中有個koa-static可以直接使用,但是oak中還缺乏這個包,所以即便他們長得相似,積累上的差距還是挺多的。 想到這裡,萬一後期阿裡的egg換了deno運行時,會不會改名叫:geg 我索性利用了oak 的洋蔥模型的原理,簡單寫了一個static的oak中間件。 定義一個中間件的基本方式:
export default async (context:any,next:Function)=>{//塞點內容進來}
根據文件請求路徑去伺服器的伺服器中訪問文件:
const data = Deno.readFileSync(_static+filename);
作為返回主體,設置response的body。
let {response,request} = context;response.body = data;
然後我再寫了一個緩存的模塊,將請求資源的路徑和data 做個映射,確保在下次訪問的時候直接去獲取記憶體中的數據,減少再次讀取文件造成的資源開銷。 根據文件名分別處理了一下返回的headers的content-type的內容。 以上大致這些內容,我把這個文件放在了並起名為static.ts的文件中
app/utils/static.ts
於是,結合oak的中間件邏輯,監聽8000埠(也是koa的中間件邏輯)。
import { Application } from "https://deno.land/x/oak/mod.ts";import _static from "./utils/static.ts";const app = new Application();app.use(_static);console.log('start at point :8000');app.listen({ port: 8000 });
運行了deno的啟動命令:
deno run --allow-net --allow-read index.ts
項目順利啟動了。當我將文件放在工程裡面指定的目錄下,用特定的url格式去訪問他們的時候,他們如約的出現在了我的瀏覽器中。 第一次編譯的時候,會從denoland上下載ts的代碼資源,拉到本地,再在deno的運行時中編譯成js文件,提交給V8引擎做最後的編譯。所以第一次編譯會比較耗時,後期的編譯會比較省時間。 TS的編譯過程在整個服務的啟動之前,也就是說實際上運行過程中完全不用考慮ts的編譯問題。所以相比較nodejs,deno的運行效率和node 應該是一模一樣的。 目前沒有找到一個類似於pm2 或者supervisor 的進程管理的工具,所以我每次修改service 的代碼之後,得反覆使用ctrl+C的方式退出當前進程,涉及到埠占用,還得強行運行一次“pkill -9 deno”暴力的關掉deno對於埠的占用,之後再起一次deno的啟動命令。整個過程對我身心造成了不小的傷害。
const run = ()=>{ return Deno.run({ cmd: ["deno", "run","--allow-net","--allow-read","index.ts"], cwd:"app", }); }let _porcess = run();const watcher = Deno.watchFs("./app");for await (const event of watcher) { console.log('kill proceess'); _porcess.close(); console.log('restart'); _porcess= run();}
於是我將deno的啟動項的代碼由
deno run --allow-net --allow-read index.ts
替換成了
deno run --allow-net --allow-read --allow-run launch.ts
這樣我再改動app目錄下的代碼,並需要驗證效果的時候就,就會自動重新編譯啦。 涉及到的三個allow相關的tag的意義:
- --allow-net :允許從遠程下載資源,deno 運行時需要拉取遠程模塊的時候必須
- --allow-read:允許調用deno的文件讀取的相關許可權,deno應用需要訪問本地資源的時候必須
- --allow-run:允許啟用deno.run實現本地命令行調用,deno 中用到各項命令行操作的時候必須
import { Application } from "https://deno.land/x/oak/mod.ts";
這種代碼讓我對於包管理的方式缺乏安全感,不像 rust開發一樣有個cargo.toml 可以統一管理所以調用的第三方包。於是我將第三方包都寫在了lib下一個專門的ts去管理
import * as oak from 'https://deno.land/x/oak/mod.ts';export { oak}
這個文件也可以作為後續管理其他所有第三方包的入口,其他業務模塊需要用到這些第三方模塊的時候都通過import 這個本地的入口,多少給了我一些安全感。 作為學不動的一方,以下是我在使用deno後的一些感想。。。。
- 沒有了node_modules的存在,整個項目代碼結構看起來舒服不少。
- typescript 的全方位支持也讓開發過程的體驗有了質的飛躍,這代表著我們不用再去顧及typescript 的編譯過程,和雜七雜八的webpack的配置項和插件;
- 沒有非常有效的包管理工具,使得使用過程中對第三方模塊的使用無法直視,缺少安全感,於是要嘗試自己去寫一些模塊管理這些模塊;
- deno最終是由rust 編寫,但是最後並沒有沿用cargo的那一套非常友好又標準的包管理機制和運行時監聽工具,所以目前調試過程還是比較繁瑣;
- 目前還沒有一個有效的類似於pm2的進程管理工具,意味著如果我要上一個deno的項目,我得先在伺服器上裝個docker?
- 官方在標準庫上還缺乏更多的佈局,所以會覺得相對於普通開發者來說現在,還不適合使用deno開發生產業務