Да кажем, че исках да отделя някакъв общ код между моя *.cljs от страна на клиента и моя *.clj от страна на сървъра, напр. различни структури от данни и общи операции, мога ли да направя това? Има ли смисъл да го правя?
Споделяне на код между сървър и клиент в Clojurescript/Clojure
Отговори (5)
Актуализация: от clojure 1.7 вижте Clojure reader условни или cljc. Използвах cljc с голям успех, за да споделя много лесно много код между сървър и браузър.
Страхотен въпрос! Напоследък също мислих много за това и написах няколко приложения, за да експериментирам.
Ето списъка ми с видовете неща, които бихте искали да споделите, както и плюсовете/минусите на всяко от тях:
- Повечето от моите клиентски cljs файлове съдържат код, който манипулира dom. Така че не би имало смисъл да споделяте нищо от това със сървъра
- Повечето от нещата от страна на сървъра се занимават с извиквания на файлова система и база данни. Предполагам, че може да искате да извикате базата данни от клиента (особено ако използвате един от no-sql db, които поддържат javascript извиквания). Но дори и тогава смятам, че трябва да изберете да извикате db от клиент или да извикате db от сървър и следователно няма много смисъл да споделяте db кода.
- Една област, в която споделянето определено е ценно, е възможността за споделяне и предаване на структури от данни clojure (вложени комбинации от списъци, вектори, набори и т.н.) между клиент и сървър. Няма нужда да конвертирате в json (или xml) и обратно. Например, възможността да предавате представяния на dom напред и назад в стил хълцане е много удобно. В 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 има вграден поддръжка за споделяне на чист код на 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 условни четеци.