Skip to content

Instantly share code, notes, and snippets.

View mhuebert's full-sized avatar

Matt Huebert mhuebert

View GitHub Profile
mhuebert / example.clj
Last active May 16, 2022 15:16 — forked from jvtrigueros/example.clj
Choosing a directory and setting setting a text label
(ns example
[cljfx.api :as fx])
(javafx.stage DirectoryChooser)))
(def *state (atom {:directory nil}))
(defmulti event-handler :event/type)
mhuebert / use_mutable_source.cljs
Last active March 5, 2020 20:03
useMutableSource with a Clojure atom - debugging example
;; Simple ClojureScript example of useMutableSource
;; (just basic usage - does not demonstrate multiple views on the same store)
(def my-store
(atom 0))
(defn get-snapshot [store]
(prn :get-snapshot store)
mhuebert /
Created August 7, 2019 17:48 — forked from raymcdermott/
Adhoc CLJS dependency generation


A conversation started at the Heart of Clojure conference in Belgium on Friday August 2nd 2019.

The group represented project owners from Maria.Cloud, Next.Journal, Klipse and Replete-Web. The projects make significant use of self-hosted CLJS.

This is a proposal to have a service that generates and caches JS files for a specific CLJS dependency (name & version).


The ClojureScript compiler generates JS files for each of an apps stated CLJS dependencies. The runtime environment then loads each of the needed JS files to satisfy the dependency at runtime.

mhuebert /
Last active April 24, 2024 09:41
shadow-cljs build hook for purgecss

purgecss is a tool for removing unused css classes from source files. It's particularly useful for functional css frameworks like tachyons, where it's normal to only use a tiny fraction of available classes. This gist contains example code you could use to add purgecss to a shadow-cljs build.

  • make sure to yarn add purgecss first
  • usage is (hooks/purge-css {:css-source __ :js-globs __ :out-dir __})
    • :css-source is the path to the original, bloated CSS file (from project root). This is ideally in a source directory, or node_modules as in this example. This cannot be the public path where the css is ultimately read.
  • :js-globs is a string / vector of strings, indicating which files to read as input. These should be all of your compiled javascript bundles which contain your views. purgecss does a brute-force parse of all these files, extracting all the strings to figure out which clas
;; sexp
;; reader-char
;; regex
;; number
;; special-form
mhuebert / eg.clj
Created March 17, 2019 09:53
tabular formatting wish
;; `table` configured with indent-1 and "align-tabular"
(table {:size [3 3]}
'_ "| " "|[ ]" "[|]"
[:cursor/move :x 1] " |" "[| ]" "[]|"
[:cursor/move :x -1] "| " "|[ ]" "[]")
;; just for context - one might compile ^that to
;; something like the following
(fn [x y]
mhuebert /
Last active October 19, 2023 06:09
clj(s) environment config w/ Shadow-CLJS using a build hook


  • Load config conditionally, based on a release flag passed in at the command line. We use juxt/aero to read a static config.edn file, passing in the release flag as aero's :profile.
  • Config should be exposed at runtime (in the browser / cljs) and macro-expansion time (clj). We store config in a plain map, app.env/config. Our build hook,, updates this using alter-var-root!.
  • Whenever config has changed, shadow-cljs must invalidate its caches so that changes are picked up immediately. We do this in by putting the current environment in the shadow build state, under [:compiler-options :external-config ::env].

Why this approach?

  • Reading config directly from macros breaks compiler caching - changing config will not cause changes to propagate to the build.
  • :clojure-defines (ie. goog-define) are not exposed in clj, & therefore can't be used by macros. We want one single way to expose config that
mhuebert / deps.edn
Last active February 1, 2019 14:43
{:deps {chia {:git/url ""
:sha "885e84e84b39836a9cb12bc3b90880dc25a11482"}}}
mhuebert /
Last active March 1, 2024 16:55
material-ui's CSS-in-JS with Reagent. (see

material-ui allows for customizing CSS via a higher-order component called withStyles. Like many higher-order components which expect render props, the purpose of withStyles is to accept some parameters, and then introduce a new variable into the scope of the component tree.

One succinct and simple way to translate the concept of scope into Clojure is via a custom let macro. Usage of such a macro is demonstrated here:

(:require [material-ui.styles :as m])

(m/let [{:keys [leftPad]} {:leftPad 
                           {:paddingLeft 8}}]
 ;; `leftPad` is now the _className_ associated with {:paddingLeft 8} 
mhuebert / React Contexts with
Last active October 30, 2020 14:15
React contexts with Reagent

The following provide and consume Reagent components expose React contexts without fuss.


(:require [example.reagent-context :as c])

;; in a component, use `provide` to supply values for contexts:
[c/provide {:app-theme {:color "blue"}}
 ;; consume one context at a time