diff --git a/README.md b/README.md index 3e6f605..9a0853c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ finally right around the corner, all you need is this small example to get start The purpose of this example application is to show packaging capabilities of cljfx and jpackage, to keep it simple some build steps where left out: -- startup time can be improved significantly by AOT-compiling clojure code; - application package size can be reduced: you can use `jlink` to minify the JDK, and if your application does not need to use webkit (which is used in this example), you can exclude cljfx's dependency on javafx-web. @@ -38,7 +37,13 @@ window. The build process is 2-step: 1. Assemble an uberjar. Here it's done using Sean Corfield's -[depstar](https://github.com/seancorfield/depstar) library with `clj -A:uberjar` alias. +[depstar](https://github.com/seancorfield/depstar) library: + - `clj -Spom` + - `clj -X:uberjar` + +The built uberjar will include AOT-compiled code and can be executed via +`java -jar dist/hn.jar`, but we will use `jpackage` to build OS distributions: + 2. Use `jpackage` with common options described in [jpackage/common](jpackage/common) and platform-specific options having their own files: [jpackage/linux](jpackage/linux), [jpackage/mac](jpackage/mac) and [jpackage/windows](jpackage/windows). For example, if you diff --git a/build/uberjar/build.clj b/build/uberjar/build.clj new file mode 100644 index 0000000..41846a9 --- /dev/null +++ b/build/uberjar/build.clj @@ -0,0 +1,12 @@ +(ns uberjar.build + (:require [hf.depstar.uberjar]) + (:import (javafx.application Platform))) + +;; see https://github.com/cljfx/cljfx#aot-compilation-is-complicated + +(defn run + [& args] + (try + (apply hf.depstar.uberjar/run args) + (finally + (Platform/exit)))) \ No newline at end of file diff --git a/deps.edn b/deps.edn index 943ee73..3937880 100644 --- a/deps.edn +++ b/deps.edn @@ -1,7 +1,11 @@ -{:deps {cljfx {:mvn/version "1.6.7"} +{:deps {cljfx/cljfx {:mvn/version "1.6.7"} cljfx/css {:mvn/version "1.1.0"} - clj-http {:mvn/version "3.9.1"} + clj-http/clj-http {:mvn/version "3.9.1"} metosin/jsonista {:mvn/version "0.2.5"} - crouton {:mvn/version "0.1.2"}} - :aliases {:uberjar {:extra-deps {seancorfield/depstar {:mvn/version "0.5.2"}} - :main-opts ["-m" "hf.depstar.uberjar" "dist/hn.jar"]}}} \ No newline at end of file + crouton/crouton {:mvn/version "0.1.2"}} + :aliases {:uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.1.136"}} + :replace-paths ["src" "build"] + :exec-fn uberjar.build/run + :exec-args {:jar "dist/hn.jar" + :aot true + :main-class "hn.core"}}}} \ No newline at end of file diff --git a/src/hn/core.clj b/src/hn/core.clj index ad77d84..3c0d085 100644 --- a/src/hn/core.clj +++ b/src/hn/core.clj @@ -4,7 +4,8 @@ [hn.event :as event] [hn.view :as view]) (:import [javafx.application Platform] - [java.util.concurrent Executors ThreadFactory])) + [java.util.concurrent Executors ThreadFactory]) + (:gen-class)) (defn http-effect [v dispatch!] (try @@ -15,9 +16,11 @@ (fn [response] (dispatch! (assoc (:on-response v) :response response))) (fn [exception] - (dispatch! (assoc (:on-exception v) :exception exception)))) + (dispatch! (assoc (:on-exception v) ::event/type ::event/exception + :exception exception)))) (catch Exception e - (dispatch! (assoc (:on-exception v) :exception e))))) + (dispatch! (assoc (:on-exception v) ::event/type ::event/exception + :exception e))))) (def daemon-executor (let [*counter (atom 0) diff --git a/src/hn/event.clj b/src/hn/event.clj index ebd2a9f..03d8246 100644 --- a/src/hn/event.clj +++ b/src/hn/event.clj @@ -11,13 +11,16 @@ (defmulti handle ::type) +(defmethod handle ::exception [{:keys [state exception]}] + {:state (assoc state :error (.getMessage exception))}) + (defmethod handle ::load-stories [_] {:http {:method :get :url "https://hacker-news.firebaseio.com/v0/topstories.json" :on-response {::type ::process-stories}}}) (defmethod handle ::process-stories [{:keys [state response]}] - (let [stories (parse-response-body response)] + (let [stories (take 100 (parse-response-body response))] (into [[:state (assoc state :stories stories)]] (map (fn [id] [:dispatch {::type ::load-story :id id}])) diff --git a/src/hn/view.clj b/src/hn/view.clj index 368c9ce..6eaa7dc 100644 --- a/src/hn/view.clj +++ b/src/hn/view.clj @@ -53,6 +53,7 @@ "-comment" {"-cell" {:-fx-padding [small-spacing default-spacing]}} "-stories" {"-item" {:-fx-spacing small-spacing} "-cell" {:-fx-padding [small-spacing default-spacing]}}} + ".error" {:-fx-text-fill :red} ".list-cell:empty" {:-fx-background-color :transparent} ".scroll-bar" {:-fx-background-color :transparent ":vertical" {"> .increment-button > .increment-arrow" @@ -115,7 +116,7 @@ :cell-factory [:setter (fx.lifecycle/detached-prop-map fx.list-cell/props) :coerce create-cell-factory]))) -(defn stories [{:keys [stories items]}] +(defn stories [{:keys [stories items error]}] {:fx/type :v-box :children [{:fx/type :h-box @@ -126,7 +127,10 @@ :text "⟲"} {:fx/type :label :style-class "hn-title" - :text "Hacker News"}]} + :text "Hacker News"} + {:fx/type :label + :style-class "error" + :text error}]} {:fx/type ext-with-list-cell-factory :v-box/vgrow :always :props