Pergunta

Digamos que eu queria fator de algum código comum entre o meu cliente-side * .cljs e meu server-side * .clj, por exemplo, várias estruturas de dados e operações comuns, eu posso fazer isso? Será que faz sentido fazê-lo?

Foi útil?

Solução

Update: a partir de Clojure 1.7, consulte a Clojure condicionais leitor ou cljc. Eu usei cljc com grande sucesso para compartilhar um monte de código entre o servidor eo navegador com muita facilidade.

Ótima pergunta! Eu estive pensando muito sobre isso tão bem ultimamente e ter escrito alguns aplicativos para experimentar.

Aqui está a minha lista de quais os tipos coisas que você pode querer compartilhar e vantagens / desvantagens de cada um:

  • A maioria dos meus arquivos cljs cliente contém código que manipula o DOM. Assim, não faria sentido para compartilhar nada disso com o servidor
  • A maioria dos servidores stuff lado lida com chamadas de sistema de arquivos e banco de dados. Eu suponho que você pode querer chamar o banco de dados do cliente (especialmente se você estiver usando um dos que as chamadas de suporte a JavaScript do db não-SQL). Mas, mesmo assim, eu sinto que você deve optar por db chamada de cliente ou chamada db do servidor e, portanto, não faz muito sentido para compartilhar o código db quer.
  • Uma área onde a partilha é definitivamente valiosa é ser capaz de compartilhar e transmitir estruturas de dados Clojure (combinações aninhados de listas, vetores, conjuntos, etc.) entre cliente e servidor. Não há necessidade de converter para JSON (ou xml) e nas costas. Por exemplo, ser capaz de passar soluço de estilo representações da volta dom e para trás é muito conveniente. No GWT, eu usei Gileade modelos compartilham entre cliente e servidor. Mas, em Clojure, você pode simplesmente passar estruturas de dados ao redor, então não há realmente nenhuma necessidade de definições de classe share como em GWT.
  • Uma área que eu sinto que preciso experimentar mais é compartilhar estado entre cliente e servidor. Na minha mente há algumas estratégias: estado loja no cliente (aplicações única página tipo ajax) ou estado loja no servidor (como aplicações legadas jsp) ou uma combinação de ambos. Talvez o código responsável por estado atualização (os átomos, refs, agentes ou qualquer outro) poderia ser compartilhado e, em seguida, estado poderia ser passado para trás e para frente sobre pedido e resposta para manter as duas listas em sincronia? Até agora, simplesmente escrever servidor usando RESTO melhores práticas e depois ter estado armazenado no cliente parece funcionar muito bem. Mas eu podia ver como pode haver benefícios para partilhar estado entre cliente e servidor.
  • Eu não precisava Constantes de compartilhamento e / ou propriedades ainda, mas isso pode ser algo que seria bom para reutilização. Se você colocar todas as constantes globais de seu aplicativo em um arquivo CLJ e, em seguida, escreveu um script para copiá-lo para cljs sempre que compilou o clojurescript, que deve funcionar bem, e pode guardar um pouco de duplicação de código.

Hope esses pensamentos são úteis, eu estou muito interessado no que os outros têm encontrado até agora!

Outras dicas

Eu escrevi o cljx Leiningen plug-in especificamente para lidar com Clojure / ClojureScript partilha de códigos para uma biblioteca de visualização de dados Clojure . 95% do código não-host-interoperabilidade parece o mesmo, e cljx permite reescrever automaticamente o último 5% especificando regras de reescrita usando core.logic. Na maioria das vezes, porém, é substituições símbolo simples; clojure.lang.IFn em Clojure é apenas IFn em ClojureScript, por exemplo.

Você também pode usar metadados para formas anotar a serem incluídas ou excluídas quando o código é gerado para uma plataforma específica.

O novo lein-cljsbuild plugin para Leiningen foi construído com suporte para o compartilhamento de código Clojure puro

Escreveu um pouco rápido de código para copiar um subconjunto do meu código Clojure servidor para o meu código clojurescript, renomeando como .cljs antes de construir:

(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 questão antecede cljc, mas desde que eu tropecei em cima dele, eu pensei que eu iria falar Clojure leitor condicionais .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top