2011-10-20 2 views
21

Dire che volevo calcolare un codice comune tra il mio lato client * .cljs e il mio lato server * .clj, ad es. varie strutture dati e operazioni comuni, posso farlo? Ha senso farlo?Condivisione codice tra server e client in Clojurescript/Clojure

+2

Avrebbe davvero senso, come in GWT è anche possibile condividere il codice Java sul server e sul client. Sarebbe molto bello sentire la risposta su questo! –

+0

l'unico modo in cui posso pensare adesso è mettere il codice condiviso in uno spazio dei nomi e una struttura di directory del server, quindi aggiungere linee al codice di compilazione per copiare i file nella directory dei sorgenti del client, rinominando come * .cljs - perché il clojurescript il compilatore cerca solo i file chiamati .cljs – Hendekagon

risposta

13

Aggiornamento: a partire da 1.7, verificare Clojure reader conditionals or cljc. Ho usato cljc con grande successo per condividere molto codice tra server e browser molto facilmente.

Ottima domanda! Ho pensato molto anche a questo ultimamente e ho scritto alcune app da sperimentare.

Ecco la mia lista di quali tipi cose che si potrebbe desiderare di condividere e vantaggi/svantaggi di ciascuno:

  • La maggior parte del mio cliente cljs file contiene il codice che manipola il dom. Quindi, non avrebbe senso condividere tutto ciò con il server
  • La maggior parte delle cose sul lato server riguardano le chiamate al filesystem e al database. Suppongo che potresti voler chiamare il database dal client (specialmente se stai usando uno dei db no-sql che supporta le chiamate javascript). Ma, anche in questo caso, penso che dovresti scegliere di chiamare db dal client o chiamare db dal server e, quindi, non ha molto senso condividere il codice db.
  • Un'area in cui la condivisione è decisamente utile è la possibilità di condividere e passare strutture di dati clojure (combinazioni annidate di elenchi, vettori, set, ecc.) Tra client e server. Non c'è bisogno di convertire in json (o xml) e viceversa. Ad esempio, essere in grado di passare le rappresentazioni in stile hiccup della dom back and forth è molto conveniente. In gwt, ho usato gilead per condividere modelli tra client e server. Ma, in Clojure, puoi semplicemente passare le strutture dati in giro, quindi non c'è davvero bisogno di condividere le definizioni di classe come in gwt.
  • Un'area che sento di dover sperimentare di più è lo stato di condivisione tra client e server. Nella mia mente ci sono alcune strategie: store state sul client (applicazioni di tipo ajax a pagina singola) o store state sul server (come le applicazioni legacy jsp) o una combinazione di entrambi. Forse il codice responsabile dell'aggiornamento dello stato (gli atomi, i refs, gli agenti o qualsiasi altra cosa) potrebbe essere condiviso e quindi lo stato potrebbe essere passato avanti e indietro su richiesta e risposta per mantenere sincronizzati i due livelli? Finora, la semplice scrittura del server utilizzando le best practice REST e lo stato memorizzato sul client sembra funzionare piuttosto bene. Ma ho potuto vedere come potrebbero esserci dei benefici nello stato di condivisione tra client e server.
  • Non ho ancora bisogno di condividere costanti e/o proprietà, ma questo potrebbe essere qualcosa che sarebbe buono da riutilizzare. Se si inseriscono tutte le costanti globali della tua app in un file clj e poi si scrive uno script per copiarlo su cljs ogni volta che si compila il clojurescript, questo dovrebbe funzionare correttamente e potrebbe salvare un po 'di duplicazione del codice.

Spero che questi pensieri siano utili, sono molto interessato a ciò che altri hanno trovato finora!

+0

Punti eccellenti! Vorrei unificare il processo facendo in modo che il mio codice server autocostruisca tutto il mio codice Clojurescript passando un sottoinsieme delle sue funzioni nel compilatore. Non ho ancora letto il codice del compilatore, ma deve essere possibile alimentare le espressioni direttamente senza utilizzare i file .cljs. – Hendekagon

+0

Per quanto riguarda la condivisione di datastruture, la libreria 'fetch' sembra essere molto carina! https://github.com/ibdknox/fetch – leontalbot

2

Ha scritto un po 'veloce di codice da copiare un sottoinsieme del mio codice server clojure verso il mio codice ClojureScript, rinominare come .cljs prima di edificio:

(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

Il nuovo plug-in per lein-cljsbuild Leiningen è dotato di support per condividere il codice Clojure puro.

+2

[cljsbuild] (https://github.com/emezeske/lein-cljsbuild) Il supporto integrato (crossover) è stato deprecato a favore di [cljx] (https : //github.com/lynaghk/cljx), vedere [questo] (http://stackoverflow.com/a/10369314/1209442) risposta. –

15

Ho scritto il plug-in Leiningen cljx appositamente per gestire la condivisione del codice Clojure/ClojureScript per una libreria di visualizzazione dei dati Clojure. Il 95% del codice di interoperabilità non host ha lo stesso aspetto e cljx consente di riscrivere automaticamente l'ultimo 5% specificando le regole di riscrittura utilizzando core.logic. La maggior parte delle volte, tuttavia, sono sostituzioni di simboli semplici; clojure.lang.IFn in Clojure è solo IFn in ClojureScript, per esempio.

È inoltre possibile utilizzare i metadati per annotare i moduli da includere o escludere quando il codice viene generato per una piattaforma specifica.

+0

sembra utile cheerz – Hendekagon

+1

[cljx] (https://github.com/lynaghk/cljx) è stato adottato come lo strumento di condivisione del codice scelto da [cljsbuild] (https://github.com/emezeske/lein-cljsbuild) –

0

Questa domanda precede lo cljc, ma poiché ci siamo imbattuti in esso, ho pensato di menzionare Clojure reader conditionals.