Frage

Angenommen, ich wollte einen gemeinsamen Code zwischen meinen clientseitigen * .cljs und meinen serverseitigen * .clj herausfiltern, z.verschiedene Datenstrukturen und gemeinsame Operationen, kann ich das tun?Ist es sinnvoll, dies zu tun?

War es hilfreich?

Lösung

Update: Ab Clojure 1.7 lesen Sie Clojure Reader Conditionals oder cljc . Ich habe cljc mit großem Erfolg verwendet, um sehr einfach viel Code zwischen Server und Browser zu teilen.

Gute Frage! Ich habe in letzter Zeit auch viel darüber nachgedacht und ein paar Apps zum Experimentieren geschrieben.

Hier ist meine Liste der Arten von Dingen, die Sie teilen möchten, und Vor- / Nachteile der einzelnen:

  • Die meisten meiner Client-CLJS-Dateien enthalten Code, der den Dom manipuliert. Es wäre also nicht sinnvoll, irgendetwas davon mit dem Server zu teilen
  • Die meisten serverseitigen Dinge befassen sich mit Dateisystem- und Datenbankaufrufen. Ich nehme an, Sie möchten die Datenbank möglicherweise vom Client aus aufrufen (insbesondere, wenn Sie eine der No-SQL-Datenbanken verwenden, die Javascript-Aufrufe unterstützen). Aber selbst dann sollten Sie entweder db vom Client oder db vom Server aufrufen, und daher ist es auch nicht sinnvoll, den db-Code gemeinsam zu nutzen.
  • Ein Bereich, in dem das Teilen definitiv wertvoll ist, ist das Teilen und Übergeben von Clojure-Datenstrukturen (verschachtelte Kombinationen von Listen, Vektoren, Mengen usw.) zwischen Client und Server. Keine Konvertierung in json (oder xml) und zurück. Zum Beispiel ist es sehr praktisch, Darstellungen des Domes im Schluckauf-Stil hin und her zu übergeben. In gwt habe ich gilead verwendet, um Modelle zwischen Client und Server zu teilen. In Clojure können Sie jedoch einfach Datenstrukturen weitergeben, sodass Klassendefinitionen wie in gwt nicht gemeinsam genutzt werden müssen.
  • Ein Bereich, in dem ich mehr experimentieren muss, ist die gemeinsame Nutzung des Status zwischen Client und Server. In meinen Augen gibt es einige Strategien: Speichern des Status auf dem Client (Anwendungen mit Ajax-Typ für eine Seite) oder Speichern des Status auf dem Server (wie ältere JSP-Apps) oder eine Kombination aus beiden. Vielleicht könnte der Code, der für die Aktualisierung des Status verantwortlich ist (die Atome, Refs, Agenten oder was auch immer), geteilt und dann der Status über Anforderung und Antwort hin und her weitergegeben werden, um die beiden Ebenen synchron zu halten? Bisher scheint es ziemlich gut zu funktionieren, einfach einen Server mit REST-Best Practices zu schreiben und dann den Status auf dem Client zu speichern. Aber ich konnte sehen, welche Vorteile es haben könnte, den Status zwischen Client und Server zu teilen.
  • Ich musste noch keine Konstanten und / oder Eigenschaften freigeben, aber dies könnte eine Wiederverwendung sein. Wenn Sie alle globalen Konstanten Ihrer App in eine CLJ-Datei einfügen und dann ein Skript schreiben, um es bei der Kompilierung des Clojureskripts in CLJS zu kopieren, sollte dies einwandfrei funktionieren und möglicherweise ein wenig doppelten Code sparen.

    Hoffe, diese Gedanken sind nützlich, ich bin sehr interessiert an dem, was andere bisher gefunden haben!

Andere Tipps

Ich habe das cljx Leiningen-Plugin speziell für die gemeinsame Nutzung von Clojure / ClojureScript-Code für eine Clojure-Datenvisualisierungsbibliothek geschrieben. 95% des Nicht-Host-Interop-Codes sehen gleich aus, und mit cljx können Sie die letzten 5% automatisch umschreiben, indem Sie Umschreiberegeln mit core.logic angeben. Meistens handelt es sich jedoch um einfache Symbolersetzungen.clojure.lang.IFn in Clojure ist beispielsweise nur IFn in ClojureScript.

Sie können auch Metadaten verwenden, um Formulare mit Anmerkungen zu versehen, die beim Generieren von Code für eine bestimmte Plattform eingeschlossen oder ausgeschlossen werden sollen.

Das neue lein-cljsbuild Plugin für Leiningen hat Unterstützung für die Freigabe von reinem Clojure-Code.

Schrieb ein kurzes Stück Code, um eine Teilmenge meines Server-Clojure-Codes in meinen Clojurescript-Code zu kopieren und vor dem Erstellen in .cljs umzubenennen:

(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"
   }
  )
)

Diese Frage ist älter als cljc, aber da ich darauf gestoßen bin, dachte ich, ich würde Clojure Reader Conditional .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top