From 8e078371add222992bba48e187bd86b7c16576d5 Mon Sep 17 00:00:00 2001 From: Miloslav Nenadal Date: Wed, 10 Jan 2024 19:52:37 +0100 Subject: [PATCH] Refactor build hook --- shadow-cljs.edn | 2 +- src/build/assets.clj | 82 ++++++++++++++++++++++++++++++++++++++++++++ src/build/hook.clj | 52 ++++++---------------------- 3 files changed, 93 insertions(+), 43 deletions(-) create mode 100644 src/build/assets.clj diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 7503ef7..622808c 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -10,7 +10,7 @@ :dev {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}} :release {:module-hash-names true} :devtools {:preloads [day8.re-frame-10x.preload]} - :build-hooks [(build.hook/hook)] + :build-hooks [(build.hook/hook {:public-dir "resources/public"})] :target :browser} :test {:target :node-test :output-to "target/node-test.js" diff --git a/src/build/assets.clj b/src/build/assets.clj new file mode 100644 index 0000000..6d98b17 --- /dev/null +++ b/src/build/assets.clj @@ -0,0 +1,82 @@ +(ns build.assets + (:require + [clojure.java.io :as io] + [build.util :as u])) + +(defn- path [s] + (java.nio.file.Paths/get s (make-array java.lang.String 0))) + +(defn- symlink [link target] + (let [link-path (path link) + target-rel (.relativize (.getParent link-path) + (path target))] + (.mkdirs (.toFile (.getParent link-path))) + (java.nio.file.Files/createSymbolicLink link-path target-rel (make-array java.nio.file.attribute.FileAttribute 0)))) + +(defn- copy [src target] + (let [target-f (io/file target)] + (.mkdirs (.getParentFile target-f)) + (io/copy + (io/file src) + target-f))) + +(defn- file-name->file-name-and-extension [s] + (let [ext-index (.lastIndexOf s ".")] + (if (== -1 ext-index) + [s] + [(.substring s 0 ext-index) (.substring s (inc ext-index))]))) + +(defn- hashed-asset [asset hash] + (let [asset-path (path asset) + dir (.getParent asset-path) + asset-file-name (.getFileName asset-path) + [asset-name asset-ext] (file-name->file-name-and-extension (.toString asset-file-name)) + target (str (when dir (str dir "/")) asset-name "." hash (when asset-ext (str "." asset-ext)))] + target)) + +(comment + (hashed-asset "app" "hash") + (hashed-asset "app.js" "hash") + (hashed-asset "js/app.js" "hash") + ;; + ) + +(defn- symlink-assets [{:keys [public-dir assets]}] + (doseq [[asset src] assets] + (symlink (str public-dir "/" asset) src)) + {}) + +(defn- hash-assets [{:keys [public-dir assets]}] + (reduce + (fn [acc [asset src]] + (let [hash (u/file-hash src) + asset-path (hashed-asset asset hash) + target (str public-dir "/" asset-path)] + (copy src target) + (assoc acc asset asset-path))) + {} + assets)) + +(defn create + "opts: + - `:public-dir` + - `:assets` - map where key is asset path and value file path" + [build-state asset-opts] + (case (:shadow.build/mode build-state) + :release (hash-assets asset-opts) + (symlink-assets asset-opts))) + +(defn from-modules + "opts: + - `:public-dir`" + [build-state {:keys [public-dir]}] + (let [output-dir (get-in build-state [:shadow.build/config :output-dir]) + path-prefix (str (.relativize + (path public-dir) + (path output-dir)) + "/")] + (-> (group-by (fn [m] + (str path-prefix (m :module-name))) + (:shadow.build.closure/modules build-state)) + (update-vals (fn [coll] + (str path-prefix (-> coll first :output-name))))))) diff --git a/src/build/hook.clj b/src/build/hook.clj index ffc9d55..19f737d 100644 --- a/src/build/hook.clj +++ b/src/build/hook.clj @@ -4,50 +4,18 @@ [build.create-manifest] [build.create-index] [build.create-worker] - [build.util :as u])) - -(defn- file->output-name [build-state] - (-> (group-by (fn [m] - (str "js/" (m :module-name))) (:shadow.build.closure/modules build-state)) - (update-vals (fn [coll] - (str "js/" (-> coll first :output-name)))))) - -(defn- path [s] - (java.nio.file.Paths/get s (make-array java.lang.String 0))) - -(defn- symlink [link target] - (let [link-path (path link) - target-rel (.relativize (.getParent link-path) - (path target))] - (.mkdirs (.toFile (.getParent link-path))) - (java.nio.file.Files/createSymbolicLink link-path target-rel (make-array java.nio.file.attribute.FileAttribute 0)))) - -(defn- copy [src target] - (let [target-f (io/file target)] - (.mkdirs (.getParentFile target-f)) - (io/copy - (io/file src) - target-f))) - -(defn- create-styles [build-mode] - (let [src "resources/private/css/styles.css"] - (case build-mode - :release - (let [hash (u/file-hash src) - target (str "resources/public/css/styles." hash ".css")] - (copy src target) - {"css/styles.css" (str "css/styles." hash ".css")}) - (do - (symlink "resources/public/css/styles.css" src) - {})))) + [build.assets :as assets])) (defn hook {:shadow.build/stage :flush} - [build-state & _args] + [build-state {:keys [public-dir]}] (when-not (.exists (io/file "resources/public/worker.js")) - (let [outputs (merge (file->output-name build-state) - (create-styles (:shadow.build/mode build-state)))] - (spit "resources/public/manifest.json" (build.create-manifest/render outputs)) - (spit "resources/public/index.html" (build.create-index/render outputs)) - (spit "resources/public/worker.js" (build.create-worker/render outputs)))) + (let [assets (merge (assets/from-modules build-state {:public-dir public-dir}) + (assets/create + build-state + {:public-dir public-dir + :assets {"css/styles.css" "resources/private/css/styles.css"}}))] + (spit "resources/public/manifest.json" (build.create-manifest/render assets)) + (spit "resources/public/index.html" (build.create-index/render assets)) + (spit "resources/public/worker.js" (build.create-worker/render assets)))) build-state)