讓 Clojurescript 使用 node.js 的外部函式庫,以 tty.js 為例

(更新於 )

使用 ClojureScript 來寫 node.js 程式 一文當中,我們提到了可以用 ClojureScript 來寫 node.js 的程式,可是如果要引用 node.js 的外部函式,比 如說 tty.js 時,要怎麼辦呢?

tty.js 是一個可以讓你在瀏覽器下使用終端機的一個很酷的 node.js 程式,雖 然他是獨立的程式,但是也可以當作函式庫引用。

本篇文章將描述如何在 ClojureScript 裏面呼叫 tty.js 的函式來建立我們的 node.js 程式。

建立新的專案

我們首先先來建立一個新的開發環境,就叫他為 cljs-tty 好了

lein new cljs-tty

加入 cljsbuild 到你的專案

接下來,編輯 project.clj 將他變成下面這樣,注意到在這篇範例中,我 們還是使用 src 作為 ClojureScript 程式的資料夾。

如果你不知道為什麼 project.clj 要這樣設定,請參考我之前寫的文章: 使用 ClojureScript 來寫 node.js 程式

(defproject cljs-tty "0.1.0-SNAPSHOT"
  :description "ClojureScript with tty.js example"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :cljsbuild {
              :builds [{
                        :source-paths ["src"]
                        :compiler {
                                   :target :nodejs
                                   :optimizations :simple
                                   :pretty-print true}}]}
  :dependencies [[org.clojure/clojure "1.5.1"]])

此外,這邊 Google Closure Compiler 的最佳化設定設定成為 Simple , 這是因為 tty.js 是外部依賴,我們並沒有將他一起編譯進我們的程式裏面,若 使用 Advanced 的最佳化格式,則會使我們的變數或是函式名稱和 tty.js 的 不同,導致執行程式時出錯。

使用 npm 來加入 node.js 套件

畢竟我們是要透過 ClojureScript 來呼叫 node.js 的函式庫,自然需要使用 npm 來安裝需要的套件,因此你必須先在專案的頂層目錄加上 package.json , 並加入以下資訊 (或是使用 npm init 來建立 package.json)

{
    "name" : "cljs-tty",
    "version" : "0.0.1",
    "dependencies" : {
        "tty.js" : "0.2.10"
    }
}

我們在 package.json 裏面加入了 tty.js 作為我們 node.js 程式的依賴,完 成後使用

npm install

來下載 tty.js 程式,他會被放到 nodemodules 下。

改程式碼的時間到了

在我們的主程式 core.cljs 裏面,要添加下面的 ClojureScript 程式碼,你 可以將他和左邊的 javascript 程式碼來對照看看 (tty.js 提供的範例程式), 我們將在後面說明這些程式碼的用途。

javascript

var tty = require('tty.js');

var app = tty.createServer({
  shell: 'bash',
  users: {
    foo: 'bar'
  },
  port: 8080
});

app.get('/foo', function(req, res, next) {
  res.send('bar');
});

app.listen();

ClojureScript

(ns cljs-hello.core
  (:require [cljs.nodejs :as nodejs]))

(def tty (nodejs/require "tty.js"))

(def app (.createServer tty
   (clj->js {:shell "bash"
             :users { :foo "bar" }
             :port 8080 })
   ))

(.get app "/foo" (fn [req, res, next] (.send res "bar")))

(defn -main [& args] (.listen app))

(set! *main-cli-fn* -main)

在我們的 ClojureScript 的第一步,除了宣告命名空間 (namespace) 外,我們 也需要載入 node-clojurescript 的函式庫,你不需要安裝他,因為這步驟 cljsbuild 已經幫你做好了。

(ns cljs-hello.core
  (:require [cljs.nodejs :as nodejs]))

我們載入 cljs.nodejs 函式,並將他的名稱改為 nodejs,這樣比如我們要使 用 cljs.nodejs 庫的 foo 函式,則使用 nodejs/foo 就好了。

接下來談談外部函式庫的載入,在 javascript 中我們是這樣做

var tty = require('tty.js');

使用 require 將 tty.js 載入後,綁到變數 tty 下,而 ClojureScript 的作 法則是這樣

(def tty (nodejs/require "tty.js"))

是不是和 javascript 長的很像? (註:以歷史的角度來看,目前所有高階語 言都擁有 Lisp 語言的影子)

接下來,當使用 tty 來建立一個 server 的時候,需要傳送 JSON 資料給他, 這個 JSON 資料會指派了使用的 shell,以及登入這個網頁伺服器用的帳號和密 碼,這是為了安全性所做的設定,此外亦可以設定使用的 Port,以下是這部份 的 javascript 程式。

var app = tty.createServer({
    shell: 'bash',
    users: {
        foo: 'bar'
    },
    port: 8080
});

在這邊我們設定使用 bash 作為我們的 shell,並且設定帳號: foo ,密碼: bar ,Port: 8080

由於他是直接傳送 JSON 資料過去,那在 ClojureScript 裏面要怎樣做呢?在 ClojureScript 裏面,你可以使用 clj->js 來將 map 格式的資料轉換成 JSON 格式。

(def app (.createServer
          tty
          (clj->js { :shell "bash" :users { :foo "bar" } :port 8080 })))

在 tty.js 提供的範例中,有以下這樣的程式

app.get('/foo', function(req, res, next) {
    res.send('bar');
});

這段程式其實不是必要的,他提供你可以登入到 /foo 下面,你會看到有一個 bar 訊息,相對應的,在 ClojureScript 裏面我們可以這樣寫

(.get app "/foo" (fn [req, res, next] (.send res "bar")))

在 javascript 中使用 function 來作為匿名函式的宣告,而在 ClojureScript 中我們 使用 fn 來作為匿名函式的宣告。

最後一部份就是整個程式的進入點了,我們在 ClojureScript 寫了以下程式

(defn -main [& args] (.listen app))

(set! *main-cli-fn* -main)

若你無法理解為什麼要這樣寫,請參考 使用 ClojureScript 來寫 node.js 程式 一文。

編譯我們的程式

使用 ClojureScript 來寫 node.js 程式 一文說過要怎樣編譯我們的 ClojureScript 程式,你可以使用

lein cljsbuild once

來產生 target/cljsbuild-main.js 程式,若你是在開發過程中,也可以使用

lein cljsbuild auto

他會在你每次儲存你的 ClojureScript 程式碼時,幫你進行編譯的動作。

執行程式看看結果

我們可以用以下命令來執行我們的程式

node target/cljsbuild-main.js

執行完後使用瀏覽器瀏覽 http://localhost:8080 這個 位址,並輸入帳號: foo 密碼: bar , 多打開幾個終端機,執行 htop、vim 等程式,你就可以看到如下圖的狀況。

img

參考連結

[1] GitHub - tty.js

[2] GitHub - node-clojurecript