Pregunta

Digamos que quería factorizar algún código común entre mi * .cljs del lado del cliente y mi * .clj del lado del servidor, p.varias estructuras de datos y operaciones comunes, ¿puedo hacer eso?¿Tiene sentido hacerlo?

¿Fue útil?

Solución

Actualización: a partir de clojure 1.7, consulte condicionales del lector de Clojure o cljc . He usado cljc con gran éxito para compartir una gran cantidad de código entre el servidor y el navegador con mucha facilidad.

¡Gran pregunta! También he estado pensando mucho en esto últimamente y he escrito algunas aplicaciones para experimentar.

Aquí está mi lista de los tipos de cosas que le gustaría compartir y las ventajas y desventajas de cada una:

  • La mayoría de los archivos cljs de mi cliente contienen código que manipula el dominio dom. Entonces, no tendría sentido compartir nada de eso con el servidor
  • La mayoría de las cosas del lado del servidor se ocupan del sistema de archivos y las llamadas a bases de datos. Supongo que es posible que desee llamar a la base de datos desde el cliente (especialmente si está utilizando una de las bases de datos no-sql que admiten llamadas de JavaScript). Pero, incluso entonces, creo que debería elegir llamar a db desde el cliente o llamar a db desde el servidor y, por lo tanto, tampoco tiene mucho sentido compartir el código de db.
  • Un área donde compartir es definitivamente valioso es poder compartir y pasar estructuras de datos de clojure (combinaciones anidadas de listas, vectores, conjuntos, etc.) entre el cliente y el servidor. No es necesario convertir a json (o xml) y viceversa. Por ejemplo, es muy conveniente poder pasar de un lado a otro representaciones del dom al estilo hipo. En gwt, he usado gilead para compartir modelos entre cliente y servidor. Pero, en clojure, simplemente puede pasar estructuras de datos, por lo que realmente no hay necesidad de compartir definiciones de clases como en gwt.
  • Un área en la que siento que necesito experimentar más es compartir el estado entre el cliente y el servidor. En mi opinión, existen algunas estrategias: almacenar el estado en el cliente (aplicaciones de tipo Ajax de una sola página) o almacenar el estado en el servidor (como las aplicaciones jsp heredadas) o una combinación de ambos. ¿Quizás el código responsable de actualizar el estado (los átomos, referencias, agentes o lo que sea) podría compartirse y luego el estado podría pasarse de un lado a otro sobre la solicitud y la respuesta para mantener los dos niveles sincronizados? Hasta ahora, simplemente escribir el servidor usando las mejores prácticas REST y luego tener el estado almacenado en el cliente parece funcionar bastante bien. Pero pude ver cómo podría haber beneficios al compartir el estado entre el cliente y el servidor.
  • No he necesitado compartir Constantes y / o Propiedades todavía, pero esto podría ser algo que sería bueno reutilizar. Si coloca todas las constantes globales de su aplicación en un archivo clj y luego escribe un script para copiarlo en cljs cada vez que compila el clojurescript, eso debería funcionar bien y podría ahorrar un poco de duplicación de código.

Espero que estos pensamientos sean útiles. ¡Estoy muy interesado en lo que otros han encontrado hasta ahora!

Otros consejos

Escribí el complemento cljx de Leiningen específicamente para manejar el uso compartido de código Clojure / ClojureScript para una biblioteca de visualización de datos Clojure. El 95% del código que no es de interoperabilidad de host tiene el mismo aspecto, y cljx le permite reescribir automáticamente ese último 5% especificando reglas de reescritura usando core.logic. La mayoría de las veces, sin embargo, son simples sustituciones de símbolos;clojure.lang.IFn en Clojure es solo IFn en ClojureScript, por ejemplo.

También puede usar metadatos para anotar formularios que se incluirán o excluirán cuando se genere código para una plataforma específica.

El nuevo complemento lein-cljsbuild para Leiningen tiene soporte para compartir código Clojure puro.

Escribí un fragmento rápido de código para copiar un subconjunto del código clojure de mi servidor en mi código clojurescript, renombrando como .cljs antes de compilar:

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

Esta pregunta es anterior a cljc, pero como me topé con ella, pensé que mencionaría condicionales del lector .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top