クライアント側の*.cljsとサーバー側の*.cljの間の一般的なコード、たとえばさまざまなデータ構造や一般的な操作を除外したいとしますか?それをするのは理にかなっていますか?
5 に答える
cljx Leiningenプラグインは、Clojureデータ視覚化ライブラリのClojure/ClojureScriptコード共有を処理するために特別に作成しました。非ホスト相互運用コードの95%は同じように見え、cljxでは、core.logicを使用して書き換えルールを指定することにより、最後の5%を自動的に書き換えることができます。ただし、ほとんどの場合、これは単純な記号の置換です。clojure.lang.IFn
たとえば、 ClojureはIFn
ClojureScriptにあります。
メタデータを使用して、特定のプラットフォーム用にコードが生成されるときに含まれる、または除外されるフォームに注釈を付けることもできます。
更新:clojure 1.7以降、Clojureリーダーの条件またはcljcを確認してください。私はcljcを使用して大成功を収め、サーバーとブラウザー間で多くのコードを非常に簡単に共有しました。
素晴らしい質問です!私は最近これについてもよく考えており、実験するためにいくつかのアプリを作成しました。
これがあなたが共有したいと思うかもしれないタイプのものとそれぞれの賛否両論の私のリストです:
- 私のクライアントcljsファイルのほとんどには、domを操作するコードが含まれています。したがって、それをサーバーと共有することは意味がありません
- サーバー側のもののほとんどは、ファイルシステムとデータベースの呼び出しを扱います。クライアントからデータベースを呼び出したいと思うかもしれません(特に、javascript呼び出しをサポートするno-sqlデータベースの1つを使用している場合)。しかし、それでも、クライアントからdbを呼び出すか、サーバーからdbを呼び出すかを選択する必要があると思います。したがって、dbコードを共有することもあまり意味がありません。
- 共有が間違いなく価値のある領域の1つは、クライアントとサーバー間でclojureデータ構造(リスト、ベクター、セットなどのネストされた組み合わせ)を共有して渡すことができることです。json(またはxml)に変換して戻す必要はありません。たとえば、domのしゃっくりスタイルの表現を前後に渡すことができると非常に便利です。gwtでは、gileadを使用してクライアントとサーバー間でモデルを共有しました。ただし、clojureでは、データ構造を渡すだけでよいため、gwtのようにクラス定義を共有する必要はありません。
- もっと実験する必要があると思う領域の1つは、クライアントとサーバー間で状態を共有することです。私の考えでは、いくつかの戦略があります。クライアントに状態を保存する(シングルページajaxタイプのアプリケーション)か、サーバーに状態を保存する(レガシーjspアプリのように)か、両方の組み合わせです。おそらく、状態(アトム、参照、エージェントなど)の更新を担当するコードを共有してから、2つの層の同期を維持するために、要求と応答を介して状態をやり取りできますか?これまでのところ、RESTのベストプラクティスを使用してサーバーを作成し、状態をクライアントに保存するだけで、かなりうまくいくようです。しかし、クライアントとサーバー間で状態を共有することにはどのようなメリットがあるのかがわかりました。
- 定数やプロパティを共有する必要はまだありませんが、これは再利用するのに適しているかもしれません。アプリのすべてのグローバル定数をcljファイルに入れてから、clojurescriptをコンパイルするたびにそれをcljsにコピーするスクリプトを作成すると、正常に機能し、コードの重複を少し節約できる可能性があります。
これらの考えがお役に立てば幸いです。私は他の人がこれまでに見つけたものに非常に興味があります。
Leiningen用の新しいlein-cljsbuildプラグインには、純粋なClojureコードを共有するためのサポートが組み込まれています。
サーバーの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"
}
)
)
この質問は以前からありますが、私はそれに遭遇したので、Clojureリーダーの条件cljc
文について言及したいと思いました。