前端使用 reagent.
见 src/client/tunnel/component/*.cljs (For Emacs) 或 src/client/tunnel/component (For Git Page)
(def root
(r/create-class
{:reagent-render
(fn
[]
[:div.container
[menu]
[:div.content
[:div.header
[:span "A Chatroom written in pure Clojure ^_^"]
[:span.icons.pull-right
[:i.fa.fa-plus-square-o.btn.fadeInLeft.animated]
[:i.fa.fa-sign-out.btn.fadeInLeft.animated {:on-click logout}]]]
[input-panel]
[msg-panel]]])}))
使用EDN的vector格式表示DOM, 代替html语法. 实现从数据到UI的逻辑(render), 用户行为触发数据的变化, 从来重绘UI.
使用 hiccup.
(defn register-page
[req]
(html5
[:head
[:meta {"charset" "utf-8"}]
[:meta {"name" "viewport"
"content" "width=device-width, initial-scale=1, maximum-scale=1"}]]
[:body
[:h3 "测试, 不要用惯用密码."]
[:form {:method :POST :action "/api/register"}
[:input {:name :username :type :text}]
[:input {:name :password :type :password}]
[:input {:type :submit :value "注册"}]
(anti-forgery-field)]
[:a {:href "/login"} "返回登陆"]]))
前后端保持一致
客户端服务器通信使用 Sente 提供的websocket.
可以模拟http请求的形式, 也可以单向的服务器->客户端, 客户端->服务器推送数据.
后台数据库使用的 Datomic.
(defmethod query :message/list-all
[{:keys [db]} _ {:keys [sel]}]
(->> (d/datoms db
:aevt :message/from)
reverse
(take 30)
(mapv #(d/pull db sel (:e %)))))
(defmethod tx-query :message/list-all
[{:keys [db tx-data]} _ {:keys [sel]}]
(d/q '[:find [(pull ?e sel) ...]
:in $ $tx-data sel
:where
[$tx-data ?e]
[?e :message/from]]
db tx-data sel))
查询写在 query.clj
, 修改写在 mutate.clj
.
开发环境前端热加载使用 Figwheel. 在保存文件的时候, 页面会自动更新. 开发环境中, Figwheel也兼职为服务器端WebServer.
使用 timbre 做日志输出.
使用 system 集成环境. 让开发的时候, 出现无法reloaded的修改时,
用 reset
重启环境.
- 测试环境: env/dev/tunnel/system.clj
- 正式环境: env/prod/tunnel/system.clj
CDN使用的 BootCDN, 简单易用, 开发很方便.
;; 启动
(go)
;; 重启
(reset)
;; 停止
(stop)
;; CLJ -> CLJS
(in-ns 'user)
(cljs-repl)
;; CLJS -> CLJ
:cljs/quit
lein do clean, uberjar