|  | (ns my.myfw | 
        
          |  | " | 
        
          |  | We make this a real namespace so we can develop this file interactively with Cursive. | 
        
          |  |  | 
        
          |  | Run me so: | 
        
          |  | lein with-profile +dev-cljs run -m clojure.main scripts/fw+cljs.clj dev | 
        
          |  | lein with-profile +dev-cljs run -m clojure.main scripts/fw+cljs.clj production | 
        
          |  | or for figwheel: | 
        
          |  | 1. Start a normal nrepl with lein: | 
        
          |  | lein with-profile +dev-cljs repl :start :port YOUR_PORT | 
        
          |  | 2. Connect to it from Cursive, Emacs etc... | 
        
          |  | 3. Enter: (load-file \"scripts/fw+cljs\") | 
        
          |  |  | 
        
          |  | Assumes you have a local server running which maps requests to: | 
        
          |  | http://localhost:10083/dev/compress/resources/public/js/ | 
        
          |  |  | 
        
          |  | For instance for nginx: | 
        
          |  | location /dev/compress/resources/public/js/ { | 
        
          |  | allow 127.0.0.1; | 
        
          |  | alias ../../resources/public/js/; | 
        
          |  | } | 
        
          |  | Should understand gzip and brotli compression. | 
        
          |  |  | 
        
          |  | This build script outputs all {raw,gzip,brotli} sizes to the root directory in | 
        
          |  | size-hist.your-out-file.js | 
        
          |  | " | 
        
          |  | (:require [cljs.build.api :as api] | 
        
          |  | [clojure.pprint :as pprint] | 
        
          |  | [clojure.java.io :as io]) | 
        
          |  | (:import (java.io File FileFilter) | 
        
          |  | (java.util Date Scanner) | 
        
          |  | (java.net URL))) | 
        
          |  | #_(clojure.java.classpath/classpath) | 
        
          |  |  | 
        
          |  | (def build-id | 
        
          |  | (keyword (first *command-line-args*))) | 
        
          |  |  | 
        
          |  | (def module-id | 
        
          |  | (second *command-line-args*)) | 
        
          |  |  | 
        
          |  | (println "Got build id: " build-id) | 
        
          |  | (println "Current ns: " (str *ns*)) | 
        
          |  |  | 
        
          |  | (defn err [msg] | 
        
          |  | (println msg) | 
        
          |  | (System/exit 1)) | 
        
          |  |  | 
        
          |  | (defn ls-match | 
        
          |  | "Given the directory handle d, lists all files matching the given | 
        
          |  | regex. Returns the Java File instances. | 
        
          |  | Example: | 
        
          |  | (ls-match (File. \"./dir\") #\"(?i).drl$\")" | 
        
          |  | ([^File d] | 
        
          |  | (ls-match d #"^[~_.]")) | 
        
          |  | ([^File d regex] | 
        
          |  | (.listFiles d | 
        
          |  | (reify | 
        
          |  | FileFilter | 
        
          |  | (accept [this f] | 
        
          |  | (and | 
        
          |  | (.isFile f) | 
        
          |  | (boolean (re-find regex (.getName f))))))))) | 
        
          |  |  | 
        
          |  | (def externs | 
        
          |  | (mapv | 
        
          |  | #(.getCanonicalPath ^File %) | 
        
          |  | (ls-match (io/file (io/resource "externs")) #"(?i)\.js$"))) | 
        
          |  |  | 
        
          |  | (def src-paths-common ["src/cljs" "src/cljc"]) | 
        
          |  | (def src-paths-dev (conj src-paths-common "env/dev/cljs")) | 
        
          |  | (def src-paths-prod (conj src-paths-common "env/prod/cljs")) | 
        
          |  |  | 
        
          |  | (defn compressed-size [^String url ^String accept-encoding] | 
        
          |  | (future | 
        
          |  | (.length | 
        
          |  | (.next | 
        
          |  | (.useDelimiter | 
        
          |  | (Scanner. | 
        
          |  | (.getInputStream | 
        
          |  | (doto | 
        
          |  | (.openConnection | 
        
          |  | (URL. url)) | 
        
          |  | (.setRequestProperty "Accept-Encoding" accept-encoding)))) | 
        
          |  | "\\Z"))))) | 
        
          |  |  | 
        
          |  | (defn log-size-history [^String output-to ^File out-file] | 
        
          |  | (future | 
        
          |  | (let [url (str "http://localhost:10083/dev/compress/" output-to) | 
        
          |  | brotli-size (compressed-size url "br") | 
        
          |  | gzip-size (compressed-size url "gzip") | 
        
          |  | size (.length out-file) | 
        
          |  | stats-str (prn-str {:date (Date.) | 
        
          |  | :size size | 
        
          |  | :gzip-size @gzip-size | 
        
          |  | :brotli-size @brotli-size})] | 
        
          |  | (println "DONE: " output-to) | 
        
          |  | (println stats-str) | 
        
          |  | (spit (str "size-hist." (.getName out-file)) | 
        
          |  | stats-str | 
        
          |  | :append true)))) | 
        
          |  |  | 
        
          |  | (defn watch-fn-stats [output-to] | 
        
          |  | (fn [] | 
        
          |  | (let [f (io/file output-to)] | 
        
          |  | (log-size-history output-to f)))) | 
        
          |  |  | 
        
          |  | (defn output-dir [build-id] | 
        
          |  | (str "resources/public/js/" (name build-id) "/compiled/out")) | 
        
          |  |  | 
        
          |  | (defn output-to [build-id module] | 
        
          |  | (str "resources/public/js/" (name build-id) "/compiled/" (name module) ".js")) | 
        
          |  |  | 
        
          |  | (defn source-map [out-file] | 
        
          |  | (str out-file ".map")) | 
        
          |  |  | 
        
          |  | (defn source-paths [cfg] | 
        
          |  | (case cfg | 
        
          |  | :dev src-paths-dev | 
        
          |  | :production src-paths-prod)) | 
        
          |  |  | 
        
          |  | (defn figwheel-cfg [cfg] | 
        
          |  | (when (= :dev cfg) | 
        
          |  | {:figwheel {:websocket-host "localhost" | 
        
          |  | :on-jsload "srs-c.dev/on-js-reload"}})) | 
        
          |  |  | 
        
          |  | (defn compiler-cfg [cfg module] | 
        
          |  | (let [out (output-to cfg module) | 
        
          |  | prod-false (get {:production false} cfg true) | 
        
          |  | prod-true (not prod-false)] | 
        
          |  | (->> | 
        
          |  | (merge | 
        
          |  | {:output-to out | 
        
          |  | :output-dir (output-dir cfg) | 
        
          |  | :compiler-stats true | 
        
          |  | :pretty-print prod-false | 
        
          |  | :elide-asserts prod-true | 
        
          |  | :source-map (get {:production (source-map out) | 
        
          |  | :dev true} cfg true) | 
        
          |  | :closure-defines {"goog.DEBUG" prod-false} | 
        
          |  | :externs externs} | 
        
          |  |  | 
        
          |  | (case cfg | 
        
          |  | :dev | 
        
          |  | {:main "srs-c.dev" | 
        
          |  | ;; :asset-path is a relative URL path not a file system path. | 
        
          |  | ;; This is prepended to the goog.require loads. So it's part of a URL: | 
        
          |  | :asset-path "/js/dev/compiled/out" ;; See :output-dir | 
        
          |  | :anon-fn-naming-policy :mapped | 
        
          |  | :optimizations :none | 
        
          |  | :source-map-timestamp true} | 
        
          |  | ;;;;;;;;;;;;;;;;;;;;;;;;;; | 
        
          |  | :production | 
        
          |  | {:main (str "srs-c.modules." module) | 
        
          |  | :optimizations :advanced | 
        
          |  | ;; False is almost no difference in brotli size. Performance? | 
        
          |  | :optimize-constants true | 
        
          |  | :pseudo-names false | 
        
          |  | :watch-fn (watch-fn-stats out)})) | 
        
          |  | (into (sorted-map))))) | 
        
          |  | #_(compiler-cfg :dev "src-c.dev") | 
        
          |  | #_(compiler-cfg :production "login") | 
        
          |  |  | 
        
          |  | (defn build-config | 
        
          |  | [cfg module] | 
        
          |  | (merge | 
        
          |  | {:source-paths (source-paths cfg)} | 
        
          |  | (figwheel-cfg cfg) | 
        
          |  | {:compiler (compiler-cfg cfg module)})) | 
        
          |  | #_(build-config :dev "srs-c.dev") | 
        
          |  | #_(build-config :production "login") | 
        
          |  |  | 
        
          |  | (defn start-compiler [build] | 
        
          |  | (pprint/pprint build) | 
        
          |  | (api/watch | 
        
          |  | (apply api/inputs (:source-paths build)) | 
        
          |  | (:compiler build))) | 
        
          |  |  | 
        
          |  | (defn build-cljs [build-id module] | 
        
          |  | (if-let [build (build-config build-id module)] | 
        
          |  | (start-compiler build) | 
        
          |  | (err "No such build id"))) | 
        
          |  |  | 
        
          |  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 
        
          |  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 
        
          |  | (defn run-figwheel [] | 
        
          |  | ;; We may not have figwheel in our classpath if we do cljs compilation: | 
        
          |  | (let [fw-api 'figwheel-sidecar.repl-api | 
        
          |  | _ (require fw-api) | 
        
          |  | start-fw (ns-resolve fw-api 'start-figwheel!) | 
        
          |  | cljs-repl (ns-resolve fw-api 'cljs-repl)] | 
        
          |  | (start-fw | 
        
          |  | {:build-ids ["dev"] ;; vector of build ids to start autobuilding | 
        
          |  | :all-builds [(assoc (build-config :dev nil) :id "dev")] | 
        
          |  | :figwheel-options | 
        
          |  | {:websocket-host "localhost" | 
        
          |  | ;; The port of the fighweel server, the browser connects to this: | 
        
          |  | :server-port 22341 | 
        
          |  | ;; The bind IP of the figwheel server | 
        
          |  | :server-ip "127.0.0.1" | 
        
          |  | :load-warninged-code true | 
        
          |  | ;;:nrepl-port 22345 | 
        
          |  | ;;:nrepl-middleware ["cemerick.piggieback/wrap-cljs-repl"] | 
        
          |  | }}) | 
        
          |  | (cljs-repl))) | 
        
          |  |  | 
        
          |  | (if build-id | 
        
          |  | (build-cljs build-id module-id) | 
        
          |  | (run-figwheel)) | 
  
Probably want to remove
watch-fn-statsfrom the watch key if you don't have a server like that.