Domanda

Supponiamo che volessi escludere un codice comune tra il mio * .cljs lato client e il mio * .clj lato server, ad es.varie strutture dati e operazioni comuni, posso farlo?Ha senso farlo?

È stato utile?

Soluzione

Aggiornamento: a partire da clojure 1.7, controlla Clojure reader conditionals o cljc . Ho utilizzato cljc con grande successo per condividere molto facilmente molto codice tra server e browser.

Ottima domanda! Ultimamente ho pensato molto anche a questo e ho scritto alcune app per sperimentare.

Ecco il mio elenco dei tipi di cose che potresti voler condividere e dei pro / contro di ciascuno:

  • La maggior parte dei file cljs del mio client contiene codice che manipola dom. Quindi, non avrebbe senso condividere nulla di tutto ciò con il server
  • La maggior parte delle cose lato server riguarda 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 supportano le chiamate javascript). Ma, anche in questo caso, sento che dovresti scegliere di chiamare db dal client o chiamare db dal server e, quindi, non ha molto senso condividere nemmeno il codice db.
  • Un'area in cui la condivisione è decisamente preziosa è la possibilità di condividere e passare strutture di dati di chiusura (combinazioni annidate di elenchi, vettori, set, ecc.) tra client e server. Non è necessario convertire in json (o xml) e viceversa. Ad esempio, essere in grado di trasmettere rappresentazioni del dom in stile singhiozzo avanti e indietro è molto conveniente. In gwt, ho usato gilead per condividere modelli tra client e server. Ma, in clojure, puoi semplicemente passare strutture di dati, quindi non c'è davvero bisogno di condividere definizioni di classe come in gwt.
  • Un'area che sento di dover sperimentare di più è la condivisione dello stato tra client e server. Nella mia mente ci sono alcune strategie: memorizzare lo stato sul client (applicazioni di tipo ajax a pagina singola) o memorizzare lo stato sul server (come le app jsp legacy) o una combinazione di entrambi. Forse il codice responsabile dell'aggiornamento dello stato (atomi, ref, agenti o altro) 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 migliori pratiche REST e quindi la memorizzazione dello stato sul client sembra funzionare abbastanza bene. Ma ho potuto vedere come potrebbero esserci vantaggi nella condivisione dello stato tra client e server.
  • Non avevo ancora bisogno di condividere costanti e / o proprietà, ma questo potrebbe essere qualcosa che sarebbe bene riutilizzare. Se metti tutte le costanti globali della tua app in un file clj e poi scrivi uno script per copiarlo su cljs ogni volta che hai compilato il clojurescript, dovrebbe funzionare bene e potrebbe far risparmiare un po 'di duplicazione del codice.

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

Altri suggerimenti

Ho scritto il plug-in Leiningen cljx specificamente 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 ti consente di riscrivere automaticamente l'ultimo 5% specificando le regole di riscrittura utilizzando core.logic. Il più delle volte, però, si tratta di semplici sostituzioni di simboli;clojure.lang.IFn in Clojure è solo IFn in ClojureScript, ad esempio.

Puoi anche utilizzare i metadati per annotare i moduli da includere o escludere quando il codice viene generato per una piattaforma specifica.

Il nuovo plug-in lein-cljsbuild per Leiningen ha supporto per la condivisione di codice Clojure puro.

Ho scritto un breve codice per copiare un sottoinsieme del codice clojure del mio server nel mio codice clojurescript, rinominandolo come .cljs prima della creazione:

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

Questa domanda è antecedente a cljc, ma poiché mi sono imbattuto in essa, ho pensato di menzionare Clojure reader conditionals .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top