大家晚安~
前面幾天對Reagent的初步認識,知道了Reagent讓我們得以用最輕鬆簡單的Clojure interface操作React,
但關於再複雜一點前端複雜的事件狀態管理,使用Reagent就有其局限性。
有了前面ClojureScript的知識積累:今天終於可以名副其實來到本系列文的主題:
後端Developer實戰ClojureScript: Reagent與前端框架 Reframe
來安裝re-frame App -
感受一下能把Re
agent再包一層的FrontEnd frame
work吧!
我們將透過Re-frame建立一個SPA(Single Page Application),所有畫面都是在前端由ClojureScript打包成的JavaScript 動態產生。後端永遠都輸出同一個檔案,避免頁面之間切換打斷使用者體驗。
shadow-cljs
re-frame-10x
如同我們之前學過clojure語言的特性,re-frame也有同樣的好處:
function是First-class一等公民,可以作為其它function的輸入參數值,也可以把function return value,被修改或者被分配給variable。
data-oriented比起oo(object-oriented)設計的好處是同一個form可以套用到不同使用情境。
例如我們學過不管是reagent或reframe,前端都是hiccup syntax,不同library之間的溝通其實是用同種plain data的表達方式。(只要具備data structure的操作能力,然後找到適合處理各種情境的第三方library,那我們就可以透過操作data的programming處理大部份需求。)
跟Reagent專案一樣,在安裝re-frame之前,電腦環境需要:
溫故知新一下,這次鐵人賽是我裝了最多次不同專案的一個月 XD
lein new figwheel hello-world
lein new reagent ironproject
有聰明腦袋瓜的你,應該可以推測安裝Reframe的指令是
lein new re-frame ironframework +10x
一下就裝完了,非常迅速!
❯ lein new re-frame ironframework +10x
Retrieving re-frame/lein-template/2.4.8/lein-template-2.4.8.pom from clojars
Retrieving re-frame/lein-template/2.4.8/lein-template-2.4.8.jar from clojars
Generating re-frame project.
用tree-a
觀察結構
~/Projects/ironmanframework 4m 41s
❯ tree -a
.
├── .clj-kondo
├── .gitignore
├── README.md
├── dev
│ └── user.cljs
├── karma.conf.js
├── package.json
├── resources
│ └── public
│ └── index.html
├── shadow-cljs.edn
└── src
└── ironframework
├── config.cljs
├── core.cljs
├── db.cljs
├── events.cljs
├── subs.cljs
└── views.cljs
相較於輕量化的reagent專案,我們可以比較出之前的src的cljs,folser內預設只有 core.cljs
一支檔案
└── src/cljs
└── ironframework
├── core.cljs
今天的re-frame預設src下還有拆分db.cljs
, events.cljs
, subs.cljs
, view.cljs
└── src
└── ironmanframework
├── config.cljs
├── core.cljs
├── db.cljs
├── events.cljs
├── subs.cljs
└── views.cljs
引入多個檔案的方式是在 ironframework.core
的namespace下
ironframework.events
, ironframework.views
等
(ns ironmanframework.core
(:require
[reagent.dom :as rdom]
[re-frame.core :as re-frame]
[ironframework.events :as events]
[ironframework.views :as views]
[ironframework.config :as config]
))
shadow-cljs
是我們的CLJS compilation, dependency management, REPL和hot reload的重要工具
在clojureScript系列專案(re-frame)安裝自訂的dependency很簡單,例如我想再多加一個debugging tool re-frame-10x
就再:dependeny
多放一個vector裝你想要的版本號[day8.re-frame/http-fx "0.2.3"]
進去就好了
:dependencies
[[reagent "1.1.1"]
[re-frame "1.3.0"]
[day8.re-frame/tracing "0.6.2"]
[day8.re-frame/http-fx "0.2.3"]
[binaryage/devtools "1.0.6"]
[day8.re-frame/re-frame-10x "1.5.0"]]
在專案資料夾下先 npm install
安裝跟dependency有關
接著輸入
npm run watch
我遇到了Execution
JVM版本錯誤的問題
~/Projects/ironmanframework
❯ npm run watch
> ironmanframework@ watch /Users/tingtinghsu/Projects/ironmanframework
> npx shadow-cljs watch app
shadow-cljs - config: /Users/tingtinghsu/Projects/ironmanframework/shadow-cljs.edn
Execution error (UnsupportedClassVersionError) at java.lang.ClassLoader/defineClass1 (ClassLoader.java:-2).
com/google/javascript/jscomp/CompilerOptions has been compiled by a more recent ver
查了一下其他人是否遇到同樣的Execution error,
發生的原因是 App 編譯成 55.0 版(Java 11),但執行環境的 JVM 為 52.0 版(Java 8)
在.tool-version裡新增 java zulu-11.58.23
再用asdf來安裝java新版本
~/Projects/ironmanframework
❯ asdf install java
########################################################### 100.0%
zulu11.58.23-ca-jdk11.0.16.1-macosx_x64.zip
zulu11.58.23-ca-jdk11.0.16.1-macosx_x64.zip: OK
Archive: zulu11.58.23-ca-jdk11.0.16.1-macosx_x64.zip
creating: zulu11.58.23-ca-jdk11.0.16.1-macosx_x64/
確認一下有沒有裝好11版
❯ javap -version
11.0.16.1
看起來Java 11版有裝成功!可以繼續跑npm run watch
來build app
~/Projects/ironmanframework
❯ npm run watch
> ironmanframework@ watch /Users/tingtinghsu/Projects/ironmanframework
> npx shadow-cljs watch app
shadow-cljs - config: /Users/tingtinghsu/Projects/ironmanframework/shadow-cljs.edn
shadow-cljs - HTTP server available at http://localhost:8280
shadow-cljs - HTTP server available at http://localhost:8290
shadow-cljs - server version: 2.19.9 running at http://localhost:9630
shadow-cljs - nREPL server started on port 8777
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
[:app] Build completed. (461 files, 460 compiled, 0 warnings, 42.08s)
確認一下 nREPL有起成功 :
;; The REPL prompt, `shadow.user=>`, indicates that is a Clojure REPL, not ClojureScript.
lein repl :connect localhost:8777
連接到shadow-cljs
觀察是否成功運行
http://localhost:9630/dashboard
最後改一下給前端顯示的view.cljs檔案,加上自己想要的wording試試看~
(ns ironmanframework.views
(:require
[re-frame.core :as re-frame]
[ironmanframework.subs :as subs]
))
(defn main-panel []
(let [name (re-frame/subscribe [::subs/name])]
[:div
[:h1
"Hello Ironman Ting Ting from " @name]
]))
又過了一個學習關卡,
成功啟動第一個re-frame專案啦!
Ref:
ClojureScript Web App Tutorial Using Re-Frame and Http-Fx