2011-10-20 139 views
21

假設我想分解出我的客戶端* .cljs和我的服務器端* .clj之間的一些通用代碼,例如各種數據結構和常見操作,我可以這樣做嗎?這樣做有意義嗎?在Clojurescript/Clojure中服務器和客戶端之間的代碼共享

+2

它確實有意義,就像在GWT中一樣,您也可以在服務器和客戶端上共享Java代碼。聽到這個答案會很酷! –

+0

我現在唯一能想到的方法是將共享代碼放在服務器名稱空間和目錄結構中,然後在您的編譯代碼中添加行以將文件複製到客戶端源目錄,重命名爲* .cljs - 因爲clojurescript編譯器只會查找名爲.cljs的文件 – Hendekagon

回答

13

更新:截止clojure 1.7,檢查出Clojure reader conditionals or cljc。我已經非常成功地使用了cljc,可以非常輕鬆地在服務器和瀏覽器之間共享大量代碼。

偉大的問題!最近我一直在想這個問題,並且寫了幾個應用程序來進行實驗。

這裏是我的,你可能想要共享和每個優點/缺點是什麼類型的東西列表:

  • 我的大多數客戶cljs文件包含操縱DOM代碼。因此,與服務器分享任何內容都沒有意義。大多數服務器端的東西都會處理文件系統和數據庫調用。我想你可能想從客戶端調用數據庫(特別是如果你使用的是支持JavaScript調用的非sql數據庫之一)。但即使如此,我覺得你應該選擇從客戶端調用db或從服務器調用db,因此,共享db代碼也沒有多大意義。
  • 共享絕對有價值的一個領域是能夠在客戶端和服務器之間共享和傳遞clojure數據結構(列表,向量,集合等的嵌套組合)。無需轉換爲json(或xml)並返回。例如,能夠通過來回打嗝式的表示非常方便。在gwt中,我使用gilead來共享客戶端和服務器之間的模型。但是,在clojure中,您可以簡單地傳遞數據結構,因此實際上不需要像gwt那樣共享類定義。
  • 我覺得我需要嘗試的一個領域是在客戶端和服務器之間共享狀態。在我看來,有幾種策略:在客戶端(單頁ajax類型的應用程序)上存儲狀態或在服務器上存儲狀態(如傳統的jsp應用程序)或兩者的組合。也許代碼負責更新狀態(原子,參考,代理或其他)可以共享,然後狀態可以通過請求和響應來回傳遞,以保持兩層同步?到目前爲止,僅僅使用REST最佳實踐編寫服務器,然後將狀態存儲在客戶端上似乎工作得很好。但我可以看到如何在客戶端和服務器之間共享狀態。
  • 我還沒有需要共享常量和/或屬性,但這可能是很好的重用。如果將所有應用程序的全局常量放在clj文件中,然後在編譯clojurescript時編寫腳本將其複製到cljs,那麼應該可以正常工作,並且可能會節省一些代碼重複。

希望這些想法很有用,我對其他人迄今爲止發現的東西非常感興趣!

+0

優異點!我想通過讓我的服務器代碼通過將其一部分功能傳遞給編譯器來自動構建我的所有Clojurescript代碼來統一該過程。我還沒有閱讀編譯器代碼,但必須能夠直接提供它的表達式而不使用.cljs文件。 – Hendekagon

+0

關於datastruture共享,庫'fetch'似乎很整潔! https://github.com/ibdknox/fetch – leontalbot

2

寫的代碼快速位的我的服務器的Clojure代碼的一個子集到我clojurescript代碼複製,重命名爲.cljs大樓前:

(ns clj-cljs.build 
    (use 
    [clojure.java.io] 
) 
    (require 
    [cljs.closure :as cljsc] 
) 
) 

(defn list-files [path] 
(.listFiles (as-file path)) 
) 

(defn copy-file* [from to] 
;(println " coping " from " to " to) 
(make-parents to) 
(copy from to) 
)  

(defn rename [to-path common-path f] 
(str to-path common-path (.replaceAll (.getName f) ".clj" ".cljs")) 
) 

(defn clj-cljs* [files common-path to-path] 
    (doseq [i (filter #(.endsWith (.getName %) ".clj") files)] 
    (copy-file* i (file (rename to-path common-path i))) 
) 
    (doseq [i (filter #(.isDirectory %) files)] 
    (clj-cljs* (list-files i) (str common-path (.getName i) "/") to-path) 
) 
) 

(defn build [{:keys [common-path clj-path cljs-path js-path module-name]}] 
    (clj-cljs* (list-files (str clj-path common-path)) common-path cljs-path) 
    (cljsc/build 
    cljs-path 
    { 
    :output-dir js-path 
    :output-to (str js-path module-name ".js") 
    } 
) 
) 

(defn build-default [] 
    (build 
    { 
    :clj-path "/home/user/projects/example/code/src/main/clojure/" 
    :cljs-path "/home/user/projects/example/code/src/main/cljs/" 
    :js-path "/home/user/projects/example/code/public/js/cljs/" 
    :common-path "example/common/" ; the root of your common server-client code 
    :module-name "example" 
    } 
) 
) 
10

lein-cljsbuild插件Leiningen內置了support分享純粹的Clojure代碼。

+2

[cljsbuild](https://github.com/emezeske/lein-cljsbuild)的內置支持(crossovers)已被棄用,支持[cljx](https ://github.com/lynaghk/cljx),請參閱[this](http://stackoverflow.com/a/10369314/1209442)回答。 –

15

我寫了cljx Leiningen插件,專門爲Clojure數據可視化庫處理Clojure/ClojureScript代碼共享。 95%的非主機互操作代碼看起來相同,並且cljx允許您通過使用core.logic指定重寫規則自動重寫最後5%。大多數情況下,它只是簡單的符號替換;例如,Clojure中的clojure.lang.IFn僅僅是ClojureScript中的IFn

您還可以使用元數據來註釋要在特定平臺生成代碼時包含或排除的表單。

+0

看起來有用cheerz – Hendekagon

+1

[cljx](https://github.com/lynaghk/cljx)已被[cljsbuild](https://github.com/emezeske/lein-cljsbuild)用作代碼共享工具) –

相關問題