大家晚安~
前面幾天對Reagent的初步認識,知道了Reagent讓我們得以用最輕鬆簡單的Clojure interface操作React,
但關於再複雜一點前端複雜的事件狀態管理,使用Reagent就有其局限性。
有了前面ClojureScript的知識積累:今天終於可以名副其實來到本系列文的主題:
後端Developer實戰ClojureScript: Reagent與前端框架 Reframe
來安裝re-frame App -
感受一下能把Reagent再包一層的FrontEnd framework吧!
我們將透過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