iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0

早安!歡迎進入前端的世界
今天來介紹ClojureScript專案,並且寫一個會跳出來跟我們說Hello Ironman的網頁~

用ClojureScript寫專案的好處

當我們在從0開始打造一個JavaScript專案時,可能要考慮蠻多的問題

  • 到底是使用純vanilla JavaScript 還是第三方的套件
  • 要不要用jQuery呢?
  • 要不要用Lodash呢?(Lodash對JavaScript底層的功能擴充,為Function、Array、Object等原生物件增加蠻多可以使用的方法

第三方套件雖然方便好用,但也會造成page loading速度變慢。

ClojureScript有許多很棒的 data structures 像是collection、strings、math, 以及狀態管理等。
就可以簡化上述麻煩的決策。

另一方面,ClojureScript使用Google Closure Compiler轉譯工具與 Closure Library函式庫,而且瀏覽器相容性的問題也比較少。讓我們工程師可以把注意力聚焦在用coding處理問題的本質上。

我蠻喜歡Learn ClojureScript畫的這張圖:

ClojureScript的ExpressionsSequence及functional programming的語法特色,可以帶我們處理High-Level層級的問題。

Leiningen 簡介

工欲善其事,必先利其器。快速產生ClojureScript(或者是Clojure)專案,我們可以用負責自動化build project的Leiningen。

https://codeberg.org/leiningen/leiningen

安裝Leiningen在Mac上十分簡單,透過Homebrew安裝就可以了

brew install Leiningen

建立ClojureScript專案

安裝好了Leiningen,
就可以透過new figwheel建立cljs template project的指令,
一鍵建立專案!( 一鍵建立的時候都會覺得自己是神)

❯ lein new figwheel hello-world

Retrieving figwheel/lein-template/0.5.20-5/lein-template-0.5.20-5.pom from clojars
Retrieving figwheel/lein-template/0.5.20-5/lein-template-0.5.20-5.jar from clojars
Generating fresh 'lein new' figwheel project.

Change into your 'hello-world' directory

Then run 'lein figwheel'
Wait for it to finish compiling
A browser window should open to the demo application, if not
then open 'http://localhost:3449/index.html' in your browser

Leiningen常用指令

Leiningen文件上可以查看實用的指令

$ lein new [TEMPLATE] NAME # generate a new project skeleton

$ lein test [TESTS] # run the tests in the TESTS namespaces, or all tests

$ lein repl # launch an interactive REPL session

$ lein run -m my.namespace # run the -main function of a namespace

$ lein uberjar # package the project and dependencies as standalone jar

$ lein deploy clojars # publish the project to Clojars as a library

由於我們是做前端專案
所以根據command line的提示

Then run 'lein figwheel'
Wait for it to finish compiling
A browser window should open to the demo application, if not
then open 'http://localhost:3449/index.html' in your browser

等等開啟瀏覽器運行code的指令是 lein figwheel

cljs資料夾結構

從此時此刻開始,我們會把ClojureScript簡稱為cljs的縮寫啦!

首先用tree這個套件來介紹一下資料夾結構

~/Projects/hello-world

❯ tree -a
.
├── .gitignore
├── README.md
├── dev
│   └── user.clj
├── project.clj
├── resources
│   └── public
│       ├── css
│       │   └── style.css
│       └── index.html
└── src
    └── hello_world
        └── core.cljs

其中

  • src/hello_world資料夾代表這個專案的namespace
  • core.cljs主程式的檔案,副檔名為cljs,我們主要會在裡面coding

cljs 版的 Hello World

注意:cljcljs 的區分

身為Clojure/ClojureScript新手,在查資料的時候一開始也被搞混,
我查到的網頁是到底是要建立Clojure專案還是cljs專案呢?

如果我們是用lein new app的方式,建立的是clj專案

所以我一開始也搞錯了!XD (以下的專案已被丟進垃圾桶O_Q)

比較一下專案內容

  • 打開core.clj主程式:
(ns cljs-it-ironman.core)

(defn hello
  [x]
  (println x "Hello, World!"))

no no no這不是cljs專案(搖手指)

就只會有副檔名為clj的檔案

  • 且clojure的project.clj檔案的配置也會很不一樣
(defproject cljs-it-ironman "0.1.0-SNAPSHOT"
  :description "My first cljs project"
  :url "https://ithelp.ithome.com.tw/users/20111177/articles"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.11.1"]]
  :repl-options {:init-ns cljs-it-ironman.core})

project.clj爲專案的配置描述文件(專案的description、license、使用到的套件以compile選項)

前端專案裡的 core.cljs & project.clj

但因為我們的目的是要做一個前端專案

就沒有core.clj這個檔案了。副檔名會是core.cljs

core裡面長的樣子就會很不一樣啦!會有狀態管理(state management),並且可以設定js reload的時候的機制

  • core.cljs
(ns hello-world.core
    (:require))

(enable-console-print!)

(println "This text is printed from src/hello-world/core.cljs. Go ahead and edit it and see reloading in action.")

;; define your app data so that it doesn't get over-written on reload

(defonce app-state (atom {:text "Hello world!"}))


(defn on-js-reload [])
  ;; optionally touch your app-state to force rerendering depending on
  ;; your application
  ;; (swap! app-state update-in [:__figwheel_counter] inc)
  • project.clj 內的defproject也複雜許多
(defproject hello-world "0.1.0-SNAPSHOT"
  :description "My first cljs project"
  :url "https://ithelp.ithome.com.tw/users/20111177/articles"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}

  :min-lein-version "2.9.1"

  :dependencies [[org.clojure/clojure "1.10.0"]
                 [org.clojure/clojurescript "1.10.773"]
                 [org.clojure/core.async  "0.4.500"]]

  :plugins [[lein-figwheel "0.5.20"]
            [lein-cljsbuild "1.1.7" :exclusions [[org.clojure/clojure]]]]

  :source-paths ["src"]

  :cljsbuild {:builds
              [{:id "dev"
                :source-paths ["src"]
                :figwheel {:on-jsload "hello-world.core/on-js-reload"
                           :open-urls ["http://localhost:3449/index.html"]}

                :compiler {:main hello-world.core
                           :asset-path "js/compiled/out"
                           :output-to "resources/public/js/compiled/hello_world.js"
                           :output-dir "resources/public/js/compiled/out"
                           :source-map-timestamp true
                           ;; To console.log CLJS data-structures make sure you enable devtools in Chrome
                           ;; https://github.com/binaryage/cljs-devtools
                           :preloads [devtools.preload]}}

               {:id "min"
                :source-paths ["src"]
                :compiler {:output-to "resources/public/js/compiled/hello_world.js"
                           :main hello-world.core
                           :optimizations :advanced
                           :pretty-print false}}]}

  :figwheel {;; :http-server-root "public" ;; default and assumes "resources"
             ;; :server-port 3449 ;; default
             ;; :server-ip "127.0.0.1"

             :css-dirs ["resources/public/css"] ;; watch and update CSS
             }

  :profiles {:dev {:dependencies [[binaryage/devtools "1.0.0"]
                                  [figwheel-sidecar "0.5.20"]]
                   ;; need to add dev source path here to get user.clj loaded
                   :source-paths ["src" "dev"]
                   ;; need to add the compiled assets to the :clean-targets
                   :clean-targets ^{:protect false} ["resources/public/js/compiled"
                                                     :target-path]}})

我們可以看到js裡的套件相依性目前有安裝 figwheel-sidecarbinaryage/devtools
也得知到,ClojureScript complier編譯為javascript後會變成這支檔案 resources/public/js/compiled/hello_world.js

啟動http-server

我們來hello-world namespace下插一句javascript的alert:

(ns hello-world.core

(js/alert "Hello Ironman!")

並且以 lein figwheel啟動http-server

~/Projects/hello-world
❯ lein figwheel

Retrieving lein-figwheel/lein-figwheel/0.5.20/lein-figwheel-0.5.20.pom from clojars
Retrieving lein-cljsbuild/lein-cljsbuild/1.1.7/lein-cljsbuild-1.1.7.pom from clojars
Retrieving lein-figwheel/lein-figwheel/0.5.20/lein-figwheel-0.5.20.jar from clojars
Retrieving lein-cljsbuild/lein-cljsbuild/1.1.7/lein-cljsbuild-1.1.7.jar from clojars
Figwheel: Cutting some fruit, just a sec ...

IT鐵人又排除萬難、順利地完成了Day21的任務了!:)

ref

ClojureScript Release - Rich Hickey
https://www.youtube.com/watch?v=tVooR-dF_Ag


上一篇
[Day20] Clojure vs Java / ClojureScript vs Javascript
下一篇
[Day22] 從ClojureScript 到 Reagent (1) React, Reagent, and why
系列文
後端Developer實戰ClojureScript: Reagent與前端框架 Reframe30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言