Совместное использование кода между сервером и клиентом в Clojurescript / Clojure - PullRequest
20 голосов
/ 20 октября 2011

Скажем, я хотел выделить какой-то общий код между моей клиентской * .cljs и моей серверной * .clj, например, различные структуры данных и общие операции, могу ли я это сделать?Есть ли смысл делать это?

Ответы [ 5 ]

15 голосов
/ 29 апреля 2012

Я написал плагин cljx Leiningen специально для управления совместным использованием кода Clojure / ClojureScript для библиотеки визуализации данных Clojure. 95% кода, не связанного с взаимодействием с хостом, выглядит одинаково, и cljx позволяет автоматически перезаписывать последние 5%, задавая правила перезаписи с использованием core.logic. Однако в большинстве случаев это простые замены символов; Например, clojure.lang.IFn в Clojure - это просто IFn в ClojureScript.

Вы также можете использовать метаданные для аннотирования форм, которые будут включены или исключены при создании кода для конкретной платформы.

12 голосов
/ 25 октября 2011

Обновление: начиная с версии 1.7, проверьте Условия чтения Clojure или cljc . Я с большим успехом использовал cljc, чтобы очень легко обмениваться большим количеством кода между сервером и браузером.

Отличный вопрос! В последнее время я тоже много думал об этом и написал несколько приложений для экспериментов.

Вот мой список типов вещей, которыми вы можете поделиться и плюсы / минусы каждого:

  • Большинство моих клиентских файлов cljs содержат код, который манипулирует dom. Поэтому не имеет смысла делиться этим с сервером
  • Большая часть серверной части имеет дело с вызовами файловой системы и базы данных. Я полагаю, вы можете вызвать базу данных с клиента (особенно если вы используете одну из баз данных no-sql, поддерживающих вызовы javascript). Но даже тогда я чувствую, что вы должны либо выбрать вызов db из клиента, либо вызов db с сервера, и поэтому нет смысла делиться кодом db.
  • Одной из областей, где совместное использование, безусловно, является ценным, является возможность совместного использования и передачи структур данных clojure (вложенных комбинаций списков, векторов, наборов и т. Д.) Между клиентом и сервером. Не нужно конвертировать в json (или xml) и обратно. Например, возможность передавать представления типа hiccup в стиле «назад-вперед» очень удобна. В gwt я использовал gilead для обмена моделями между клиентом и сервером. Но в clojure вы можете просто передавать структуры данных, так что на самом деле нет необходимости делиться определениями классов, как в gwt.
  • Одна область, в которой мне нужно больше экспериментировать, - это совместное использование состояния между клиентом и сервером. На мой взгляд, существует несколько стратегий: сохранение состояния на клиенте (одностраничные приложения типа ajax) или сохранение состояния на сервере (например, унаследованные приложения jsp) или их комбинация. Возможно, код, отвечающий за обновление состояния (атомы, ссылки, агенты или что-то еще), может быть разделен, а затем состояние может передаваться взад и вперед по запросу и ответу, чтобы синхронизировать два уровня? До сих пор простое написание сервера с использованием лучших методик REST, а затем сохранение состояния на клиенте, кажется, работает довольно хорошо. Но я мог видеть, как могут быть преимущества совместного использования состояния между клиентом и сервером.
  • Мне еще не нужно было делиться константами и / или свойствами, но это может быть полезно для повторного использования. Если вы поместите все глобальные константы вашего приложения в файл clj, а затем напишите сценарий для его копирования в cljs всякий раз, когда вы скомпилируете clojurescript, это должно работать нормально и может сэкономить немного дублирования кода.

Надеюсь, что эти мысли полезны, мне очень интересно, что уже нашли другие!

10 голосов
/ 19 февраля 2012

Новый плагин lein-cljsbuild для Leiningen имеет встроенную поддержку для обмена чистым кодом Clojure.

2 голосов
/ 02 ноября 2011

Написал небольшой фрагмент кода, чтобы скопировать часть моего кода clojure моего сервера в мой код clojurescript, переименовав его в .cljs перед сборкой:

(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"
   }
  )
)
0 голосов
/ 17 января 2017

Этот вопрос предшествует cljc, но, поскольку я наткнулся на него, я подумал, что упомяну Clojure условия чтения .

...