Совместное использование кода между сервером и клиентом в Clojurescript/Clojure

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


person Hendekagon    schedule 20.10.2011    source источник
comment
Это действительно имело бы смысл, как и в GWT, вы также можете совместно использовать код Java на сервере и на клиенте. Было бы очень здорово услышать ответ по этому поводу!   -  person Michiel Borkent    schedule 20.10.2011
comment
единственный способ, который я могу придумать прямо сейчас, - это поместить общий код в пространство имен сервера и структуру каталогов, а затем добавить строки в ваш код компиляции, чтобы скопировать файлы в исходный каталог клиента, переименовав их как *.cljs - потому что компилятор clojurescript ищет только файлы с именами .cljs   -  person Hendekagon    schedule 21.10.2011


Ответы (5)


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

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

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

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

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

person Upgradingdave    schedule 25.10.2011
comment
Отличные очки! Я хотел бы унифицировать процесс, заставив мой серверный код автоматически создавать весь мой код Clojurescript, передавая подмножество его функций в компилятор. Я еще не читал код компилятора, но должна быть возможность передавать ему выражения напрямую, без использования файлов .cljs. - person Hendekagon; 26.10.2011
comment
Что касается совместного использования структур данных, библиотека fetch кажется довольно удобной! github.com/ibdknox/fetch - person leontalbot; 06.08.2014

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

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

person Kevin L.    schedule 29.04.2012
comment
cljx был выбран cljsbuild - person Stephen Nelson; 04.03.2014

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

person Evan    schedule 19.02.2012

Написал небольшой фрагмент кода, чтобы скопировать подмножество кода моего сервера 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"
   }
  )
)
person Hendekagon    schedule 02.11.2011

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

person nha    schedule 17.01.2017