Clojurescript / Clojure中服务器和客户端之间的代码共享

时间:2011-10-20 01:13:31

标签: clojure clojurescript

说我想在我的客户端* .cljs和我的服务器端* .clj之间分解一些常用代码,例如:各种数据结构和常见操作,我可以这样做吗?这样做有意义吗?

5 个答案:

答案 0 :(得分:15)

我专门编写了cljx Leiningen插件来处理Clojure数据可视化库的Clojure / ClojureScript代码共享。 95%的非主机间互操作代码看起来相同,而cljx允许您通过使用core.logic指定重写规则来自动重写最后5%。 但大多数时候,这是简单的符号替换;例如,Clojure中的clojure.lang.IFn只是ClojureScript中的IFn

在为特定平台生成代码时,您还可以使用元数据来注释要包含或排除的表单。

答案 1 :(得分:12)

更新:截至clojure 1.7,请查看Clojure reader conditionals or cljc。我已经非常成功地使用cljc在服务器和浏览器之间共享很多代码。

好问题!我最近一直在考虑这个问题,并编写了一些应用程序来进行实验。

以下列出了您可能希望分享的内容以及每种内容的优缺点:

  • 我的大多数客户端cljs文件都包含操作dom的代码。因此,与服务器
  • 分享任何内容是没有意义的
  • 大多数服务器端处理文件系统和数据库调用。我想你可能想从客户端调用数据库(特别是如果你正在使用一个支持javascript调用的no-sql db)。但是,即便如此,我觉得你应该选择从客户端调用db或从服务器调用db,因此,共享db代码也没有多大意义。
  • 共享绝对有价值的一个领域是能够在客户端和服务器之间共享和传递clojure数据结构(列表,向量,集合等的嵌套组合)。无需转换为json(或xml)并返回。例如,能够来回传递dom的打嗝式表示非常方便。在gwt中,我使用gilead在客户端和服务器之间共享模型。但是,在clojure中,您可以简单地传递数据结构,因此实际上不需要像gwt那样共享类定义。
  • 我觉得我需要尝试更多的一个方面是在客户端和服务器之间共享状态。在我看来,有一些策略:在客户端上存储状态(单页ajax类型应用程序)或在服务器上存储状态(如旧版jsp应用程序)或两者的组合。也许负责更新状态的代码(原子,引用,代理或其他)可以共享,然后状态可以在请求和响应之间来回传递以保持两个层同步?到目前为止,简单地使用REST最佳实践编写服务器,然后将状态存储在客户端上似乎工作得很好。但我可以看到在客户端和服务器之间共享状态可能会有什么好处。
  • 我还不需要共享常量和/或属性,但这可能是重用的好方法。如果你将所有应用程序的全局常量放在clj文件中,然后编写一个脚本,在编译clojurescript时将其复制到cljs,那应该可以正常工作,并且可能会节省一些代码重复。

希望这些想法很有用,我对其他人到目前为止所发现的内容非常感兴趣!

答案 2 :(得分:10)

Leiningen的新lein-cljsbuild插件内置support,用于共享纯Clojure代码。

答案 3 :(得分: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"
   }
  )
)

答案 4 :(得分:0)

这个问题早于cljc,但由于我偶然发现它,我想我会提到Clojure reader conditionals