Скажем, я хотел выделить некоторый общий код между моим клиентским *.cljs и моим серверным *.clj, например. различные структуры данных и общие операции, могу ли я это сделать? Есть ли смысл это делать?
Совместное использование кода между сервером и клиентом в Clojurescript/Clojure
Ответы (5)
Обновление: начиная с clojure 1.7, ознакомьтесь с условиями чтения Clojure или cljc. Я с большим успехом использовал cljc, чтобы очень легко обмениваться большим количеством кода между сервером и браузером.
Отличный вопрос! В последнее время я тоже много думал об этом и написал несколько приложений для экспериментов.
Вот мой список вещей, которыми вы, возможно, захотите поделиться, а также плюсы и минусы каждого из них:
- Большинство моих клиентских файлов cljs содержат код, управляющий файлом dom. Таким образом, не имеет смысла делиться этим с сервером.
- Большая часть серверной части связана с файловой системой и вызовами базы данных. Я предполагаю, что вы можете вызвать базу данных с клиента (особенно если вы используете одну из баз данных без sql, которые поддерживают вызовы javascript). Но даже в этом случае я чувствую, что вам следует выбрать либо вызов базы данных с клиента, либо вызов базы данных с сервера, и поэтому также не имеет особого смысла делиться кодом базы данных.
- Одной из областей, где совместное использование определенно ценно, является возможность совместного использования и передачи структур данных clojure (вложенных комбинаций списков, векторов, наборов и т. д.) между клиентом и сервером. Не нужно конвертировать в json (или xml) и обратно. Например, возможность передавать представления дома в стиле икоты туда и обратно очень удобна. В gwt я использовал Gilead для обмена моделями между клиентом и сервером. Но в clojure вы можете просто передавать структуры данных, поэтому нет необходимости делиться определениями классов, как в gwt.
- Одна область, в которой, как мне кажется, мне нужно больше экспериментировать, — это совместное использование состояния между клиентом и сервером. На мой взгляд, есть несколько стратегий: хранить состояние на клиенте (одностраничные приложения типа ajax) или хранить состояние на сервере (например, устаревшие приложения jsp) или комбинацию обоих. Возможно, код, отвечающий за обновление состояния (атомы, ссылки, агенты или что-то еще), можно было бы использовать совместно, а затем состояние можно было бы передавать туда и обратно по запросу и ответу, чтобы поддерживать синхронизацию двух уровней? До сих пор просто писать сервер с использованием лучших практик REST, а затем сохранять состояние на клиенте, похоже, работает довольно хорошо. Но я мог видеть, какие преимущества может принести совместное использование состояния между клиентом и сервером.
- Мне еще не нужно было делиться константами и/или свойствами, но это может быть полезно для повторного использования. Если вы поместите все глобальные константы вашего приложения в файл clj, а затем напишете скрипт, который будет копировать их в cljs всякий раз, когда вы компилируете clojurescript, это должно работать нормально и может сэкономить немного дублирования кода.
Надеюсь, эти мысли будут полезны, мне очень интересно, что другие уже нашли!
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.
Вы также можете использовать метаданные для аннотирования форм, которые будут включены или исключены при создании кода для конкретной платформы.
Новый подключаемый модуль lein-cljsbuild для Leiningen имеет встроенный support для обмена чистым кодом Clojure.
Написал небольшой фрагмент кода, чтобы скопировать подмножество кода моего сервера 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"
}
)
)
Этот вопрос предшествует cljc
, но поскольку я наткнулся на него, я решил упомянуть Clojure условия чтения.