<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:a="http://www.w3.org/2005/Atom">
  <title>Coruscation.net</title>
  <link href="https://coruscation.net"/>
  <updated>2026-01-26T05:09:29+08:00</updated>
  <author>imakira</author>
  <id>https://coruscation.net</id>
  <entry>
    <title type="html">About Dynamic Adding to Classpath in Clojure</title>
    <link href="https://coruscation.net/blogs/about-dynamic-adding-to-classpath-in-clojure.html"/>
    <published>2026-01-25T00:00:00+08:00</published>
    <updated>2026-01-26T05:09:29+08:00</updated>
    <id>https://coruscation.net/blogs/about-dynamic-adding-to-classpath-in-clojure.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
Well, I guess people will just inevitably get into the problem of &lt;code&gt;classpath&lt;/code&gt;, one way or another. &lt;a href="https://lambdaisland.com/blog/2021-08-25-classpath-is-a-lie"&gt;The Classpath is a Lie&lt;/a&gt; described the problem very well: &lt;i&gt;classpath is a lie&lt;/i&gt;. &lt;code&gt;classpath&lt;/code&gt;, &lt;i&gt;per se&lt;/i&gt;, is a simple list separated by colons, however, the real work is done by the &lt;code&gt;Classloader&lt;/code&gt;.
&lt;/p&gt;&lt;p&gt;
Nevertheless, this isn&amp;#x27;t a post talking about &lt;code&gt;classpath&lt;/code&gt; and &lt;code&gt;ClassLoader&lt;/code&gt;. There are already a lot of great articles talking about it (&lt;a href="#links"&gt;links&lt;/a&gt; at the end of this post), and I can&amp;#x27;t claim I understand &lt;code&gt;ClassLoaders&lt;/code&gt; to the extent that I can confidently teach others about it either.
&lt;/p&gt;&lt;p&gt;
This is a blog about what I have found during the process of trying to add new directories to &lt;code&gt;classpath&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; Clojure files in them at runtime. &lt;code&gt;ClassLoader&lt;/code&gt; in Clojure is something very messy. The best strategy probably is to avoid the problem altogether. But still, if you really want to do it, I wish the following content can offer some help.
&lt;/p&gt;&lt;div id="outline-container-use-builtin-~clojure.core/add-classpath~" class="outline-2"&gt;&lt;a href="#use-builtin-~clojure.core/add-classpath~"&gt;&lt;h2 id="use-builtin-~clojure.core/add-classpath~" class="cr-self-reference "&gt;Use Builtin &lt;code&gt;clojure.core/add-classpath&lt;/code&gt;&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-use-builtin-~clojure.core/add-classpath~" class="outline-text-2"&gt;&lt;p&gt;&lt;code&gt;Clojure&lt;/code&gt; has a builtin &lt;code&gt;add-classpath&lt;/code&gt; function. Although it has been deprecated, it works for simple use cases.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;check-dynamic-load&lt;/span&gt; []
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [tmp-dir (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; (&lt;span class="hljs-name"&gt;Files/createTempDirectory&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;classpath-demo&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; java.nio.file.attribute.FileAttribute [])))
        tmp-clj (&lt;span class="hljs-name"&gt;File/createTempFile&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;demo&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;.clj&amp;quot;&lt;/span&gt; tmp-dir)
        tmp-name (&lt;span class="hljs-name"&gt;subs&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getName&lt;/span&gt; tmp-clj)
                       &lt;span class="hljs-number"&gt;0&lt;/span&gt;
                       (&lt;span class="hljs-name"&gt;.lastIndexOf&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getName&lt;/span&gt; tmp-clj)
                                     &lt;span class="hljs-string"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;))]
    &lt;span class="hljs-comment"&gt;;; Add `tmp-dir` to `classpath` using builtin `add-classpath`.&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;add-classpath&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toURL&lt;/span&gt; tmp-dir))

    &lt;span class="hljs-comment"&gt;;; Put a Clojure file under the directory&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;spit&lt;/span&gt; tmp-clj
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;(ns &amp;quot;&lt;/span&gt; tmp-name &lt;span class="hljs-string"&gt;&amp;quot;) (def a 1)&amp;quot;&lt;/span&gt;))
                                        &lt;span class="hljs-comment"&gt;;&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;;; `require` the Clojure file, and resolve the variable&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assert&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt; (&lt;span class="hljs-name"&gt;var-get&lt;/span&gt; (&lt;span class="hljs-name"&gt;requiring-resolve&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; tmp-name
                                                     &lt;span class="hljs-string"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;)))))

    &lt;span class="hljs-comment"&gt;;; Update the Clojure file&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;spit&lt;/span&gt; tmp-clj
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;(ns &amp;quot;&lt;/span&gt; tmp-name &lt;span class="hljs-string"&gt;&amp;quot;) (def a 2)&amp;quot;&lt;/span&gt;))

    &lt;span class="hljs-comment"&gt;;; Reload the Clojure file&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;require&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; tmp-name)
             &lt;span class="hljs-symbol"&gt;:reload-all&lt;/span&gt;)

    &lt;span class="hljs-comment"&gt;;; We can read the new value&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assert&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; (&lt;span class="hljs-name"&gt;var-get&lt;/span&gt; (&lt;span class="hljs-name"&gt;requiring-resolve&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; tmp-name
                                                     &lt;span class="hljs-string"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;)))))
    (&lt;span class="hljs-name"&gt;println&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;success&amp;quot;&lt;/span&gt;)))

&lt;span class="hljs-comment"&gt;;; success&lt;/span&gt;
(&lt;span class="hljs-name"&gt;check-dynamic-load&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
If we evaluate the above code in a REPL or in cider, it works and prints &amp;quot;success&amp;quot;. As we can see from the code, we can &lt;code&gt;require&lt;/code&gt; a Clojure file whose path determined at runtime, and reload it to get the updated value.
&lt;/p&gt;&lt;p&gt;
However, there is a reason of it being deprecated. We can check its source code:
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-java"&gt;&lt;span class="hljs-comment"&gt;// The method used by clojure.core/add-classpath&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;static&lt;/span&gt; &lt;span class="hljs-keyword"&gt;public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;void&lt;/span&gt; &lt;span class="hljs-title function_"&gt;addURL&lt;/span&gt;&lt;span class="hljs-params"&gt;(Object url)&lt;/span&gt; &lt;span class="hljs-keyword"&gt;throws&lt;/span&gt; MalformedURLException{
      &lt;span class="hljs-type"&gt;URL&lt;/span&gt; &lt;span class="hljs-variable"&gt;u&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; (url &lt;span class="hljs-keyword"&gt;instanceof&lt;/span&gt; String) ? toUrl((String) url) : (URL) url;
      &lt;span class="hljs-type"&gt;ClassLoader&lt;/span&gt; &lt;span class="hljs-variable"&gt;ccl&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; Thread.currentThread().getContextClassLoader();
      &lt;span class="hljs-keyword"&gt;if&lt;/span&gt;(ccl &lt;span class="hljs-keyword"&gt;instanceof&lt;/span&gt; DynamicClassLoader)
              ((DynamicClassLoader)ccl).addURL(u);
      &lt;span class="hljs-keyword"&gt;else&lt;/span&gt;
              &lt;span class="hljs-keyword"&gt;throw&lt;/span&gt; &lt;span class="hljs-keyword"&gt;new&lt;/span&gt; &lt;span class="hljs-title class_"&gt;IllegalAccessError&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;quot;Context classloader is not a DynamicClassLoader&amp;quot;&lt;/span&gt;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
It checks if the current thread&amp;#x27;s &lt;code&gt;ContextClassLoader&lt;/code&gt; is a &lt;code&gt;DynamicClassLoader&lt;/code&gt;. If so, it will call the &lt;code&gt;DynamicClassLoader&lt;/code&gt;&amp;#x27;s &lt;code&gt;addURL&lt;/code&gt; method.
That means, this method will fail if there&amp;#x27;s some code set the current &lt;code&gt;ContextClassLoader&lt;/code&gt; to something other than a &lt;code&gt;DynamicClassLoader&lt;/code&gt;.
&lt;/p&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
We expect &lt;code&gt;add-classpath&lt;/code&gt; continues to work in case because the convention of setting a new &lt;code&gt;ClassLoader&lt;/code&gt; is to set the current &lt;code&gt;ClassLoader&lt;/code&gt; as the parent of the newly created &lt;code&gt;ClassLoader&lt;/code&gt;. However, &lt;code&gt;clojure.core/add-classpath&lt;/code&gt; only checks the current &lt;code&gt;ClassLoader&lt;/code&gt;, more on this in the section.
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [future
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;future&lt;/span&gt;&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [cl (&lt;span class="hljs-name"&gt;.getContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;))]
          (&lt;span class="hljs-name"&gt;.setContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;)
                                  (&lt;span class="hljs-name"&gt;java.net.URLClassLoader.&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; java.net.URL [])
                                                            cl)))
            (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;try&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;check-dynamic-load&lt;/span&gt;)
             (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assert&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;unreachable&amp;quot;&lt;/span&gt;)
             (&lt;span class="hljs-name"&gt;catch&lt;/span&gt; Throwable t
               (&lt;span class="hljs-name"&gt;println&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;dynamic loading failed&amp;quot;&lt;/span&gt;))))]
  &lt;span class="hljs-comment"&gt;;; &amp;quot;dynamic loading failed&amp;quot;&lt;/span&gt;
  @future)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-use-~add-classpath~-from-~pomegranate~" class="outline-2"&gt;&lt;a href="#use-~add-classpath~-from-~pomegranate~"&gt;&lt;h2 id="use-~add-classpath~-from-~pomegranate~" class="cr-self-reference "&gt;Use &lt;code&gt;add-classpath&lt;/code&gt; from &lt;code&gt;pomegranate&lt;/code&gt;&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-use-~add-classpath~-from-~pomegranate~" class="outline-text-2"&gt;&lt;p&gt;&lt;a href="https://github.com/clj-commons/pomegranate"&gt;pomegranate&lt;/a&gt; provides a &lt;code&gt;add-classpath&lt;/code&gt; that solves the problem described in the previous section.
&lt;/p&gt;&lt;p&gt;
The only thing we need to change is to replace &lt;code&gt;clojure.core/add-classpath&lt;/code&gt; with &lt;code&gt;cemerick.pomegranate/add-classpath&lt;/code&gt;.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;ns&lt;/span&gt;&lt;/span&gt; demo
  (&lt;span class="hljs-symbol"&gt;:require&lt;/span&gt;
   [cemerick.pomegranate &lt;span class="hljs-symbol"&gt;:as&lt;/span&gt; pomegranate]))

(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;check-dynamic-load-using-pomegranate&lt;/span&gt; []
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [&lt;span class="hljs-comment"&gt;;; ...&lt;/span&gt;
        ]
    &lt;span class="hljs-comment"&gt;;; same code as `check-dynamic-load`&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;pomegranate/add-classpath&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toURL&lt;/span&gt; tmp-dir))
    &lt;span class="hljs-comment"&gt;;; same code as `check-dynamic-load`&lt;/span&gt;
    ))

(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [future
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;future&lt;/span&gt;&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [cl (&lt;span class="hljs-name"&gt;.getContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;))]
          (&lt;span class="hljs-name"&gt;.setContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;)
                                  (&lt;span class="hljs-name"&gt;java.net.URLClassLoader.&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; java.net.URL [])
                                                            cl)))
        (&lt;span class="hljs-name"&gt;check-dynamic-load-using-pomegranate&lt;/span&gt;)
        (&lt;span class="hljs-name"&gt;print&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;success&amp;quot;&lt;/span&gt;))]
  &lt;span class="hljs-comment"&gt;;; success&lt;/span&gt;
  @future)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
Unlike &lt;code&gt;add-classpath&lt;/code&gt; from &lt;code&gt;clojure.core&lt;/code&gt;, &lt;code&gt;pomegranate&lt;/code&gt;&amp;#x27;s &lt;code&gt;add-classpath&lt;/code&gt; try to find the &lt;code&gt;ClassLoader&lt;/code&gt; closest to the &lt;i&gt;Primordial ClassLoader&lt;/i&gt; that is compatible with &lt;code&gt;add-classpath&lt;/code&gt;, and call the &lt;code&gt;addURL&lt;/code&gt; method from it.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;span class="hljs-comment"&gt;;; in `add-classpath` function in pomegranate.clj  &lt;/span&gt;
(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [classloaders (&lt;span class="hljs-name"&gt;classloader-hierarchy&lt;/span&gt;)]
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if-let&lt;/span&gt;&lt;/span&gt; [cl (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;last&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;filter&lt;/span&gt;&lt;/span&gt; modifiable-classloader? classloaders))]
        (&lt;span class="hljs-name"&gt;add-classpath&lt;/span&gt; jar-or-dir cl)
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;throw&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;IllegalStateException.&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Could not find a suitable classloader to modify from &amp;quot;&lt;/span&gt;
                                            (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;mapv&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [^ClassLoader c]
                                                    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; c .getClass .getSimpleName))
                                                  classloaders))))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-create-a-~dynamicclassloader~-when-there-isn't-one" class="outline-2"&gt;&lt;a href="#create-a-~dynamicclassloader~-when-there-isn&amp;#x27;t-one"&gt;&lt;h2 id="create-a-~dynamicclassloader~-when-there-isn't-one" class="cr-self-reference "&gt;Create a &lt;code&gt;DynamicClassLoader&lt;/code&gt; When There isn&amp;#x27;t One&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-create-a-~dynamicclassloader~-when-there-isn't-one" class="outline-text-2"&gt;&lt;p&gt;
If you are running Clojure in REPL or with &lt;code&gt;nrepl&lt;/code&gt;, the &lt;code&gt;ContextClassLoader&lt;/code&gt; of the current thread will certainly be &lt;code&gt;DynamicClassLoader&lt;/code&gt;, set by one of those tools. However, when you run &lt;code&gt;clj&lt;/code&gt; command in a non-interactive manner, or use a AOT-compiled jar file, this wouldn&amp;#x27;t be the case.
&lt;/p&gt;&lt;p&gt;
This problem is quite easy to solve, we just need to set the &lt;code&gt;ContextClassLoader&lt;/code&gt; to a &lt;code&gt;DynamicClassLoader&lt;/code&gt; created by ourselves in the entrypoint of the program.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;-main&lt;/span&gt; [&amp;amp; args]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [cl (&lt;span class="hljs-name"&gt;.getContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;))]
    (&lt;span class="hljs-name"&gt;.setContextClassLoader&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/currentThread&lt;/span&gt;) (&lt;span class="hljs-name"&gt;clojure.lang.DynamicClassLoader.&lt;/span&gt; cl)))
  &lt;span class="hljs-comment"&gt;;; other code...&lt;/span&gt;
  )
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-when-using-~kaocha~" class="outline-2"&gt;&lt;a href="#when-using-~kaocha~"&gt;&lt;h2 id="when-using-~kaocha~" class="cr-self-reference "&gt;When Using &lt;code&gt;kaocha&lt;/code&gt;&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-when-using-~kaocha~" class="outline-text-2"&gt;&lt;p&gt;
So far, so good. Except when you finish the code and try to test some code and run it under the &lt;a href="https://github.com/lambdaisland/kaocha"&gt;kaocha&lt;/a&gt; test runner. &lt;code&gt;kaocha&lt;/code&gt; also did its own thing with &lt;code&gt;ClassLoader&lt;/code&gt; and provides a &lt;code&gt;add-classpath&lt;/code&gt; method. It breaks the previous method.
&lt;/p&gt;&lt;p&gt;
By detecting &lt;code&gt;kaocha&lt;/code&gt;&amp;#x27;s presence and calling its &lt;code&gt;add-classpath&lt;/code&gt;, alongside with the &lt;code&gt;pomegranate&lt;/code&gt; one solves the issue for me.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;find-ns&lt;/span&gt; &amp;#x27;kaocha.classpath)
  ((&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;intern&lt;/span&gt;&lt;/span&gt; &amp;#x27;kaocha.classpath
           &amp;#x27;add-classpath)
   new-path))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-pitfall-when-using-a-threadpool" class="outline-2"&gt;&lt;a href="#pitfall-when-using-a-threadpool"&gt;&lt;h2 id="pitfall-when-using-a-threadpool" class="cr-self-reference "&gt;Pitfall When Using a Threadpool&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-pitfall-when-using-a-threadpool" class="outline-text-2"&gt;&lt;p&gt;
When you create a thread, the new thread will inherit the &lt;code&gt;ContextClassLoader&lt;/code&gt; of the thread created it. However when you explicitly or implicitly (like when using &lt;code&gt;future&lt;/code&gt;) use a threadpool, the executor may choose an existing thread, which could have a &lt;code&gt;ContextClassLoader&lt;/code&gt; different from the calling thread.
&lt;/p&gt;&lt;p&gt;
You may consider creating a thread directly instead of relying on &lt;code&gt;future&lt;/code&gt; in this case.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doto&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;Thread/new&lt;/span&gt;
       (&lt;span class="hljs-name"&gt;bound-fn&lt;/span&gt; []
         &lt;span class="hljs-comment"&gt;;; code&lt;/span&gt;
         ))
  (&lt;span class="hljs-name"&gt;.start&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-a-few-more-words" class="outline-2"&gt;&lt;a href="#a-few-more-words"&gt;&lt;h2 id="a-few-more-words" class="cr-self-reference "&gt;A Few More Words&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-a-few-more-words" class="outline-text-2"&gt;&lt;p&gt;
This post is definitely not comprehensive, and there are still a lot things I currently do not understand. The method I have described works for me for now. If you want to understand more about this topic, I have listed a few links below.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-links" class="outline-2"&gt;&lt;a href="#links"&gt;&lt;h2 id="links" class="cr-self-reference "&gt;Links&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-links" class="outline-text-2"&gt;&lt;ol class="org-ol"&gt;&lt;li&gt;&lt;a href="https://www.infoworld.com/article/2171026/find-a-way-out-of-the-classloader-maze.html"&gt;Find a way out of the ClassLoader maze&lt;/a&gt; (2003)&lt;/li&gt;&lt;li&gt;&lt;a href="https://danielsz.github.io/2021-05-12T13_24.html"&gt;Once Upon a Class&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://lambdaisland.com/blog/2021-08-25-classpath-is-a-lie"&gt;The Classpath is a Lie&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Something Like MDX but with Clojure and Org-Mode for My Personal Blog: Part I</title>
    <link href="https://coruscation.net/blogs/something-like-mdx-but-with-clojure-and-org-mode-for-my-personal-blog--part-i.html"/>
    <published>2026-01-03T01:47:09+08:00</published>
    <updated>2026-01-03T15:10:59+08:00</updated>
    <id>https://coruscation.net/blogs/something-like-mdx-but-with-clojure-and-org-mode-for-my-personal-blog--part-i.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;&lt;a href="https://mdxjs.com/"&gt;MDX&lt;/a&gt; is a tool lets you write JavaScript and JSX in a Markdown file. It will then compile the Markdown file into a JavaScript file, so that we can use it from other JavaScript code. I always wanted something similar for my personal blog. For some background, the blogging program is written in Clojure/ClojureScript. The blogging program runs on the JVM, it works by statically generating all the HTML and other files so that the result could be hosted on platforms like Github Pages. Posts of my blog are written in &lt;a href="https://orgmode.org"&gt;org-mode&lt;/a&gt;. As the blog program runs on the JVM, directly using MDX is theoratically possible, but probably would create a lot of frictions.
&lt;/p&gt;&lt;p&gt;
Therefore I took some time to implement something similar. Albeit it is not fully tested, the result is quite satisfactory: I can embed Clojure code directly in an Org file, or use React components defined in Clojure code with native Org syntax. The Org file can then be converted into a Cljc file and used from other Clojure code.
&lt;/p&gt;&lt;p&gt;
In the following sections I will call it &lt;code&gt;OrgX&lt;/code&gt;.
&lt;/p&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-lime-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
&lt;i&gt;This is part &lt;b&gt;one&lt;/b&gt; of the series, in this post I will show the features and in the next post I will describe the process of implementing it&lt;/i&gt;
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div id="outline-container-how-orgx-works" class="outline-2"&gt;&lt;a href="#how-orgx-works"&gt;&lt;h2 id="how-orgx-works" class="cr-self-reference "&gt;How OrgX Works&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-how-orgx-works" class="outline-text-2"&gt;&lt;p&gt;
Similar to MDX, OrgX works by compiling the OrgX file into a &lt;a href="https://clojure.org/guides/reader_conditionals"&gt;Cljc&lt;/a&gt; file. A basic OrgX file would look like this:
&lt;/p&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;example.org:&lt;/i&gt;&lt;pre id="orgc3c59e4" class="example"&gt;#+ORGX: true

/*Hello* from @@orgx:($ :span &amp;quot;OrgX&amp;quot;)@@/

#+begin_orgx
($ :div (str &amp;quot;Hello&amp;quot; &amp;quot; World!&amp;quot;))
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;p&gt;
It will be converted into something similar to the following Clojure snippet.
&lt;/p&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;orgx/example.cljc:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;ns&lt;/span&gt;&lt;/span&gt; orgx.example
  (&lt;span class="hljs-symbol"&gt;:require&lt;/span&gt; [uix.core &lt;span class="hljs-symbol"&gt;:as&lt;/span&gt; uix &lt;span class="hljs-symbol"&gt;:refer&lt;/span&gt;
             [defui use-state use-effect use-context $]]))

(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; _comp [post-props]
  ($ &lt;span class="hljs-symbol"&gt;:&amp;lt;&amp;gt;&lt;/span&gt;
     ($ &lt;span class="hljs-symbol"&gt;:p&lt;/span&gt; {} ($ &lt;span class="hljs-symbol"&gt;:i&lt;/span&gt; {}
                 ($ &lt;span class="hljs-symbol"&gt;:b&lt;/span&gt; {} &lt;span class="hljs-string"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;)
                 &lt;span class="hljs-string"&gt;&amp;quot; from &amp;quot;&lt;/span&gt;
                 ($ &lt;span class="hljs-symbol"&gt;:span&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;OrgX&amp;quot;&lt;/span&gt;)))
     ($ &lt;span class="hljs-symbol"&gt;:div&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot; World!&amp;quot;&lt;/span&gt;))))

(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; component [props]
  ($ _comp (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;merge&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;quote&lt;/span&gt;&lt;/span&gt; {#_&lt;span class="hljs-string"&gt;&amp;quot;default properties&amp;quot;&lt;/span&gt;}) props)))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
The blogging program uses &lt;a href="https://github.com/pitch-io/uix?tab=readme-ov-file"&gt;uix&lt;/a&gt; as its React wrapper, thus the generated Clojure code is using uix. Some uix functions like &lt;code&gt;$&lt;/code&gt; are also imported by default. 
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;p&gt;
As you can see from this example:
&lt;/p&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;We can &lt;code&gt;@@orgx:@@&lt;/code&gt; for inline Clojure code and &lt;code&gt;#+begin_orgx&lt;/code&gt; for Clojure blocks.&lt;/li&gt;&lt;li&gt;The embedded Clojure code are put in a component called &lt;code&gt;_comp&lt;/code&gt;, along with other contents in the Org file.&lt;/li&gt;&lt;li&gt;The outer &lt;code&gt;component&lt;/code&gt; wraps the &lt;code&gt;_comp&lt;/code&gt; component, its provides some metadata about this post related to the blogging program. More about this on the following sections.&lt;/li&gt;&lt;li&gt;We can use the &lt;code&gt;component&lt;/code&gt; component from other Clojure code.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-basic-usage" class="outline-2"&gt;&lt;a href="#basic-usage"&gt;&lt;h2 id="basic-usage" class="cr-self-reference "&gt;Basic Usage&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-basic-usage" class="outline-text-2"&gt;&lt;p&gt;
As we have seen from the earily example, &lt;code&gt;#+begin_orgx&lt;/code&gt; and &lt;code&gt;@@orgx:@@&lt;/code&gt; are the most basic structure for standalone and inline Clojure code, respectively.
&lt;/p&gt;&lt;p&gt;
We can have a clickable button with the following code.
&lt;/p&gt;&lt;pre id="orgb18a8ba" class="example"&gt;#+begin_orgx
  ;; you can style it using tailwindcss
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
     :on-click (fn [&amp;amp; _]
                   #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))}
  &amp;quot;click me&amp;quot;)
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
That will be rendered as:
&lt;/p&gt;&lt;button class="my-2 bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;&lt;p&gt;
Notice the &lt;a href="https://clojure.org/guides/reader_conditionals"&gt;reader conditional macro&lt;/a&gt; &lt;code&gt;#?(:cljs)&lt;/code&gt;  . The generated Clojure code is in a Cljc file, therefore it pairs well with the server side rendering or static generation. However, it also means we need to put the platform specified code in the corresponding reader conditionals.
&lt;/p&gt;&lt;pre id="orge805190" class="example"&gt;We can also use the button inline this way: @@orgx:($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot; :on-click (fn [&amp;amp; _] #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))} &amp;quot;Click Me&amp;quot;)@@
&lt;/pre&gt;&lt;p&gt;
The above snippet will be rendered as:
&lt;/p&gt;&lt;p&gt;
We can also use the button inline this way: &lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;&lt;/p&gt;&lt;/div&gt;&lt;div id="outline-container-toplevel-clojure-code" class="outline-3"&gt;&lt;a href="#toplevel-clojure-code"&gt;&lt;h3 id="toplevel-clojure-code" class="cr-self-reference "&gt;Toplevel Clojure Code&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-toplevel-clojure-code" class="outline-text-3"&gt;&lt;p&gt;
You may have noticed that, all the Clojure code being put in a component means that we can&amp;#x27;t use Clojure code that only works on the top level like &lt;code&gt;defn&lt;/code&gt; or &lt;code&gt;require&lt;/code&gt;. To solve this, we can use &lt;code&gt;#+attr_orgx_toplevel: true&lt;/code&gt; to mark a OrgX block and make its contents appear in toplevel of the generated Clojure file.
&lt;/p&gt;&lt;p&gt;
Let&amp;#x27;s go back to the button example, we can define a &lt;code&gt;my-button&lt;/code&gt; component with the following code:
&lt;/p&gt;&lt;pre id="orgb24feeb" class="example"&gt;#+attr_orgx_toplevel: true
#+begin_orgx
(defui my-button [{:keys [children callback]}]
    ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
       :on-click (fn [&amp;amp; _]
                   (if callback (callback)))}
    children))
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
The &lt;code&gt;defui&lt;/code&gt; will be put on the top level in the generated Clojure code, along side something like &lt;code&gt;_comp&lt;/code&gt;:
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;ns&lt;/span&gt;&lt;/span&gt; ...)
(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; my-button [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [children callback]}]
  ($ &lt;span class="hljs-symbol"&gt;:button&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;&lt;/span&gt;
              &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [&amp;amp; _]
                          #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt; (&lt;span class="hljs-name"&gt;callback&lt;/span&gt;)))}
     children))

(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; _comp ...)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
We can then easily use the &lt;code&gt;my-button&lt;/code&gt; component with either inline or standalone OrgX block.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Example Usage:&lt;/i&gt;&lt;pre id="orgc3ab17f" class="example"&gt;Inline OrgX block:
@@orgx:($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;quot;Hello From inline OrgX&amp;quot;)))} &amp;quot;From inline OrgX&amp;quot;)@@
#+begin_orgx
($ :div &amp;quot;We can also use it in a orgx block&amp;quot;
    ($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;quot;Hello from OrgX block!&amp;quot;)))}
         &amp;quot;From OrgX block&amp;quot;))
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;p&gt;
Inline OrgX block:
&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;From inline OrgX&lt;/button&gt;
&lt;/p&gt;
&lt;div&gt;We can also use it in a orgx block&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;From OrgX block&lt;/button&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-import-modules" class="outline-3"&gt;&lt;a href="#import-modules"&gt;&lt;h3 id="import-modules" class="cr-self-reference "&gt;Import Modules&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-import-modules" class="outline-text-3"&gt;&lt;p&gt;
In MDX, we can import modules with normal &lt;code&gt;import&lt;/code&gt; statements. In OrgX, we can do something similar with toplevel OrgX block and the &lt;code&gt;require&lt;/code&gt; function.
&lt;/p&gt;&lt;pre id="orga8b559a" class="example"&gt;#+attr_orgx_toplevel: true
#+begin_orgx
(require &amp;#x27;[clojure.string :as string])
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
We can also do this with keyword metadata at the beginning of an Org file.
&lt;/p&gt;&lt;pre id="orgc2e9035" class="example"&gt;#+ORGX_REQUIRE: [[clojure.string :as string]]
&lt;/pre&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
Settings in keyword metadata currently doesn&amp;#x27;t support reader macros.
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-access-component-properties" class="outline-3"&gt;&lt;a href="#access-component-properties"&gt;&lt;h3 id="access-component-properties" class="cr-self-reference "&gt;Access Component Properties&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-access-component-properties" class="outline-text-3"&gt;&lt;p&gt;
Similar to MDX, we can access the component&amp;#x27;s properties with the &lt;code&gt;post-props&lt;/code&gt; variable. Some metadata are also provided in the &lt;code&gt;post-props&lt;/code&gt; variable.
&lt;/p&gt;&lt;p&gt;
The following metadata are provided by default:
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Example:&lt;/i&gt;&lt;pre id="orgbd2cae9" class="example"&gt;($ :pre
  (binding [*print-namespace-maps* true]
    (with-out-str (pprint/pprint post-props))))
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Result:&lt;/i&gt;&lt;pre&gt;#:blog{:orgx true,
       :tags [],
       :unlisted false,
       :title
       &amp;quot;Something Like MDX but with Clojure and Org-Mode for My Personal Blog: Part I&amp;quot;,
       :show-toc? true,
       :file-path
       &amp;quot;/home/void/Projects/cerulean/workspace/blogs/some-like-mdx-but-with-clojure-and-org-mode.org&amp;quot;,
       :author nil,
       :email nil,
       :description
       &amp;quot;MDX  is a tool lets you write JavaScript and JSX in a Markdown file. It will then compile the Markdown file into a JavaScript file, so that we can use it f...&amp;quot;,
       :id
       &amp;quot;something-like-mdx-but-with-clojure-and-org-mode-for-my-personal-blog--part-i&amp;quot;,
       :category &amp;quot;Coding&amp;quot;,
       :language &amp;quot;en_US&amp;quot;,
       :published-date &amp;quot;2026-01-03T01:47:09+08:00&amp;quot;,
       :content
       &amp;quot;&amp;lt;p&amp;gt;\n&amp;lt;a href=\&amp;quot;https://mdxjs.com/\&amp;quot;&amp;gt;MDX&amp;lt;/a&amp;gt; is a tool lets you write JavaScript and JSX in a Markdown file. It will then compile the Markdown file into a JavaScript file, so that we can use it from other JavaScript code. I always wanted something similar for my personal blog. For some background, the blogging program is written in Clojure/ClojureScript. The blogging program runs on the JVM, it works by statically generating all the HTML and other files so that the result could be hosted on platforms like Github Pages. Posts of my blog are written in &amp;lt;a href=\&amp;quot;https://orgmode.org\&amp;quot;&amp;gt;org-mode&amp;lt;/a&amp;gt;. As the blog program runs on the JVM, directly using MDX is theoratically possible, but probably would create a lot of frictions.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nTherefore I took some time to implement something similar. Albeit it is not fully tested, the result is quite satisfactory: I can embed Clojure code directly in an Org file, or use React components defined in Clojure code with native Org syntax. The Org file can then be converted into a Cljc file and used from other Clojure code.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nIn the following sections I will call it &amp;lt;code&amp;gt;OrgX&amp;lt;/code&amp;gt;.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;info\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\n&amp;lt;i&amp;gt;This is part &amp;lt;b&amp;gt;one&amp;lt;/b&amp;gt; of the series, in this post I will show the features and in the next post I will describe the process of implementing it&amp;lt;/i&amp;gt;\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-how-orgx-works\&amp;quot; class=\&amp;quot;outline-2\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#how-orgx-works\&amp;quot;&amp;gt;&amp;lt;h2 id=\&amp;quot;how-orgx-works\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;How OrgX Works&amp;lt;/h2&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-2\&amp;quot; id=\&amp;quot;text-how-orgx-works\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nSimilar to MDX, OrgX works by compiling the OrgX file into a &amp;lt;a href=\&amp;quot;https://clojure.org/guides/reader_conditionals\&amp;quot;&amp;gt;Cljc&amp;lt;/a&amp;gt; file. A basic OrgX file would look like this:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;orgx-example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgc3c59e4\&amp;quot;&amp;gt;#+ORGX: true\n\n/*Hello* from @@orgx:($ :span &amp;amp;quot;OrgX&amp;amp;quot;)@@/\n\n#+begin_orgx\n($ :div (str &amp;amp;quot;Hello&amp;amp;quot; &amp;amp;quot; World!&amp;amp;quot;))\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ tabs {:tab-list [{:name &amp;amp;quot;example.org&amp;amp;quot; :content ($ orgx-example)}]})\n\n&amp;lt;/pre&amp;gt;\n\n\n&amp;lt;p&amp;gt;\nIt will be converted into something similar to the following Clojure snippet.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;orgx-cljc\&amp;quot;&amp;gt;&amp;lt;div class=\&amp;quot;org-src-container\&amp;quot;&amp;gt;\n&amp;lt;pre class=\&amp;quot;cr-highlighted\&amp;quot;&amp;gt;&amp;lt;code class=\&amp;quot;lang-clojure\&amp;quot;&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;ns&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; orgx.example\n  (&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:require&amp;lt;/span&amp;gt; [uix.core &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:as&amp;lt;/span&amp;gt; uix &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:refer&amp;lt;/span&amp;gt;\n             [defui use-state use-effect use-context $]]))\n\n(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;defui&amp;lt;/span&amp;gt; _comp [post-props]\n  ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:&amp;amp;lt;&amp;amp;gt;&amp;lt;/span&amp;gt;\n     ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:p&amp;lt;/span&amp;gt; {} ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:i&amp;lt;/span&amp;gt; {}\n                 ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:b&amp;lt;/span&amp;gt; {} &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;Hello&amp;amp;quot;&amp;lt;/span&amp;gt;)\n                 &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot; from &amp;amp;quot;&amp;lt;/span&amp;gt;\n                 ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:span&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;OrgX&amp;amp;quot;&amp;lt;/span&amp;gt;)))\n     ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:div&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;str&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;Hello&amp;amp;quot;&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot; World!&amp;amp;quot;&amp;lt;/span&amp;gt;))))\n\n(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;defui&amp;lt;/span&amp;gt; component [props]\n  ($ _comp (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;merge&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;quote&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; {#_&amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;default properties&amp;amp;quot;&amp;lt;/span&amp;gt;}) props)))\n&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ tabs {:tab-list [{:name &amp;amp;quot;orgx/example.cljc&amp;amp;quot; :content ($ orgx-cljc)}]})\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThe blogging program uses &amp;lt;a href=\&amp;quot;https://github.com/pitch-io/uix?tab=readme-ov-file\&amp;quot;&amp;gt;uix&amp;lt;/a&amp;gt; as its React wrapper, thus the generated Clojure code is using uix. Some uix functions like &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt; are also imported by default. \n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nAs you can see from this example:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;ul class=\&amp;quot;org-ul\&amp;quot;&amp;gt;\n&amp;lt;li&amp;gt;We can &amp;lt;code&amp;gt;@@orgx:@@&amp;lt;/code&amp;gt; for inline Clojure code and &amp;lt;code&amp;gt;#+begin_orgx&amp;lt;/code&amp;gt; for Clojure blocks.&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;The embedded Clojure code are put in a component called &amp;lt;code&amp;gt;_comp&amp;lt;/code&amp;gt;, along with other contents in the Org file.&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;The outer &amp;lt;code&amp;gt;component&amp;lt;/code&amp;gt; wraps the &amp;lt;code&amp;gt;_comp&amp;lt;/code&amp;gt; component, its provides some metadata about this post related to the blogging program. More about this on the following sections.&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;We can use the &amp;lt;code&amp;gt;component&amp;lt;/code&amp;gt; component from other Clojure code.&amp;lt;/li&amp;gt;\n&amp;lt;/ul&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-basic-usage\&amp;quot; class=\&amp;quot;outline-2\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#basic-usage\&amp;quot;&amp;gt;&amp;lt;h2 id=\&amp;quot;basic-usage\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Basic Usage&amp;lt;/h2&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-2\&amp;quot; id=\&amp;quot;text-basic-usage\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nAs we have seen from the earily example, &amp;lt;code&amp;gt;#+begin_orgx&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;@@orgx:@@&amp;lt;/code&amp;gt; are the most basic structure for standalone and inline Clojure code, respectively.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nWe can have a clickable button with the following code.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgb18a8ba\&amp;quot;&amp;gt;#+begin_orgx\n  ;; you can style it using tailwindcss\n  ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n     :on-click (fn [&amp;amp;amp; _]\n                   #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))}\n  &amp;amp;quot;click me&amp;amp;quot;)\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nThat will be rendered as:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;  ($ :button {:class &amp;amp;quot;my-2 bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot; :on-click (fn [&amp;amp;amp; _] #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))} &amp;amp;quot;Click Me&amp;amp;quot;)\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nNotice the &amp;lt;a href=\&amp;quot;https://clojure.org/guides/reader_conditionals\&amp;quot;&amp;gt;reader conditional macro&amp;lt;/a&amp;gt; &amp;lt;code&amp;gt;#?(:cljs)&amp;lt;/code&amp;gt;  . The generated Clojure code is in a Cljc file, therefore it pairs well with the server side rendering or static generation. However, it also means we need to put the platform specified code in the corresponding reader conditionals.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orge805190\&amp;quot;&amp;gt;We can also use the button inline this way: @@orgx:($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot; :on-click (fn [&amp;amp;amp; _] #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))} &amp;amp;quot;Click Me&amp;amp;quot;)@@\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nThe above snippet will be rendered as:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nWe can also use the button inline this way: &amp;lt;code class=\&amp;quot;orgx\&amp;quot;&amp;gt;\n($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot; :on-click (fn [&amp;amp;amp; _] #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))} &amp;amp;quot;Click Me&amp;amp;quot;)\n&amp;lt;/code&amp;gt;\n&amp;lt;/p&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-toplevel-clojure-code\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#toplevel-clojure-code\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;toplevel-clojure-code\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Toplevel Clojure Code&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-toplevel-clojure-code\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nYou may have noticed that, all the Clojure code being put in a component means that we can&amp;#x27;t use Clojure code that only works on the top level like &amp;lt;code&amp;gt;defn&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;require&amp;lt;/code&amp;gt;. To solve this, we can use &amp;lt;code&amp;gt;#+attr_orgx_toplevel: true&amp;lt;/code&amp;gt; to mark a OrgX block and make its contents appear in toplevel of the generated Clojure file.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nLet&amp;#x27;s go back to the button example, we can define a &amp;lt;code&amp;gt;my-button&amp;lt;/code&amp;gt; component with the following code:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgb24feeb\&amp;quot;&amp;gt;#+attr_orgx_toplevel: true\n#+begin_orgx\n(defui my-button [{:keys [children callback]}]\n    ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n       :on-click (fn [&amp;amp;amp; _]\n                   (if callback (callback)))}\n    children))\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-toplevel=\&amp;quot;\&amp;quot;&amp;gt;  (defui my-button [{:keys [children callback]}]\n      ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n         :on-click (fn [&amp;amp;amp; _]\n                     (if callback (callback)))}\n      children))\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nThe &amp;lt;code&amp;gt;defui&amp;lt;/code&amp;gt; will be put on the top level in the generated Clojure code, along side something like &amp;lt;code&amp;gt;_comp&amp;lt;/code&amp;gt;:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;div class=\&amp;quot;org-src-container\&amp;quot;&amp;gt;\n&amp;lt;pre class=\&amp;quot;cr-highlighted\&amp;quot;&amp;gt;&amp;lt;code class=\&amp;quot;lang-clojure\&amp;quot;&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;ns&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; ...)\n(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;defui&amp;lt;/span&amp;gt; my-button [{&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:keys&amp;lt;/span&amp;gt; [children callback]}]\n  ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:button&amp;lt;/span&amp;gt; {&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:class&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;&amp;lt;/span&amp;gt;\n              &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:on-click&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;fn&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; [&amp;amp;amp; _]\n                          #?(&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:cljs&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;callback&amp;lt;/span&amp;gt;)))}\n     children))\n\n(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;defui&amp;lt;/span&amp;gt; _comp ...)\n&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n\n&amp;lt;p&amp;gt;\nWe can then easily use the &amp;lt;code&amp;gt;my-button&amp;lt;/code&amp;gt; component with either inline or standalone OrgX block.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;mybutton_example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgc3ab17f\&amp;quot;&amp;gt;Inline OrgX block:\n@@orgx:($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;amp;quot;Hello From inline OrgX&amp;amp;quot;)))} &amp;amp;quot;From inline OrgX&amp;amp;quot;)@@\n#+begin_orgx\n($ :div &amp;amp;quot;We can also use it in a orgx block&amp;amp;quot;\n    ($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;amp;quot;Hello from OrgX block!&amp;amp;quot;)))}\n         &amp;amp;quot;From OrgX block&amp;amp;quot;))\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;mybutton_result\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nInline OrgX block:\n&amp;lt;code class=\&amp;quot;orgx\&amp;quot;&amp;gt;\n($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;amp;quot;Hello From inline OrgX&amp;amp;quot;)))} &amp;amp;quot;From inline OrgX&amp;amp;quot;)\n&amp;lt;/code&amp;gt;\n&amp;lt;/p&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ :div &amp;amp;quot;We can also use it in a orgx block&amp;amp;quot;\n    ($ my-button {:callback (fn [] #?(:cljs (js/alert &amp;amp;quot;Hello from OrgX block!&amp;amp;quot;)))}\n         &amp;amp;quot;From OrgX block&amp;amp;quot;))\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Example Usage&amp;amp;quot; :content ($ mybutton_example)}]})\n  ($ mybutton_result))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-import-modules\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#import-modules\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;import-modules\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Import Modules&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-import-modules\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nIn MDX, we can import modules with normal &amp;lt;code&amp;gt;import&amp;lt;/code&amp;gt; statements. In OrgX, we can do something similar with toplevel OrgX block and the &amp;lt;code&amp;gt;require&amp;lt;/code&amp;gt; function.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orga8b559a\&amp;quot;&amp;gt;#+attr_orgx_toplevel: true\n#+begin_orgx\n(require &amp;#x27;[clojure.string :as string])\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nWe can also do this with keyword metadata at the beginning of an Org file.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgc2e9035\&amp;quot;&amp;gt;#+ORGX_REQUIRE: [[clojure.string :as string]]\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nSettings in keyword metadata currently doesn&amp;#x27;t support reader macros.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-access-component-properties\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#access-component-properties\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;access-component-properties\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Access Component Properties&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-access-component-properties\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nSimilar to MDX, we can access the component&amp;#x27;s properties with the &amp;lt;code&amp;gt;post-props&amp;lt;/code&amp;gt; variable. Some metadata are also provided in the &amp;lt;code&amp;gt;post-props&amp;lt;/code&amp;gt; variable.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;metadata-example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgbd2cae9\&amp;quot;&amp;gt;($ :pre\n  (binding [*print-namespace-maps* true]\n    (with-out-str (pprint/pprint post-props))))\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nThe following metadata are provided by default:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase ($ tabs {:tab-list [{:name &amp;amp;quot;Example&amp;amp;quot; :content ($ metadata-example)}]}) ($ :pre (binding [*print-namespace-maps* true] (with-out-str (pprint/pprint post-props)))))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-use-other-orgx-files-as-components\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#use-other-orgx-files-as-components\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;use-other-orgx-files-as-components\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Use Other OrgX Files as Components&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-use-other-orgx-files-as-components\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nBy default, OrgX files are compiled as Cljc files and will be put in the &amp;lt;code&amp;gt;orgx&amp;lt;/code&amp;gt; namespace. You can import them as described in &amp;lt;a href=\&amp;quot;#import-modules\&amp;quot;&amp;gt;Import Modules&amp;lt;/a&amp;gt;.\n&amp;lt;/p&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-use-orgx-with-native-org-syntax\&amp;quot; class=\&amp;quot;outline-2\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#use-orgx-with-native-org-syntax\&amp;quot;&amp;gt;&amp;lt;h2 id=\&amp;quot;use-orgx-with-native-org-syntax\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Use OrgX With Native Org Syntax&amp;lt;/h2&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-2\&amp;quot; id=\&amp;quot;text-use-orgx-with-native-org-syntax\&amp;quot;&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-use-components\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#use-components\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;use-components\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Use Components&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-use-components\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nWriting &amp;lt;code&amp;gt;#+begin_orgx&amp;lt;/code&amp;gt; and Clojure code must be very tedious every time we want to use a simple component, like &amp;lt;code&amp;gt;note&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;warning&amp;lt;/code&amp;gt; notice blocks.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nTo solve this problem, a new syntax &amp;lt;code&amp;gt;#+orgx_{comp-name}&amp;lt;/code&amp;gt; has been introduced.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nFor example:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;orgx_syntax_example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgff794f0\&amp;quot;&amp;gt;#+begin_orgx_note\nThis is a note\n\n+ /Normal/ Org markups *can* be used inside it\n\n@@orgx:($ :span &amp;amp;quot;You can even nest OrgX syntax in it&amp;amp;quot;)@@\n#+end_orgx_note\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;orgx_syntax_result\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is a note\n&amp;lt;/p&amp;gt;\n\n&amp;lt;ul class=\&amp;quot;org-ul\&amp;quot;&amp;gt;\n&amp;lt;li&amp;gt;&amp;lt;i&amp;gt;Normal&amp;lt;/i&amp;gt; Org markups &amp;lt;b&amp;gt;can&amp;lt;/b&amp;gt; be used inside it&amp;lt;/li&amp;gt;\n&amp;lt;/ul&amp;gt;\n\n&amp;lt;p&amp;gt;\n&amp;lt;code class=\&amp;quot;orgx\&amp;quot;&amp;gt;\n($ :span &amp;amp;quot;You can even nest OrgX syntax in it&amp;amp;quot;)\n&amp;lt;/code&amp;gt;\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Use Component With Org Syntax&amp;amp;quot; :content ($  orgx_syntax_example)}]})\n  ($ orgx_syntax_result))\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nIt works by passing the rendered content to the component &amp;lt;code&amp;gt;note&amp;lt;/code&amp;gt; as &amp;lt;code&amp;gt;children&amp;lt;/code&amp;gt;. All other Org markups or structures that can be used in an Org environment can also be used here. You can also nested other OrgX structures in it, except for top level Clojure definition and component building, which are not supported.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nCurrently we can&amp;#x27;t pass other properties to the component using this syntax, but that might change in the future.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-build-components\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#build-components\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;build-components\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Build Components&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-build-components\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nSomething we may want to build a React component out of some Org blocks. Like we may want to pass two Org mode source blocks as arguments to a &amp;lt;code&amp;gt;tabs&amp;lt;/code&amp;gt; components.\nTo do this, we just need to add an annotation to the existing &amp;lt;code&amp;gt;#+begin_orgx_{comp-name}&amp;lt;/code&amp;gt; syntax:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;org78eb610\&amp;quot;&amp;gt;#+attr_orgx_defui: true\n#+begin_orgx_my-note\n*@@orgx:(or (:note-text props) &amp;amp;quot;Tip&amp;amp;quot;)@@*\n#+begin_orgx\n(:children props)\n#+end_orgx\n#+end_orgx_my-note\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;my-note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\n&amp;lt;b&amp;gt;&amp;lt;code class=\&amp;quot;orgx\&amp;quot;&amp;gt;\n(or (:note-text props) &amp;amp;quot;Tip&amp;amp;quot;)\n&amp;lt;/code&amp;gt;&amp;lt;/b&amp;gt;\n&amp;lt;/p&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;(:children props)\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n\n&amp;lt;p&amp;gt;\nAs shown in the example, we can use normal Org syntax along with OrgX snippets. We can also access the properties with the &amp;lt;code&amp;gt;props&amp;lt;/code&amp;gt; variable.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;p&amp;gt;\nIn the above example we have defined a &amp;lt;code&amp;gt;my-note&amp;lt;/code&amp;gt; component, we can then use it with any aforementioned methods.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;my-note-example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;org54e2523\&amp;quot;&amp;gt;#+begin_orgx_my-note\nThis is a note!\n#+end_orgx_my-note\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;my-note-result\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;my-note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is a note!\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Example Usage&amp;amp;quot; :content ($ my-note-example)}]})\n  ($ my-note-result))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-inline-orgx-with-macros\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#inline-orgx-with-macros\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;inline-orgx-with-macros\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Inline OrgX with Macros&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-inline-orgx-with-macros\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nCurrently no similar syntax for inline OrgX is supported, however, it is fairly easy to make life easier with macros. Let&amp;#x27;s go back to use &amp;lt;code&amp;gt;my-button&amp;lt;/code&amp;gt; as the example.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;macro-example\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nWe can define a macro like:\n&amp;lt;/p&amp;gt;\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;org2cb14d6\&amp;quot;&amp;gt;#+MACRO: my-button @@orgx:($ my-button {:callback (or $2 nil)} $1)@@\n&amp;lt;/pre&amp;gt;\n\n\n&amp;lt;p&amp;gt;\nAnd then use it with:\n&amp;lt;/p&amp;gt;\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;org0f1468f\&amp;quot;&amp;gt;{{{my-button(&amp;amp;quot;Using Macro&amp;amp;quot;, #?(:cljs (fn [] (js/alert &amp;amp;quot;Hello From Macro!&amp;amp;quot;))))}}}\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;macro-result\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\n&amp;lt;code class=\&amp;quot;orgx\&amp;quot;&amp;gt;\n($ my-button {:callback (or  #?(:cljs (fn [] (js/alert &amp;amp;quot;Hello From Macro!&amp;amp;quot;))) nil)} &amp;amp;quot;Using Macro&amp;amp;quot;)\n&amp;lt;/code&amp;gt;\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot; :class &amp;amp;quot;lg:grid-cols-[minmax(0,1fr)_minmax(0,0.5fr)]&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Inline OrgX with Macro&amp;amp;quot; :content ($ macro-example)}]})\n  ($ macro-result))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-builtin-components\&amp;quot; class=\&amp;quot;outline-2\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#builtin-components\&amp;quot;&amp;gt;&amp;lt;h2 id=\&amp;quot;builtin-components\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Builtin Components&amp;lt;/h2&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-2\&amp;quot; id=\&amp;quot;text-builtin-components\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nThe blogging program provides several builtin components, I will briefly describe their features.\n&amp;lt;/p&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-simple-remarks\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#simple-remarks\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;simple-remarks\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Simple Notice Blocks&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-simple-remarks\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nIt provides most commons blocks like &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;note&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;warn&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;error&amp;lt;/code&amp;gt;.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;remarks_example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgf924c87\&amp;quot;&amp;gt;#+begin_orgx_info\nThis is an info\n#+end_orgx_info\n\n#+begin_orgx_note\nThis is a note\n#+end_orgx_note\n\n#+begin_orgx_warn\nThis is a warn\n#+end_orgx_warn\n\n#+begin_orgx_error\nThis is an error\n#+end_orgx_error\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;remarks_result\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;info\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is an info\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;note\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is a note\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;warn\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is a warn\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-comp\&amp;quot; data-wrapper-data=\&amp;quot;error\&amp;quot;&amp;gt;&amp;lt;p&amp;gt;\nThis is an error\n&amp;lt;/p&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Remarks&amp;amp;quot; :content ($ remarks_example)}]})\n  ($ remarks_result))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-tabs\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#tabs\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;tabs\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Tabs&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-tabs\&amp;quot;&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;code_tabs\&amp;quot;&amp;gt;&amp;lt;div class=\&amp;quot;org-src-container\&amp;quot;&amp;gt;\n&amp;lt;pre class=\&amp;quot;cr-highlighted\&amp;quot;&amp;gt;&amp;lt;code class=\&amp;quot;lang-clojure\&amp;quot;&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;(&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;defui&amp;lt;/span&amp;gt; tabs [{&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:keys&amp;lt;/span&amp;gt; [tab-list default-table class]}]\n  (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;let&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; [[selected-tab set-selected-tab!] (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;use-state&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;or&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; default-table\n                                                        (&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:name&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;first&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; tab-list))))]\n    ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:div.my-4.relative.border-sky-300.border-l-2.border-l-neutral-100&amp;lt;/span&amp;gt; {&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:class&amp;lt;/span&amp;gt; class}\n       ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:div.my-0.flex.relative.bg-neutral-100&amp;lt;/span&amp;gt;\n          (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;map&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;fn&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; [{&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:keys&amp;lt;/span&amp;gt; [name]}]\n                 ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:button.font-medium.text-neutral-700.bg-neutral-50.py-1.px-2.border-t-2.border-neutral-50.min-w-28.bg-neutral-50.border-t-neutral-100&amp;lt;/span&amp;gt;\n                    {&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:key&amp;lt;/span&amp;gt; name\n                     &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:class&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;when&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;=&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; name selected-tab)\n                              &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot; text-sky-800 border-sky-400 bg-sky-100 border-t-sky-400&amp;amp;quot;&amp;lt;/span&amp;gt;)\n                     &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:on-click&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;fn&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; []\n                                 #?(&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:cljs&amp;lt;/span&amp;gt;\n                                    (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;set-selected-tab!&amp;lt;/span&amp;gt; name)))}\n                    name))\n               tab-list))\n       ($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:div.my-0.bg-neutral-50.overflow-hidden.px-2.h-full&amp;lt;/span&amp;gt;\n          (&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:content&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;first&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;filter&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;fn&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; [{&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:keys&amp;lt;/span&amp;gt; [name]}]\n                                     (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;=&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; name selected-tab))\n                                   tab-list)))))))\n&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;tabs_example\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orgba7f7a5\&amp;quot;&amp;gt;#+begin_orgx\n($ tabs {:tab-list [{:name &amp;amp;quot;tabs.clj&amp;amp;quot; :content ($ code_tabs)}\n                    {:name &amp;amp;quot;tabs usage&amp;amp;quot; :content ($ tabs_example)}]})\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;tabs_result\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ tabs {:tab-list [{:name &amp;amp;quot;tabs.clj&amp;amp;quot; :content ($ code_tabs)}\n                      {:name &amp;amp;quot;tabs usage&amp;amp;quot; :content ($ tabs_example)}]})\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\n&amp;lt;code&amp;gt;tabs&amp;lt;/code&amp;gt; is like tabs in a browser or a text editor.\n&amp;lt;/p&amp;gt;\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;tabs usage&amp;amp;quot; :content ($ tabs_example)}]})\n  ($ tabs_result))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-split-layout\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#split-layout\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;split-layout\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Split Layout&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-split-layout\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nSplit layout lets you show two things side by side:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;org2aaa82a\&amp;quot;&amp;gt;#+attr_orgx_defui: true\n#+begin_orgx_split_1\n#+begin_src clojure\n  ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n              :on-click (fn [&amp;amp;amp; _]\n                          #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))}\n     &amp;amp;quot;Click Me&amp;amp;quot;)\n#+end_src\n#+end_orgx_split_1\n\n#+attr_orgx_defui: true\n#+begin_orgx_split_2\n#+begin_orgx\n  ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n              :on-click (fn [&amp;amp;amp; _]\n                          #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))}\n     &amp;amp;quot;Click Me&amp;amp;quot;)\n#+end_orgx\n#+end_orgx_split_2\n\n#+begin_orgx\n($ split-layout\n($ tabs {:tab-list [{:name &amp;amp;quot;button&amp;amp;quot; :content ($ split_1)}]})\n($ tabs {:tab-list [{:name &amp;amp;quot;showcase&amp;amp;quot; :content ($ split_2)}]}))\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;p&amp;gt;\nWill be rendered as:\n&amp;lt;/p&amp;gt;\n\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;split_1\&amp;quot;&amp;gt;&amp;lt;div class=\&amp;quot;org-src-container\&amp;quot;&amp;gt;\n&amp;lt;pre class=\&amp;quot;cr-highlighted\&amp;quot;&amp;gt;&amp;lt;code class=\&amp;quot;lang-clojure\&amp;quot;&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;($ &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:button&amp;lt;/span&amp;gt; {&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:class&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;&amp;lt;/span&amp;gt;\n            &amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:on-click&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;&amp;lt;span class=\&amp;quot;hljs-built_in\&amp;quot;&amp;gt;fn&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; [&amp;amp;amp; _]\n                        #?(&amp;lt;span class=\&amp;quot;hljs-symbol\&amp;quot;&amp;gt;:cljs&amp;lt;/span&amp;gt; (&amp;lt;span class=\&amp;quot;hljs-name\&amp;quot;&amp;gt;js/alert&amp;lt;/span&amp;gt; &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;clicked!&amp;amp;quot;&amp;lt;/span&amp;gt;)))}\n   &amp;lt;span class=\&amp;quot;hljs-string\&amp;quot;&amp;gt;&amp;amp;quot;Click Me&amp;amp;quot;&amp;lt;/span&amp;gt;)\n&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot; data-wrapper=\&amp;quot;use-defui\&amp;quot; data-wrapper-data=\&amp;quot;split_2\&amp;quot;&amp;gt;&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;  ($ :button {:class &amp;amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;amp;quot;\n              :on-click (fn [&amp;amp;amp; _]\n                          #?(:cljs (js/alert &amp;amp;quot;clicked!&amp;amp;quot;)))}\n     &amp;amp;quot;Click Me&amp;amp;quot;)\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;/pre&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;orgx\&amp;quot;&amp;gt;($ split-layout\n($ tabs {:tab-list [{:name &amp;amp;quot;button&amp;amp;quot; :content ($ split_1)}]})\n($ tabs {:tab-list [{:name &amp;amp;quot;showcase&amp;amp;quot; :content ($ split_2)}]}))\n\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-showcase\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#showcase\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;showcase\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Showcase&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-showcase\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nShowcase is a simple wrapper over &amp;lt;code&amp;gt;split-layout&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tabs&amp;lt;/code&amp;gt;. The &amp;lt;code&amp;gt;showcase&amp;lt;/code&amp;gt; component is used extensive in this post, such as the example in &amp;lt;a href=\&amp;quot;#simple-remarks\&amp;quot;&amp;gt;Simple Notice Blocks&amp;lt;/a&amp;gt; is coded as:\n&amp;lt;/p&amp;gt;\n\n&amp;lt;pre class=\&amp;quot;example\&amp;quot; id=\&amp;quot;orga398f69\&amp;quot;&amp;gt;#+attr_orgx_defui: true\n#+begin_orgx_remarks_example\n#+begin_example\n#+begin_orgx_info\nThis is an info\n#+end_orgx_info\n\n#+begin_orgx_note\nThis is a note\n#+end_orgx_note\n\n#+begin_orgx_warn\nThis is a warn\n#+end_orgx_warn\n\n#+begin_orgx_error\nThis is an error\n#+end_orgx_error\n\n#+end_example\n#+end_orgx_remarks_example\n\n#+attr_orgx_defui: true\n#+begin_orgx_remarks_result\n#+begin_orgx_info\nThis is an info\n#+end_orgx_info\n#+begin_orgx_note\nThis is a note\n#+end_orgx_note\n#+begin_orgx_warn\nThis is a warn\n#+end_orgx_warn\n#+begin_orgx_error\nThis is an error\n#+end_orgx_error\n#+end_orgx_remarks_result\n\n#+begin_orgx\n($ showcase {:showcase-name &amp;amp;quot;Rendering&amp;amp;quot;}\n  ($ tabs {:tab-list [{:name &amp;amp;quot;Remarks&amp;amp;quot; :content ($ remarks_example)}]})\n  ($ remarks_result))\n#+end_orgx\n&amp;lt;/pre&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-conclusions\&amp;quot; class=\&amp;quot;outline-2\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#conclusions\&amp;quot;&amp;gt;&amp;lt;h2 id=\&amp;quot;conclusions\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Conclusions&amp;lt;/h2&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-2\&amp;quot; id=\&amp;quot;text-conclusions\&amp;quot;&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-caveats\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#caveats\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;caveats\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Caveats&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-caveats\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nAlthough I have extensively used it in this demostration and will definitely use it in the future, there are some notably deficiency with the current implementation.\n&amp;lt;/p&amp;gt;\n\n&amp;lt;ul class=\&amp;quot;org-ul\&amp;quot;&amp;gt;\n&amp;lt;li&amp;gt;You need to read the logging to understand the problem if anything goes wrong. If you want to do SSR or SSG, the fact that the same code must be run on the JVM and the browser and produce the same result adds complexity.&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;The syntax still feels cumbersome in many cases, but that might be improved in the future.&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;The current implementation requires Emacs itself to convert the Org files into HTML, and Clojure code will then process the HTML. The most notably advantage of this method is that we can use the (basically) the full power of Org mode. However, it is also a lot of moving parts.&amp;lt;/li&amp;gt;\n&amp;lt;/ul&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;div id=\&amp;quot;outline-container-future-plans\&amp;quot; class=\&amp;quot;outline-3\&amp;quot;&amp;gt;\n&amp;lt;a href=\&amp;quot;#future-plans\&amp;quot;&amp;gt;&amp;lt;h3 id=\&amp;quot;future-plans\&amp;quot; class=\&amp;quot;cr-self-reference \&amp;quot;&amp;gt;Future Plans&amp;lt;/h3&amp;gt;&amp;lt;/a&amp;gt;\n&amp;lt;div class=\&amp;quot;outline-text-3\&amp;quot; id=\&amp;quot;text-future-plans\&amp;quot;&amp;gt;\n&amp;lt;p&amp;gt;\nI will describe the process of implement it in the next post of this series. Current the code is still coupled with my blogging program. I&amp;#x27;m planning on make it a separate library in the future.\n&amp;lt;/p&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;lt;/div&amp;gt;\n&amp;quot;,
       :orgx-require [[clojure.pprint :as pprint]],
       :modified-date &amp;quot;2026-01-03T15:10:59+08:00&amp;quot;}
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-use-other-orgx-files-as-components" class="outline-3"&gt;&lt;a href="#use-other-orgx-files-as-components"&gt;&lt;h3 id="use-other-orgx-files-as-components" class="cr-self-reference "&gt;Use Other OrgX Files as Components&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-use-other-orgx-files-as-components" class="outline-text-3"&gt;&lt;p&gt;
By default, OrgX files are compiled as Cljc files and will be put in the &lt;code&gt;orgx&lt;/code&gt; namespace. You can import them as described in &lt;a href="#import-modules"&gt;Import Modules&lt;/a&gt;.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-use-orgx-with-native-org-syntax" class="outline-2"&gt;&lt;a href="#use-orgx-with-native-org-syntax"&gt;&lt;h2 id="use-orgx-with-native-org-syntax" class="cr-self-reference "&gt;Use OrgX With Native Org Syntax&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-use-orgx-with-native-org-syntax" class="outline-text-2"&gt;&lt;/div&gt;&lt;div id="outline-container-use-components" class="outline-3"&gt;&lt;a href="#use-components"&gt;&lt;h3 id="use-components" class="cr-self-reference "&gt;Use Components&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-use-components" class="outline-text-3"&gt;&lt;p&gt;
Writing &lt;code&gt;#+begin_orgx&lt;/code&gt; and Clojure code must be very tedious every time we want to use a simple component, like &lt;code&gt;note&lt;/code&gt; or &lt;code&gt;warning&lt;/code&gt; notice blocks.
&lt;/p&gt;&lt;p&gt;
To solve this problem, a new syntax &lt;code&gt;#+orgx_{comp-name}&lt;/code&gt; has been introduced.
&lt;/p&gt;&lt;p&gt;
For example:
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Use Component With Org Syntax:&lt;/i&gt;&lt;pre id="orgff794f0" class="example"&gt;#+begin_orgx_note
This is a note

+ /Normal/ Org markups *can* be used inside it

@@orgx:($ :span &amp;quot;You can even nest OrgX syntax in it&amp;quot;)@@
#+end_orgx_note
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
This is a note
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;&lt;i&gt;Normal&lt;/i&gt; Org markups &lt;b&gt;can&lt;/b&gt; be used inside it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;span&gt;You can even nest OrgX syntax in it&lt;/span&gt;
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;p&gt;
It works by passing the rendered content to the component &lt;code&gt;note&lt;/code&gt; as &lt;code&gt;children&lt;/code&gt;. All other Org markups or structures that can be used in an Org environment can also be used here. You can also nested other OrgX structures in it, except for top level Clojure definition and component building, which are not supported.
&lt;/p&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
Currently we can&amp;#x27;t pass other properties to the component using this syntax, but that might change in the future.
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-build-components" class="outline-3"&gt;&lt;a href="#build-components"&gt;&lt;h3 id="build-components" class="cr-self-reference "&gt;Build Components&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-build-components" class="outline-text-3"&gt;&lt;p&gt;
Something we may want to build a React component out of some Org blocks. Like we may want to pass two Org mode source blocks as arguments to a &lt;code&gt;tabs&lt;/code&gt; components.
To do this, we just need to add an annotation to the existing &lt;code&gt;#+begin_orgx_{comp-name}&lt;/code&gt; syntax:
&lt;/p&gt;&lt;pre id="org78eb610" class="example"&gt;#+attr_orgx_defui: true
#+begin_orgx_my-note
*@@orgx:(or (:note-text props) &amp;quot;Tip&amp;quot;)@@*
#+begin_orgx
(:children props)
#+end_orgx
#+end_orgx_my-note
&lt;/pre&gt;&lt;p&gt;
As shown in the example, we can use normal Org syntax along with OrgX snippets. We can also access the properties with the &lt;code&gt;props&lt;/code&gt; variable.
&lt;/p&gt;&lt;p&gt;
In the above example we have defined a &lt;code&gt;my-note&lt;/code&gt; component, we can then use it with any aforementioned methods.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Example Usage:&lt;/i&gt;&lt;pre id="org54e2523" class="example"&gt;#+begin_orgx_my-note
This is a note!
#+end_orgx_my-note
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;p&gt;
&lt;b&gt;Tip&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;
This is a note!
&lt;/p&gt;

&lt;!-- --&gt;

&lt;!-- --&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-inline-orgx-with-macros" class="outline-3"&gt;&lt;a href="#inline-orgx-with-macros"&gt;&lt;h3 id="inline-orgx-with-macros" class="cr-self-reference "&gt;Inline OrgX with Macros&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-inline-orgx-with-macros" class="outline-text-3"&gt;&lt;p&gt;
Currently no similar syntax for inline OrgX is supported, however, it is fairly easy to make life easier with macros. Let&amp;#x27;s go back to use &lt;code&gt;my-button&lt;/code&gt; as the example.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 lg:grid-cols-[minmax(0,1fr)_minmax(0,0.5fr)]"&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Inline OrgX with Macro:&lt;/i&gt;&lt;p&gt;
We can define a macro like:
&lt;/p&gt;
&lt;pre id="org2cb14d6" class="example"&gt;#+MACRO: my-button @@orgx:($ my-button {:callback (or $2 nil)} $1)@@
&lt;/pre&gt;


&lt;p&gt;
And then use it with:
&lt;/p&gt;
&lt;pre id="org0f1468f" class="example"&gt;{{{my-button(&amp;quot;Using Macro&amp;quot;, #?(:cljs (fn [] (js/alert &amp;quot;Hello From Macro!&amp;quot;))))}}}
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;p&gt;
&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Using Macro&lt;/button&gt;
&lt;/p&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-builtin-components" class="outline-2"&gt;&lt;a href="#builtin-components"&gt;&lt;h2 id="builtin-components" class="cr-self-reference "&gt;Builtin Components&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-builtin-components" class="outline-text-2"&gt;&lt;p&gt;
The blogging program provides several builtin components, I will briefly describe their features.
&lt;/p&gt;&lt;/div&gt;&lt;div id="outline-container-simple-remarks" class="outline-3"&gt;&lt;a href="#simple-remarks"&gt;&lt;h3 id="simple-remarks" class="cr-self-reference "&gt;Simple Notice Blocks&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-simple-remarks" class="outline-text-3"&gt;&lt;p&gt;
It provides most commons blocks like &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;note&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt; and &lt;code&gt;error&lt;/code&gt;.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Remarks:&lt;/i&gt;&lt;pre id="orgf924c87" class="example"&gt;#+begin_orgx_info
This is an info
#+end_orgx_info

#+begin_orgx_note
This is a note
#+end_orgx_note

#+begin_orgx_warn
This is a warn
#+end_orgx_warn

#+begin_orgx_error
This is an error
#+end_orgx_error

&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-lime-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
This is an info
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
This is a note
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-rose-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
This is a warn
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-red-600"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
This is an error
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-tabs" class="outline-3"&gt;&lt;a href="#tabs"&gt;&lt;h3 id="tabs" class="cr-self-reference "&gt;Tabs&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-tabs" class="outline-text-3"&gt;&lt;p&gt;&lt;code&gt;tabs&lt;/code&gt; is like tabs in a browser or a text editor.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;tabs usage:&lt;/i&gt;&lt;pre id="orgba7f7a5" class="example"&gt;#+begin_orgx
($ tabs {:tab-list [{:name &amp;quot;tabs.clj&amp;quot; :content ($ code_tabs)}
                    {:name &amp;quot;tabs usage&amp;quot; :content ($ tabs_example)}]})
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Rendering:&lt;/i&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;tabs.clj:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; tabs [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [tab-list default-table class]}]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [[selected-tab set-selected-tab!] (&lt;span class="hljs-name"&gt;use-state&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; default-table
                                                        (&lt;span class="hljs-symbol"&gt;:name&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; tab-list))))]
    ($ &lt;span class="hljs-symbol"&gt;:div.my-4.relative.border-sky-300.border-l-2.border-l-neutral-100&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; class}
       ($ &lt;span class="hljs-symbol"&gt;:div.my-0.flex.relative.bg-neutral-100&lt;/span&gt;
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [name]}]
                 ($ &lt;span class="hljs-symbol"&gt;:button.font-medium.text-neutral-700.bg-neutral-50.py-1.px-2.border-t-2.border-neutral-50.min-w-28.bg-neutral-50.border-t-neutral-100&lt;/span&gt;
                    {&lt;span class="hljs-symbol"&gt;:key&lt;/span&gt; name
                     &lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; name selected-tab)
                              &lt;span class="hljs-string"&gt;&amp;quot; text-sky-800 border-sky-400 bg-sky-100 border-t-sky-400&amp;quot;&lt;/span&gt;)
                     &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; []
                                 #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt;
                                    (&lt;span class="hljs-name"&gt;set-selected-tab!&lt;/span&gt; name)))}
                    name))
               tab-list))
       ($ &lt;span class="hljs-symbol"&gt;:div.my-0.bg-neutral-50.overflow-hidden.px-2.h-full&lt;/span&gt;
          (&lt;span class="hljs-symbol"&gt;:content&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;filter&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [name]}]
                                     (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; name selected-tab))
                                   tab-list)))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;div class="hidden"&gt;&lt;i&gt;tabs usage:&lt;/i&gt;&lt;pre id="orgba7f7a5" class="example"&gt;#+begin_orgx
($ tabs {:tab-list [{:name &amp;quot;tabs.clj&amp;quot; :content ($ code_tabs)}
                    {:name &amp;quot;tabs usage&amp;quot; :content ($ tabs_example)}]})
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-split-layout" class="outline-3"&gt;&lt;a href="#split-layout"&gt;&lt;h3 id="split-layout" class="cr-self-reference "&gt;Split Layout&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-split-layout" class="outline-text-3"&gt;&lt;p&gt;
Split layout lets you show two things side by side:
&lt;/p&gt;&lt;pre id="org2aaa82a" class="example"&gt;#+attr_orgx_defui: true
#+begin_orgx_split_1
#+begin_src clojure
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
              :on-click (fn [&amp;amp; _]
                          #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))}
     &amp;quot;Click Me&amp;quot;)
#+end_src
#+end_orgx_split_1

#+attr_orgx_defui: true
#+begin_orgx_split_2
#+begin_orgx
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
              :on-click (fn [&amp;amp; _]
                          #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))}
     &amp;quot;Click Me&amp;quot;)
#+end_orgx
#+end_orgx_split_2

#+begin_orgx
($ split-layout
($ tabs {:tab-list [{:name &amp;quot;button&amp;quot; :content ($ split_1)}]})
($ tabs {:tab-list [{:name &amp;quot;showcase&amp;quot; :content ($ split_2)}]}))
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
Will be rendered as:
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;button:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;($ &lt;span class="hljs-symbol"&gt;:button&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;&lt;/span&gt;
            &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [&amp;amp; _]
                        #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt; (&lt;span class="hljs-name"&gt;js/alert&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;clicked!&amp;quot;&lt;/span&gt;)))}
   &lt;span class="hljs-string"&gt;&amp;quot;Click Me&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;showcase:&lt;/i&gt;&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-showcase" class="outline-3"&gt;&lt;a href="#showcase"&gt;&lt;h3 id="showcase" class="cr-self-reference "&gt;Showcase&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-showcase" class="outline-text-3"&gt;&lt;p&gt;
Showcase is a simple wrapper over &lt;code&gt;split-layout&lt;/code&gt; and &lt;code&gt;tabs&lt;/code&gt;. The &lt;code&gt;showcase&lt;/code&gt; component is used extensive in this post, such as the example in &lt;a href="#simple-remarks"&gt;Simple Notice Blocks&lt;/a&gt; is coded as:
&lt;/p&gt;&lt;pre id="orga398f69" class="example"&gt;#+attr_orgx_defui: true
#+begin_orgx_remarks_example
#+begin_example
#+begin_orgx_info
This is an info
#+end_orgx_info

#+begin_orgx_note
This is a note
#+end_orgx_note

#+begin_orgx_warn
This is a warn
#+end_orgx_warn

#+begin_orgx_error
This is an error
#+end_orgx_error

#+end_example
#+end_orgx_remarks_example

#+attr_orgx_defui: true
#+begin_orgx_remarks_result
#+begin_orgx_info
This is an info
#+end_orgx_info
#+begin_orgx_note
This is a note
#+end_orgx_note
#+begin_orgx_warn
This is a warn
#+end_orgx_warn
#+begin_orgx_error
This is an error
#+end_orgx_error
#+end_orgx_remarks_result

#+begin_orgx
($ showcase {:showcase-name &amp;quot;Rendering&amp;quot;}
  ($ tabs {:tab-list [{:name &amp;quot;Remarks&amp;quot; :content ($ remarks_example)}]})
  ($ remarks_result))
#+end_orgx
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-conclusions" class="outline-2"&gt;&lt;a href="#conclusions"&gt;&lt;h2 id="conclusions" class="cr-self-reference "&gt;Conclusions&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-conclusions" class="outline-text-2"&gt;&lt;/div&gt;&lt;div id="outline-container-caveats" class="outline-3"&gt;&lt;a href="#caveats"&gt;&lt;h3 id="caveats" class="cr-self-reference "&gt;Caveats&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-caveats" class="outline-text-3"&gt;&lt;p&gt;
Although I have extensively used it in this demostration and will definitely use it in the future, there are some notably deficiency with the current implementation.
&lt;/p&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;You need to read the logging to understand the problem if anything goes wrong. If you want to do SSR or SSG, the fact that the same code must be run on the JVM and the browser and produce the same result adds complexity.&lt;/li&gt;&lt;li&gt;The syntax still feels cumbersome in many cases, but that might be improved in the future.&lt;/li&gt;&lt;li&gt;The current implementation requires Emacs itself to convert the Org files into HTML, and Clojure code will then process the HTML. The most notably advantage of this method is that we can use the (basically) the full power of Org mode. However, it is also a lot of moving parts.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-future-plans" class="outline-3"&gt;&lt;a href="#future-plans"&gt;&lt;h3 id="future-plans" class="cr-self-reference "&gt;Future Plans&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-future-plans" class="outline-text-3"&gt;&lt;p&gt;
I will describe the process of implement it in the next post of this series. Current the code is still coupled with my blogging program. I&amp;#x27;m planning on make it a separate library in the future.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Watching Files with java.nio.file.WatchService and Clojure</title>
    <link href="https://coruscation.net/blogs/watching-files-with-java-nio-file-watchservice-and-clojure.html"/>
    <published>2025-12-13T22:18:29+08:00</published>
    <updated>2025-12-14T00:36:14+08:00</updated>
    <id>https://coruscation.net/blogs/watching-files-with-java-nio-file-watchservice-and-clojure.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
Recently I want to have a utility in Clojure that can notify me when there is a change happened in some specified directory. Fortunately Java seems to natively support it by providing a &lt;code&gt;java.nio.file.WatchService&lt;/code&gt;. It seems trivial so I want to use it directly in Clojure instead of adding another dependency to my project. It turns out to be sightly more complicated than I expected. Let me explain.
&lt;/p&gt;
&lt;div id="outline-container-the-problem" class="outline-2"&gt;
&lt;a href="#the-problem"&gt;&lt;h2 id="the-problem" class="cr-self-reference "&gt;The Problem&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-the-problem"&gt;
&lt;p&gt;
The challenge mainly lies in the fact that, Java doesn't natively support recursively watching a directory. If we want this behavoir, we have to implement it ourselves.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; ^&lt;span class="hljs-symbol"&gt;:dynamic&lt;/span&gt; &lt;span class="hljs-title"&gt;*chan-size*&lt;/span&gt; &lt;span class="hljs-number"&gt;512&lt;/span&gt;)

(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;register&lt;/span&gt; [^Path path ^WatchService watch-service]
  (&lt;span class="hljs-name"&gt;.register&lt;/span&gt; path
             watch-service
             (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; WatchEvent$Kind
                         [StandardWatchEventKinds/ENTRY_CREATE
                          StandardWatchEventKinds/ENTRY_DELETE
                          StandardWatchEventKinds/ENTRY_MODIFY
                          StandardWatchEventKinds/OVERFLOW])))

(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;watch&lt;/span&gt; [&amp;amp; paths]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [resp-chan (&lt;span class="hljs-name"&gt;a/chan&lt;/span&gt; *chan-size*)
        cancel-chan (&lt;span class="hljs-name"&gt;a/chan&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt;)
        stopped? (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;atom&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt;)

        worker
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;future&lt;/span&gt;&lt;/span&gt;
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [paths (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [p]
                             (&lt;span class="hljs-name"&gt;Path/of&lt;/span&gt; p (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; String [])))
                           paths)
                watch-service (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;java.nio.file.FileSystems/getDefault&lt;/span&gt;)
                                  (&lt;span class="hljs-name"&gt;.newWatchService&lt;/span&gt;))]
            (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [path paths]
              (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [^File subpath-file (&lt;span class="hljs-name"&gt;file-seq&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; path))]
                (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.isDirectory&lt;/span&gt; subpath-file)
                  (&lt;span class="hljs-name"&gt;register&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toPath&lt;/span&gt; subpath-file)
                            watch-service))))
            (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;try&lt;/span&gt;&lt;/span&gt;
              (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;while&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;not&lt;/span&gt;&lt;/span&gt; @stopped?)
                (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [watch-key (&lt;span class="hljs-name"&gt;.take&lt;/span&gt; watch-service)
                      events (&lt;span class="hljs-name"&gt;.pollEvents&lt;/span&gt; watch-key)
                      ^Path parent-dir (&lt;span class="hljs-name"&gt;.watchable&lt;/span&gt; watch-key)]
                  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [^WatchEvent event events]
                    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [^WatchEvent$Kind kind (&lt;span class="hljs-name"&gt;.kind&lt;/span&gt; event)
                          ^Path event-path (&lt;span class="hljs-name"&gt;.context&lt;/span&gt; event)
                          ^Path resolved-path (&lt;span class="hljs-name"&gt;.resolve&lt;/span&gt; parent-dir event-path)]
                      (&lt;span class="hljs-name"&gt;a/&amp;gt;!!&lt;/span&gt; resp-chan
                             {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;case&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.name&lt;/span&gt; kind)
                                      &lt;span class="hljs-string"&gt;&amp;quot;ENTRY_CREATE&amp;quot;&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-create&lt;/span&gt;
                                      &lt;span class="hljs-string"&gt;&amp;quot;ENTRY_MODIFY&amp;quot;&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-modify&lt;/span&gt;
                                      &lt;span class="hljs-string"&gt;&amp;quot;ENTRY_DELETE&amp;quot;&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-delete&lt;/span&gt;
                                      &lt;span class="hljs-string"&gt;&amp;quot;OVERFLOW&amp;quot;&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:overflow&lt;/span&gt;)
                              &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; resolved-path})

                      &lt;span class="hljs-comment"&gt;;; If the newly created object is a directory,&lt;/span&gt;
                      &lt;span class="hljs-comment"&gt;;;   we recursively register files in it.&lt;/span&gt;
                          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;and&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; kind StandardWatchEventKinds/ENTRY_CREATE)
                                 (&lt;span class="hljs-name"&gt;.isDirectory&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; resolved-path)))
                        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [^File subpath-file (&lt;span class="hljs-name"&gt;file-seq&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; resolved-path))]
                          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.isDirectory&lt;/span&gt; subpath-file)
                            (&lt;span class="hljs-name"&gt;register&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toPath&lt;/span&gt; subpath-file)
                                      watch-service))))
                      (&lt;span class="hljs-name"&gt;.reset&lt;/span&gt; watch-key)))))
              (&lt;span class="hljs-name"&gt;catch&lt;/span&gt; InterruptedException _)
              (&lt;span class="hljs-name"&gt;finally&lt;/span&gt;
                (&lt;span class="hljs-name"&gt;.close&lt;/span&gt; watch-service)))))

        sentinel (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;future&lt;/span&gt;&lt;/span&gt;
                   (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;while&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;not&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;a/&amp;lt;!!&lt;/span&gt; cancel-chan)))
                   (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;reset!&lt;/span&gt;&lt;/span&gt; stopped? &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
                   (&lt;span class="hljs-name"&gt;future-cancel&lt;/span&gt; worker)
                   (&lt;span class="hljs-name"&gt;a/close!&lt;/span&gt; resp-chan)
                   (&lt;span class="hljs-name"&gt;a/close!&lt;/span&gt; cancel-chan))]
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;with-meta&lt;/span&gt;&lt;/span&gt; [resp-chan cancel-chan]
      {&lt;span class="hljs-symbol"&gt;:debug&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:worker&lt;/span&gt; worker
               &lt;span class="hljs-symbol"&gt;:sentinel&lt;/span&gt; sentinel
               &lt;span class="hljs-symbol"&gt;:stopped?&lt;/span&gt; stopped?}})))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The initial implementation looks like this, which is fairly straightforward. We start by recursively registering files in the directories provided by &lt;code&gt;paths&lt;/code&gt; argument, and if there is a newly created directory, we also recursively register its contents. Clojure provides a &lt;code&gt;file-seq&lt;/code&gt; function that makes this task much easier. For an example usage of this code, check the end of this post.
&lt;/p&gt;

&lt;p&gt;
However, there is only one issue: If a file is created in a subdirectory before the subdirectory got registered, the event won't be fired.
&lt;/p&gt;

&lt;pre class="example" id="orgabed38f"&gt;+---------------+
| worker thread |
+-------+-------+
        +                 +---------------+
        +-----------------| create subdir |
        |                 +---------------+
+-------+---------------+
| event: subdir created |
+-------+---------------+    
        |                 +------------------------+
        +-----------------+ new file in the subdir |
        |                 +------------------------+
+-------+-----------+
| subdir registered |
+-------------------+
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-the-workaround" class="outline-2"&gt;
&lt;a href="#the-workaround"&gt;&lt;h2 id="the-workaround" class="cr-self-reference "&gt;The Workaround&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-the-workaround"&gt;
&lt;p&gt;
We can have a workaround of this by emitting an event of each file in the newly created directory, like this:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;and&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; kind StandardWatchEventKinds/ENTRY_CREATE)
           (&lt;span class="hljs-name"&gt;.isDirectory&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; resolved-path)))

  (&lt;span class="hljs-name"&gt;register&lt;/span&gt; resolved-path
            watch-service)

  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [^File subpath-file (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;file-seq&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toFile&lt;/span&gt; resolved-path)))]
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.isDirectory&lt;/span&gt; subpath-file)
      (&lt;span class="hljs-name"&gt;register&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toPath&lt;/span&gt; subpath-file)
                watch-service))
    (&lt;span class="hljs-name"&gt;a/&amp;gt;!!&lt;/span&gt; resp-chan
           {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-create&lt;/span&gt;
            &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toPath&lt;/span&gt; subpath-file)})))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
However, it introduces a new problem. If a file is created in a subdirectory after be subdirectory is regsitered, but before the subdirectories scanning is finished. The event of the file may be emitted twice.
&lt;/p&gt;

&lt;pre class="example" id="org267513e"&gt;  +---------------+
  | worker thread |
  +-------+-------+
          +                +----------------+
          +----------------+ subdir created |
          |                +----------------+
          |
 +--------+----------+
 | subdir registered |
 +--------+----------+
          |              +-------------------------+
          |--------------+ file1 created in subdir |
          |              +-------------------------+
 +--------+---------+
 | scan: find file1 |
 +--------+---------+  
          |               
          |               
+---------+------------+ 
| event: file1 created |
+----------------------+      
&lt;/pre&gt;

&lt;p&gt;
We have three choices here, we can:
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;ignore this issue, treat it as something acceptable.&lt;/li&gt;
&lt;li&gt;discard the workaround all together, let the user scan if there is any new file in the newly created directory.&lt;/li&gt;
&lt;li&gt;memorize all the files detected, check if the event has already been fired if a new file is detected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
In my case, the first option is good enough, however, it got me curious about how this issue is handled by other projects.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-how-is-it-handled-by-other-projects?" class="outline-2"&gt;
&lt;a href="#how-is-it-handled-by-other-projects?"&gt;&lt;h2 id="how-is-it-handled-by-other-projects?" class="cr-self-reference "&gt;How is it Handled by Other Projects?&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-how-is-it-handled-by-other-projects?"&gt;
&lt;/div&gt;
&lt;div id="outline-container-chokidar" class="outline-3"&gt;
&lt;a href="#chokidar"&gt;&lt;h3 id="chokidar" class="cr-self-reference "&gt;chokidar&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-chokidar"&gt;
&lt;p&gt;
&lt;a href="https://github.com/paulmillr/chokidar"&gt;chokidar&lt;/a&gt; is a famous file watching library in JavaScript. It seems to have chosen the third option:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-typescript"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;// handler.ts&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// line starting from 575&lt;/span&gt;

&lt;span class="hljs-comment"&gt;// Files that present in current directory snapshot&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// but absent in previous are added to watch list and&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// emit `add` event.&lt;/span&gt;
&lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (item === target || (!target &amp;amp;&amp;amp; !previous.&lt;span class="hljs-title function_"&gt;has&lt;/span&gt;(item))) {
  &lt;span class="hljs-variable language_"&gt;this&lt;/span&gt;.&lt;span class="hljs-property"&gt;fsw&lt;/span&gt;.&lt;span class="hljs-title function_"&gt;_incrReadyCount&lt;/span&gt;();

  &lt;span class="hljs-comment"&gt;// ensure relativeness of path is preserved in case of watcher reuse&lt;/span&gt;
  path = sp.&lt;span class="hljs-title function_"&gt;join&lt;/span&gt;(dir, sp.&lt;span class="hljs-title function_"&gt;relative&lt;/span&gt;(dir, path));

  &lt;span class="hljs-variable language_"&gt;this&lt;/span&gt;.&lt;span class="hljs-title function_"&gt;_addToNodeFs&lt;/span&gt;(path, initialAdd, wh, depth + &lt;span class="hljs-number"&gt;1&lt;/span&gt;);
}
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-inotify-tools" class="outline-3"&gt;
&lt;a href="#inotify-tools"&gt;&lt;h3 id="inotify-tools" class="cr-self-reference "&gt;inotify-tools&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-inotify-tools"&gt;
&lt;p&gt;
&lt;a href="https://github.com/inotify-tools/inotify-tools"&gt;inotify-tools&lt;/a&gt; is a set of cli tools providing interface to &lt;code&gt;inotify&lt;/code&gt;. It was written in C++ and newer version is rewritten in Rust.
&lt;/p&gt;

&lt;p&gt;
By default, &lt;code&gt;inotify-wait&lt;/code&gt; quits after it detected a change. Therefore the problem described in the previous section is naturally up to the user to solve.
&lt;/p&gt;

&lt;p&gt;
It also provides an &lt;code&gt;--monitor&lt;/code&gt; option to continuously monitoring the changes happened in a directory. With &lt;code&gt;--monitor&lt;/code&gt; on, it seems to choose the second option described in the previous section.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&amp;gt; inotifywait -mr -e create .

Setting up watches.  Beware: since -r was given, this may take a &lt;span class="hljs-keyword"&gt;while&lt;/span&gt;!
Watches established.

&lt;span class="hljs-comment"&gt;# executing `mkdir -p s1/s2/s3/s4` in another shell session&lt;/span&gt;

./ CREATE,ISDIR s1
Watching new directory ./s1/
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If we create the directories one by one, all the directories will be notified. However, by using &lt;code&gt;-p&lt;/code&gt; option to create multiple level of directories at once. Only the first one will be notified.
&lt;/p&gt;

&lt;p&gt;
We can further confirm it by reading the source code:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-cpp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;// inotifywait.cpp&lt;/span&gt;
&lt;span class="hljs-comment"&gt;// L391, main function&lt;/span&gt;

&lt;span class="hljs-keyword"&gt;do&lt;/span&gt; {
  event = &lt;span class="hljs-built_in"&gt;inotifytools_next_event&lt;/span&gt;(timeout);

  &lt;span class="hljs-comment"&gt;/*
   * ......
   */&lt;/span&gt;

  &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (monitor &amp;amp;&amp;amp; recursive) {
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; ((event-&amp;gt;mask &amp;amp; IN_CREATE) ||
        (!moved_from &amp;amp;&amp;amp; (event-&amp;gt;mask &amp;amp; IN_MOVED_TO))) {
      &lt;span class="hljs-comment"&gt;// New file - if it is a directory, watch it&lt;/span&gt;
      &lt;span class="hljs-type"&gt;char&lt;/span&gt; *new_file = &lt;span class="hljs-built_in"&gt;inotifytools_dirpath_from_event&lt;/span&gt;(event);
      &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (new_file &amp;amp;&amp;amp; *new_file &amp;amp;&amp;amp; &lt;span class="hljs-built_in"&gt;isdir&lt;/span&gt;(new_file)) {
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (!quiet) {
          &lt;span class="hljs-built_in"&gt;output_error&lt;/span&gt;(sysl, &lt;span class="hljs-string"&gt;&amp;quot;Watching new directory %s\n&amp;quot;&lt;/span&gt;, new_file);
        }
        &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (!&lt;span class="hljs-built_in"&gt;inotifytools_watch_recursively&lt;/span&gt;(new_file, events)) {
          &lt;span class="hljs-built_in"&gt;output_error&lt;/span&gt;(sysl, &lt;span class="hljs-string"&gt;&amp;quot;Couldn't watch new directory %s: %s\n&amp;quot;&lt;/span&gt;, new_file,
                       &lt;span class="hljs-built_in"&gt;strerror&lt;/span&gt;(&lt;span class="hljs-built_in"&gt;inotifytools_error&lt;/span&gt;()));
        }
      }
      &lt;span class="hljs-built_in"&gt;free&lt;/span&gt;(new_file);
    } 

    &lt;span class="hljs-comment"&gt;/*
     * ......
     */&lt;/span&gt;
  }
  &lt;span class="hljs-built_in"&gt;fflush&lt;/span&gt;(&lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;);
} &lt;span class="hljs-keyword"&gt;while&lt;/span&gt; (monitor)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The program constantly polls and prints new events in the main function. If the newly created object is a directory and &lt;code&gt;--recursive&lt;/code&gt; option is on, it recursively watch the newly created directory. However, it won't print files in the new directory if we check the &lt;code&gt;inotifytools_watch_recursively&lt;/code&gt; function.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-conclusion" class="outline-2"&gt;
&lt;a href="#conclusion"&gt;&lt;h2 id="conclusion" class="cr-self-reference "&gt;Conclusion&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-conclusion"&gt;
&lt;p&gt;
There doesn't seem to a definitive solution to this issue. The workaround described in &lt;a href="#the-workaround"&gt;section 2&lt;/a&gt; seems to be good enough in my case. I will conclude this post by posing a simple example usage of the code with the workaround applied.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;deftest&lt;/span&gt; wach_service_example
  (&lt;span class="hljs-name"&gt;testing&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [test-dir (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; *test-dir* &lt;span class="hljs-string"&gt;&amp;quot;/example&amp;quot;&lt;/span&gt;)]
      (&lt;span class="hljs-name"&gt;.mkdirs&lt;/span&gt; (&lt;span class="hljs-name"&gt;io/file&lt;/span&gt; test-dir))
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [[resp cancel] (&lt;span class="hljs-name"&gt;subject/watch&lt;/span&gt; test-dir)
            worker (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;future&lt;/span&gt;&lt;/span&gt;
                     (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;loop&lt;/span&gt;&lt;/span&gt; [event (&lt;span class="hljs-name"&gt;a/&amp;lt;!!&lt;/span&gt; resp)
                            result (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;transient&lt;/span&gt;&lt;/span&gt; [])]
                       (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;not&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;nil?&lt;/span&gt;&lt;/span&gt; event))
                         (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;recur&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;a/&amp;lt;!!&lt;/span&gt; resp)
                                (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;conj!&lt;/span&gt;&lt;/span&gt; result
                                       {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; event)
                                        &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; (&lt;span class="hljs-name"&gt;.toString&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; event))}))
                         (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;persistent!&lt;/span&gt;&lt;/span&gt; result))))]
        (&lt;span class="hljs-name"&gt;.sleep&lt;/span&gt; java.util.concurrent.TimeUnit/MILLISECONDS &lt;span class="hljs-number"&gt;200&lt;/span&gt;)
        (&lt;span class="hljs-name"&gt;.mkdirs&lt;/span&gt; (&lt;span class="hljs-name"&gt;io/file&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; test-dir &lt;span class="hljs-string"&gt;&amp;quot;/s1/s2&amp;quot;&lt;/span&gt;)))
        (&lt;span class="hljs-name"&gt;.createNewFile&lt;/span&gt; (&lt;span class="hljs-name"&gt;io/file&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; test-dir &lt;span class="hljs-string"&gt;&amp;quot;/s1/s2/file&amp;quot;&lt;/span&gt;)))
        &lt;span class="hljs-comment"&gt;;; We can't delete the files too quickly after they are created,&lt;/span&gt;
        &lt;span class="hljs-comment"&gt;;;    otherwise we will receive no event.&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;.sleep&lt;/span&gt; java.util.concurrent.TimeUnit/MILLISECONDS &lt;span class="hljs-number"&gt;200&lt;/span&gt;)
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [f (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;reverse&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;file-seq&lt;/span&gt; (&lt;span class="hljs-name"&gt;io/file&lt;/span&gt; test-dir))))]
          (&lt;span class="hljs-name"&gt;.delete&lt;/span&gt; f))
        (&lt;span class="hljs-name"&gt;.sleep&lt;/span&gt; java.util.concurrent.TimeUnit/MILLISECONDS &lt;span class="hljs-number"&gt;200&lt;/span&gt;)
        &lt;span class="hljs-comment"&gt;;; shutdown the watch service&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;a/&amp;gt;!!&lt;/span&gt; cancel &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)

        &lt;span class="hljs-comment"&gt;;; verify the result&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;is&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; [{&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-create&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;		  
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1&amp;quot;&lt;/span&gt;}
                        {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-create&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1/s2&amp;quot;&lt;/span&gt;}
                        {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-create&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1/s2/file&amp;quot;&lt;/span&gt;}
                        {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-delete&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1/s2/file&amp;quot;&lt;/span&gt;}
                        {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-delete&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1/s2&amp;quot;&lt;/span&gt;}
                        {&lt;span class="hljs-symbol"&gt;:kind&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:entry-delete&lt;/span&gt;&lt;span class="hljs-punctuation"&gt;,&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;test/resource/watch_service_test/example/s1&amp;quot;&lt;/span&gt;}]
               @worker))))))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can also find the source code and some unit tests &lt;a href="https://gist.github.com/imakira/4b537a13ecd8c1816427068d10777565"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">My Experience with lsp-bridge</title>
    <link href="https://coruscation.net/blogs/my-experience-with-lsp-bridge.html"/>
    <published>2025-11-22T23:33:09+08:00</published>
    <updated>2025-11-25T16:23:27+08:00</updated>
    <id>https://coruscation.net/blogs/my-experience-with-lsp-bridge.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
The experience of using &lt;code&gt;lsp-mode&lt;/code&gt; or &lt;code&gt;elgot&lt;/code&gt; depends heavily on the lsp server you are using and the project you are working on. With the newly added JSON parser in Emacs 30 and the garbage collecting improvements in the &lt;a href="https://github.com/emacs-mirror/emacs/blob/feature/igc/README-IGC"&gt;igc branch&lt;/a&gt;, the experience of &lt;code&gt;lsp-mode&lt;/code&gt; or &lt;code&gt;eglot&lt;/code&gt; can be more than good enough. Still, if you are using the more demanding lsp server (like some language servers for frontend development) or working on a larger-size project, the experience could still be unsatisfying or even super frustrating. If you have ever experienced Emacs freezing after checkout to another git branch or big gc lag when using &lt;code&gt;gcmh-mode&lt;/code&gt;, you could still consider giving &lt;code&gt;lsp-bridge&lt;/code&gt; a try.
&lt;/p&gt;

&lt;p&gt;
In exchange for speed and fluency, &lt;code&gt;lsp-bridge&lt;/code&gt; replaces every builtin and well known tools that aren't suitable for async operations, including but not limited to &lt;code&gt;completion-at-point&lt;/code&gt;, &lt;code&gt;xref&lt;/code&gt;, &lt;code&gt;eldoc&lt;/code&gt;. This prevents a lot of users from ever trying it, and that's reasonable. However, the async nature of &lt;code&gt;lsp-bridge&lt;/code&gt; also brings its own advantages.
&lt;/p&gt;

&lt;p&gt;
For a small example, consider that even the &lt;code&gt;go-to-definition&lt;/code&gt; operation in &lt;code&gt;lsp-bridge&lt;/code&gt; is asynchronous. With other lsp clients, Emacs is stuck between the time you call &lt;code&gt;xref-find-definitions&lt;/code&gt; and the lsp server returns a response. With &lt;code&gt;lsp-bridge&lt;/code&gt;, even if you are waiting for a response, Emacs is free to do other things in the meantime, such as doing a garbage collection, or executing a callback registered by &lt;code&gt;run-with-idle-timer&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Finally, you certainly can use lsp-bridge only for some modes and keep using &lt;code&gt;completion-at-point&lt;/code&gt; for other modes. That's also what I'm doing.
&lt;/p&gt;
&lt;div id="outline-container-basic-setup" class="outline-2"&gt;
&lt;a href="#basic-setup"&gt;&lt;h2 id="basic-setup" class="cr-self-reference "&gt;Basic Setup&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-basic-setup"&gt;
&lt;p&gt;
To use &lt;code&gt;lsp-bridge&lt;/code&gt;, you first need to install some external dependencies.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;pip3 install epc orjson sexpdata six setuptools paramiko rapidfuzz watchdog packaging
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
If you are using Nix, you need to add a python package with dependencies to your Nix config files.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(python3.withPackages (
      &lt;span class="hljs-params"&gt;ps:&lt;/span&gt; &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; ps; [
        &lt;span class="hljs-comment"&gt;# ...&lt;/span&gt;
        epc
        orjson
        packaging
        paramiko
        rapidfuzz
        setuptools
        sexpdata
        six
        watchdog
      ]
    ))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
With external dependencies installed, now we can install the &lt;code&gt;lsp-bridge&lt;/code&gt; package. Here's how I have done it with &lt;code&gt;straight&lt;/code&gt; and &lt;code&gt;use-package&lt;/code&gt;.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;use-package&lt;/span&gt; lsp-bridge
  &lt;span class="hljs-symbol"&gt;:hook&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;clojure-mode&lt;/span&gt; . lsp-bridge-mode)
  (&lt;span class="hljs-name"&gt;clojure-ts-mode&lt;/span&gt; . lsp-bridge-mode)
  (&lt;span class="hljs-name"&gt;typescript-ts-mode&lt;/span&gt; . lsp-bridge-mode)
  (&lt;span class="hljs-name"&gt;js-ts-mode&lt;/span&gt; . lsp-bridge-mode)
  (&lt;span class="hljs-name"&gt;java-ts-mode&lt;/span&gt; . lsp-bridge-mode)
  &lt;span class="hljs-symbol"&gt;:straight&lt;/span&gt; '(lsp-bridge &lt;span class="hljs-symbol"&gt;:type&lt;/span&gt; git &lt;span class="hljs-symbol"&gt;:host&lt;/span&gt; github &lt;span class="hljs-symbol"&gt;:repo&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;manateelazycat/lsp-bridge&amp;quot;&lt;/span&gt;
                         &lt;span class="hljs-symbol"&gt;:files&lt;/span&gt; (:defaults &lt;span class="hljs-string"&gt;&amp;quot;*.el&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;*.py&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;acm&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;core&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;langserver&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;multiserver&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;resources&amp;quot;&lt;/span&gt;)
                         &lt;span class="hljs-symbol"&gt;:build&lt;/span&gt; (:not compile))

  &lt;span class="hljs-symbol"&gt;:init&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-corfu-hook ()
    (&lt;span class="hljs-name"&gt;when&lt;/span&gt; (&lt;span class="hljs-name"&gt;and&lt;/span&gt; lsp-bridge-mode
               (&lt;span class="hljs-name"&gt;boundp&lt;/span&gt; 'corfu-mode)
               corfu-mode)
      (&lt;span class="hljs-name"&gt;corfu-mode&lt;/span&gt; &lt;span class="hljs-number"&gt;-1&lt;/span&gt;)))
  (&lt;span class="hljs-name"&gt;add-hook&lt;/span&gt; 'corfu-mode-hook #'me/lsp-bridge-corfu-hook))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here I only enabled &lt;code&gt;lsp-bridge-mode&lt;/code&gt; for modes in the &lt;code&gt;:hook&lt;/code&gt; part, and I disabled &lt;code&gt;corfu&lt;/code&gt; in &lt;code&gt;lsp-bridge-mode-hook&lt;/code&gt; (I'm still using it for other programming or writing tasks).
&lt;/p&gt;

&lt;p&gt;
Unlike &lt;code&gt;lsp-mode&lt;/code&gt;, lsp-bridge doesn't provide a lsp server installation function. Check &lt;a href="https://github.com/manateelazycat/lsp-bridge?tab=readme-ov-file#supported-language-servers"&gt;Supported language servers&lt;/a&gt; and their corresponding pages for installation methods.
&lt;/p&gt;

&lt;p&gt;
If the server is installed and &lt;code&gt;lsp-bridge-mode&lt;/code&gt; is enabled, it should just work without any other configurations. If it doesn't, set &lt;code&gt;lsp-bridge-enable-debug&lt;/code&gt; to true and check &lt;code&gt;*lsp-bridge*&lt;/code&gt; for error messages.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-configuration" class="outline-2"&gt;
&lt;a href="#configuration"&gt;&lt;h2 id="configuration" class="cr-self-reference "&gt;Configuration&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-configuration"&gt;
&lt;/div&gt;
&lt;div id="outline-container-keymapping" class="outline-3"&gt;
&lt;a href="#keymapping"&gt;&lt;h3 id="keymapping" class="cr-self-reference "&gt;Keymapping&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-keymapping"&gt;
&lt;p&gt;
lsp-bridge provides its xef and eldoc equivalents, but it's up to us to mapping them. Here is what I do just for a reference.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;general-evil-define-key&lt;/span&gt; '(normal) '(lsp-bridge-mode-map)
  &lt;span class="hljs-string"&gt;&amp;quot;s S&amp;quot;&lt;/span&gt; #'lsp-bridge-workspace-list-symbols
  &lt;span class="hljs-string"&gt;&amp;quot;s D&amp;quot;&lt;/span&gt; #'lsp-bridge-diagnostic-list
  &lt;span class="hljs-string"&gt;&amp;quot;s R&amp;quot;&lt;/span&gt; #'lsp-bridge-rename
  &lt;span class="hljs-string"&gt;&amp;quot;g d&amp;quot;&lt;/span&gt; #'lsp-bridge-find-def
  &lt;span class="hljs-string"&gt;&amp;quot;g r&amp;quot;&lt;/span&gt; #'lsp-bridge-find-references
  &lt;span class="hljs-string"&gt;&amp;quot;g D&amp;quot;&lt;/span&gt; #'lsp-bridge-find-impl
  &lt;span class="hljs-string"&gt;&amp;quot;C-RET&amp;quot;&lt;/span&gt; #'lsp-bridge-code-action
  &lt;span class="hljs-string"&gt;&amp;quot;C-&amp;lt;return&amp;gt;&amp;quot;&lt;/span&gt; #'lsp-bridge-code-action)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-a-little-hack-(minimum-popup-width)" class="outline-3"&gt;
&lt;a href="#a-little-hack-(minimum-popup-width)"&gt;&lt;h3 id="a-little-hack-(minimum-popup-width)" class="cr-self-reference "&gt;a Little Hack (minimum popup width)&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-a-little-hack-(minimum-popup-width)"&gt;
&lt;p&gt;
In corfu you can set minimum popup width with &lt;code&gt;corfu-min-width&lt;/code&gt;. &lt;code&gt;lsp-bridge~/~acm&lt;/code&gt; currently doesn't provide a way to do so. However it is relatively easy to hack one.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;setq&lt;/span&gt; me/acm-minimum-width &lt;span class="hljs-number"&gt;1000&lt;/span&gt;)

(&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/acm-minimum-width-function (&lt;span class="hljs-name"&gt;oldfun&lt;/span&gt; &lt;span class="hljs-symbol"&gt;&amp;amp;rest&lt;/span&gt; r)
  (&lt;span class="hljs-name"&gt;let&lt;/span&gt; ((&lt;span class="hljs-name"&gt;result&lt;/span&gt; (&lt;span class="hljs-name"&gt;apply&lt;/span&gt; oldfun r)))
    (&lt;span class="hljs-name"&gt;max&lt;/span&gt; me/acm-minimum-width result)))

(&lt;span class="hljs-name"&gt;advice-add&lt;/span&gt; 'acm-menu-max-length &lt;span class="hljs-symbol"&gt;:around&lt;/span&gt; #'me/acm-minimum-width-function)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-flymake" class="outline-3"&gt;
&lt;a href="#flymake"&gt;&lt;h3 id="flymake" class="cr-self-reference "&gt;flymake&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-flymake"&gt;
&lt;p&gt;
There is actually a third-party lsp-bridge integration for flymake. Check &lt;a href="https://github.com/eki3z/flymake-bridge"&gt;eki3z/flymake-bridge&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-workspace-management" class="outline-2"&gt;
&lt;a href="#workspace-management"&gt;&lt;h2 id="workspace-management" class="cr-self-reference "&gt;Workspace Management&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-workspace-management"&gt;
&lt;p&gt;
lsp-bridge's workspace detection depends entirely on &lt;code&gt;git&lt;/code&gt;. It simply use the nearest directory contains &lt;code&gt;.git&lt;/code&gt; as the workspace root. This may not be enough for some use cases. However, it provides a &lt;code&gt;lsp-bridge-get-project-path-by-filepath&lt;/code&gt; for us to customize. We can implement something similar to what lsp-mode provides fairly easily.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;require&lt;/span&gt; 'f)

&lt;span class="hljs-comment"&gt;;; assume savehist-mode is enabled&lt;/span&gt;
(&lt;span class="hljs-name"&gt;defvar&lt;/span&gt; me/lsp-bridge-workspaces (&lt;span class="hljs-name"&gt;list&lt;/span&gt;))
(&lt;span class="hljs-name"&gt;add-to-list&lt;/span&gt; 'savehist-additional-variables 'me/lsp-bridge-workspaces)

(&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-workspace-add (&lt;span class="hljs-name"&gt;project-root&lt;/span&gt;)
  (&lt;span class="hljs-name"&gt;interactive&lt;/span&gt;
   (&lt;span class="hljs-name"&gt;list&lt;/span&gt; (&lt;span class="hljs-name"&gt;read-directory-name&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Select folder:&amp;quot;&lt;/span&gt;)))
  (&lt;span class="hljs-name"&gt;add-to-list&lt;/span&gt; 'me/lsp-bridge-workspaces project-root))

(&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-workspace-remove (&lt;span class="hljs-name"&gt;project-root&lt;/span&gt;)
  (&lt;span class="hljs-name"&gt;interactive&lt;/span&gt; (&lt;span class="hljs-name"&gt;list&lt;/span&gt; (&lt;span class="hljs-name"&gt;completing-read&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Select folder to remove: &amp;quot;&lt;/span&gt;
                                      me/lsp-bridge-workspaces)))
  (&lt;span class="hljs-name"&gt;setq&lt;/span&gt; me/lsp-bridge-workspaces (&lt;span class="hljs-name"&gt;cl-remove&lt;/span&gt; project-root me/lsp-bridge-workspaces &lt;span class="hljs-symbol"&gt;:test&lt;/span&gt; #'equal)))

(&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-get-workspace (&lt;span class="hljs-name"&gt;path&lt;/span&gt;)
  (&lt;span class="hljs-name"&gt;cl-first&lt;/span&gt; (&lt;span class="hljs-name"&gt;cl-mapcar&lt;/span&gt; #'f-expand
                       (&lt;span class="hljs-name"&gt;cl-remove-if-not&lt;/span&gt; (&lt;span class="hljs-name"&gt;lambda&lt;/span&gt; (&lt;span class="hljs-name"&gt;workspace&lt;/span&gt;)
                                           (&lt;span class="hljs-name"&gt;if&lt;/span&gt; (&lt;span class="hljs-name"&gt;f-ancestor-of&lt;/span&gt;? (&lt;span class="hljs-name"&gt;f-expand&lt;/span&gt; workspace) path)
                                                   workspace                                  
                                             &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;))
                                         me/lsp-bridge-workspaces))))

(&lt;span class="hljs-name"&gt;setq&lt;/span&gt; lsp-bridge-get-project-path-by-filepath #'me/lsp-bridge-get-workspace)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-working-with-java" class="outline-2"&gt;
&lt;a href="#working-with-java"&gt;&lt;h2 id="working-with-java" class="cr-self-reference "&gt;Working with Java&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-working-with-java"&gt;
&lt;p&gt;
We need a few more lines of configuration to make it works with Java.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;use-package&lt;/span&gt; lsp-bridge
  &lt;span class="hljs-comment"&gt;;; ...&lt;/span&gt;
  &lt;span class="hljs-symbol"&gt;:init&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;require&lt;/span&gt; 'lsp-bridge-jdtls)
  (&lt;span class="hljs-name"&gt;setq&lt;/span&gt; lsp-bridge-enable-auto-import &lt;span class="hljs-literal"&gt;t&lt;/span&gt;)
  &lt;span class="hljs-comment"&gt;;; ... other configurations&lt;/span&gt;
  )
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-working-with-clojure-and-cider" class="outline-2"&gt;
&lt;a href="#working-with-clojure-and-cider"&gt;&lt;h2 id="working-with-clojure-and-cider" class="cr-self-reference "&gt;Working with Clojure and Cider&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-working-with-clojure-and-cider"&gt;
&lt;p&gt;
When writing Clojure, I would like to use &lt;code&gt;cider&lt;/code&gt; for completion and let lsp handling everything else. With &lt;code&gt;lsp-mode&lt;/code&gt; we can just locally set &lt;code&gt;lsp-enable-completion-at-point&lt;/code&gt; to false. With &lt;code&gt;lsp-bridge&lt;/code&gt;, well, we can disable &lt;code&gt;lsp-bridge&lt;/code&gt;'s automatic popup and continue to use corfu.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;use-package&lt;/span&gt; lsp-bridge
  &lt;span class="hljs-comment"&gt;;; ...&lt;/span&gt;
  &lt;span class="hljs-comment"&gt;;; add a new variable&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;defvar&lt;/span&gt; me/force-corfu &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;)

  &lt;span class="hljs-comment"&gt;;; change the previous hook to this&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-corfu-hook ()
    (&lt;span class="hljs-name"&gt;when&lt;/span&gt; (&lt;span class="hljs-name"&gt;and&lt;/span&gt; lsp-bridge-mode
               (&lt;span class="hljs-name"&gt;boundp&lt;/span&gt; 'corfu-mode)
               corfu-mode
               (&lt;span class="hljs-name"&gt;not&lt;/span&gt; me/force-corfu))
      (&lt;span class="hljs-name"&gt;corfu-mode&lt;/span&gt; &lt;span class="hljs-number"&gt;-1&lt;/span&gt;))))

(&lt;span class="hljs-name"&gt;use-package&lt;/span&gt; cider
  &lt;span class="hljs-symbol"&gt;:after&lt;/span&gt; lsp-bridge
  &lt;span class="hljs-symbol"&gt;:config&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;defun&lt;/span&gt; me/lsp-bridge-cider-hook ()
    (&lt;span class="hljs-name"&gt;when&lt;/span&gt; cider-mode
      (&lt;span class="hljs-name"&gt;setq-local&lt;/span&gt; me/force-corfu &lt;span class="hljs-literal"&gt;t&lt;/span&gt;)
      (&lt;span class="hljs-name"&gt;setq-local&lt;/span&gt; lsp-bridge-complete-manually &lt;span class="hljs-literal"&gt;t&lt;/span&gt;)
      (&lt;span class="hljs-name"&gt;corfu-mode&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt;)))
  (&lt;span class="hljs-name"&gt;add-hook&lt;/span&gt; 'cider-mode-hook #'me/lsp-bridge-cider-hook &lt;span class="hljs-number"&gt;80&lt;/span&gt;))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-conclusion" class="outline-2"&gt;
&lt;a href="#conclusion"&gt;&lt;h2 id="conclusion" class="cr-self-reference "&gt;Conclusion&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-conclusion"&gt;
&lt;p&gt;
Overall I would say I'm satisfied with what lsp-bridge provides and amazed at its fluency. I can now load and browse through &lt;a href="https://github.com/oracle/graaljs.git"&gt;graaljs&lt;/a&gt;'s source code with no stutter, no random freeze I need to &lt;code&gt;C-g&lt;/code&gt;, that may or may not work, no nothing. The strategy of off-loading computation to an external process and async everything seems to put very light weight on the Emacs side and work really well.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Experiment with GraalVM, Clojure, and JavaScript</title>
    <link href="https://coruscation.net/blogs/experiment-with-graalvm--clojure--and-javascript.html"/>
    <published>2025-11-18T15:03:31+08:00</published>
    <updated>2025-11-18T15:03:31+08:00</updated>
    <id>https://coruscation.net/blogs/experiment-with-graalvm--clojure--and-javascript.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
A common challenge when making a fullstack website using Clojure/ClojureScript is that, we are often required to use a JavaScript library on the server side when doing Server Side Rendering (SSR). GraalVM/GraalJS provides a solution to run JavaScript code on the JVM. If only we could harness that power…
&lt;/p&gt;

&lt;p&gt;
This blog describes the basic usage of GraalJS and what I managed to achieve with GraalJS and Clojure.
&lt;/p&gt;
&lt;div id="outline-container-basic-setup-and-a-hello-world-program" class="outline-2"&gt;
&lt;a href="#basic-setup-and-a-hello-world-program"&gt;&lt;h2 id="basic-setup-and-a-hello-world-program" class="cr-self-reference "&gt;Basic Setup and a Hello World Program&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-basic-setup-and-a-hello-world-program"&gt;
&lt;p&gt;
We add the following dependencies to our &lt;code&gt;deps.edn&lt;/code&gt;
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;:deps {org.clojure/clojure {:mvn/version &lt;span class="hljs-string"&gt;&amp;quot;1.11.1&amp;quot;&lt;/span&gt;}
       org.graalvm.polyglot/polyglot {:mvn/version &lt;span class="hljs-string"&gt;&amp;quot;25.0.1&amp;quot;&lt;/span&gt;}
       org.graalvm.js/js-language {:mvn/version &lt;span class="hljs-string"&gt;&amp;quot;25.0.1&amp;quot;&lt;/span&gt;}
       org.graalvm.truffle/truffle-runtime {:mvn/version &lt;span class="hljs-string"&gt;&amp;quot;25.0.1&amp;quot;&lt;/span&gt;}}
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
With the dependencies installed, we can write a Hello World program.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;ns&lt;/span&gt;&lt;/span&gt; your-namespace
  (&lt;span class="hljs-symbol"&gt;:import&lt;/span&gt;
   [org.graalvm.polyglot Context]))


(&lt;span class="hljs-keyword"&gt;defonce&lt;/span&gt; ^&lt;span class="hljs-symbol"&gt;:dynamic&lt;/span&gt; &lt;span class="hljs-title"&gt;*context*&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;Context/newBuilder&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; String [&lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;]))
      (&lt;span class="hljs-name"&gt;.build&lt;/span&gt;)))

(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;hello-fn&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context*
                     &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;
                     &lt;span class="hljs-string"&gt;&amp;quot;(function (name) {console.log('hello '+name)})&amp;quot;&lt;/span&gt;))

(&lt;span class="hljs-name"&gt;.executeVoid&lt;/span&gt; hello-fn (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; String [&lt;span class="hljs-string"&gt;&amp;quot;world!&amp;quot;&lt;/span&gt;])) &lt;span class="hljs-comment"&gt;;; output: hello world!&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
All kinds of JavaScript values are represented as &lt;code&gt;org.graalvm.polyglot.Value&lt;/code&gt; objects by GraalJS. In the above example the &lt;code&gt;(.eval ...)&lt;/code&gt; calling returns a executable &lt;code&gt;polyglot.Value&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
We can check if it is an executable by calling the &lt;code&gt;.canExecute()&lt;/code&gt; method.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;.canExecute&lt;/span&gt; hello-fn) &lt;span class="hljs-comment"&gt;;; true&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We can invoke the executable by calling the &lt;code&gt;.execute()&lt;/code&gt; method or the &lt;code&gt;.executeVoid()&lt;/code&gt; method. Their difference is that latter one doesn't have a return value.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;.executeVoid&lt;/span&gt; hello-fn (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object [&lt;span class="hljs-string"&gt;&amp;quot;world&amp;quot;&lt;/span&gt;])) &lt;span class="hljs-comment"&gt;;; output: hello world&lt;/span&gt;

(&lt;span class="hljs-name"&gt;.executeVoid&lt;/span&gt; hello-fn (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object [&lt;span class="hljs-string"&gt;&amp;quot;graaljs&amp;quot;&lt;/span&gt;])) &lt;span class="hljs-comment"&gt;;; output: hello graaljs&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can check if a &lt;code&gt;polyglot.Value&lt;/code&gt; object is of a certain type by using methods starting with &lt;code&gt;.is&lt;/code&gt;, and convert the &lt;code&gt;Value&lt;/code&gt; object to native Java value with methods starting with &lt;code&gt;.as&lt;/code&gt;. For example:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;integer-one&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;)) &lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0x3583d830 &amp;quot;1&amp;quot;]&lt;/span&gt;
(&lt;span class="hljs-name"&gt;.isNumber&lt;/span&gt; integer-one) &lt;span class="hljs-comment"&gt;;; true&lt;/span&gt;
(&lt;span class="hljs-name"&gt;.asLong&lt;/span&gt; integer-one) &lt;span class="hljs-comment"&gt;;; 1&lt;/span&gt;
(&lt;span class="hljs-name"&gt;.isString&lt;/span&gt; integer-one) &lt;span class="hljs-comment"&gt;;; false&lt;/span&gt;
(&lt;span class="hljs-name"&gt;.asString&lt;/span&gt; integer-one) &lt;span class="hljs-comment"&gt;;; ERROR: Unhandled java.lang.ClassCastException&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
To handle JavaScript objects, we have &lt;code&gt;.newInstance()&lt;/code&gt; for instantiating an Object, &lt;code&gt;.invokeMember()&lt;/code&gt; for calling a method, &lt;code&gt;.getMemberKeys()&lt;/code&gt;, &lt;code&gt;.getMember()&lt;/code&gt; and &lt;code&gt;.putMember()&lt;/code&gt; for accessing properties of an object.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;;; We can access top-level JavaScript variables using the (.getBindings *context* &amp;quot;js&amp;quot;).&lt;/span&gt;
&lt;span class="hljs-comment"&gt;;; It returns a polyglot.Value object from which we can retrieve builtin&lt;/span&gt;
&lt;span class="hljs-comment"&gt;;;   JavaScript functions and objects.&lt;/span&gt;
(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;Array&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getMember&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getBindings&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;) &lt;span class="hljs-string"&gt;&amp;quot;Array&amp;quot;&lt;/span&gt;))

&lt;span class="hljs-comment"&gt;;; create an Array&lt;/span&gt;
(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;arr&lt;/span&gt; (&lt;span class="hljs-name"&gt;.newInstance&lt;/span&gt; Array (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object [&lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt;])))

(&lt;span class="hljs-name"&gt;print&lt;/span&gt; arr) &lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0x2dd585ca &amp;quot;(3)[1, 2, 3]&amp;quot;]&lt;/span&gt;

&lt;span class="hljs-comment"&gt;;; pop a value and cast it to Long&lt;/span&gt;
(&lt;span class="hljs-name"&gt;.asLong&lt;/span&gt; (&lt;span class="hljs-name"&gt;.invokeMember&lt;/span&gt; arr &lt;span class="hljs-string"&gt;&amp;quot;pop&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object []))) &lt;span class="hljs-comment"&gt;;; 3&lt;/span&gt;

(&lt;span class="hljs-name"&gt;print&lt;/span&gt; arr) &lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0x27e1e162 (2)[1, 2]]&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-working-with-javascript-libraries" class="outline-2"&gt;
&lt;a href="#working-with-javascript-libraries"&gt;&lt;h2 id="working-with-javascript-libraries" class="cr-self-reference "&gt;Working With JavaScript Libraries&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-working-with-javascript-libraries"&gt;
&lt;p&gt;
GraalJS has an option to provide a &lt;code&gt;require&lt;/code&gt; function, with which we can import CommonJS JavaScript modules. The option isn't enabled by default. To enable it, we need to change the definition of &lt;code&gt;*context*&lt;/code&gt; to the following:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defonce&lt;/span&gt; ^&lt;span class="hljs-symbol"&gt;:dynamic&lt;/span&gt; &lt;span class="hljs-title"&gt;*context*&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;Context/newBuilder&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; String ))
      (&lt;span class="hljs-name"&gt;.allowExperimentalOptions&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
      (&lt;span class="hljs-name"&gt;.options&lt;/span&gt; (&lt;span class="hljs-name"&gt;HashMap.&lt;/span&gt;
                 {&lt;span class="hljs-string"&gt;&amp;quot;js.commonjs-require&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
                  &lt;span class="hljs-string"&gt;&amp;quot;js.commonjs-require-cwd&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;System/getProperty&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;user.dir&amp;quot;&lt;/span&gt;)
                                                 &lt;span class="hljs-string"&gt;&amp;quot;/node_modules&amp;quot;&lt;/span&gt;)}))
      (&lt;span class="hljs-name"&gt;.allowIO&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;)
      (&lt;span class="hljs-name"&gt;.build&lt;/span&gt;)))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here we use as &lt;code&gt;commonjs-require-cwd&lt;/code&gt;'s value. It tells GraalJS to find JavaScript modules under the &lt;code&gt;node_modules&lt;/code&gt; folder in the project root.
&lt;/p&gt;

&lt;p&gt;
We can then install JavaScript libraries using npm under the project root. Here I use &amp;quot;luxon&amp;quot; as an example.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;npm init
npm install luxon
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We can then import the module by using &lt;code&gt;require&lt;/code&gt; function.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;luxon&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;require('luxon')&amp;quot;&lt;/span&gt;))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We can access the resulting module with the &lt;code&gt;.getMember()&lt;/code&gt; method.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;DateTime&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getMember&lt;/span&gt; luxon &lt;span class="hljs-string"&gt;&amp;quot;DateTime&amp;quot;&lt;/span&gt;))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now we have the &lt;code&gt;DateTime&lt;/code&gt; class from the &lt;code&gt;luxon&lt;/code&gt; library, let's try to turn it into something useful:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;now&lt;/span&gt; []
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; DateTime
      &lt;span class="hljs-comment"&gt;;; DateTime.now() returns a DateTime object&lt;/span&gt;
      (&lt;span class="hljs-name"&gt;.invokeMember&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;now&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object []))
      &lt;span class="hljs-comment"&gt;;; We call the .toString method to convert the object&lt;/span&gt;
      &lt;span class="hljs-comment"&gt;;;    into a JavaScript String&lt;/span&gt;
          (&lt;span class="hljs-name"&gt;.invokeMember&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;toString&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object []))
      &lt;span class="hljs-comment"&gt;;; then we convert the result into a Java String&lt;/span&gt;
          (&lt;span class="hljs-name"&gt;.asString&lt;/span&gt;)))

&lt;span class="hljs-comment"&gt;;; Let's try to call the function&lt;/span&gt;

(&lt;span class="hljs-name"&gt;now&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; &amp;quot;2025-11-15T16:56:49.798+08:00&amp;quot;&lt;/span&gt;
(&lt;span class="hljs-name"&gt;now&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; &amp;quot;2025-11-15T16:57:01.961+08:00&amp;quot;&lt;/span&gt;

&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We wrapped the details of interop between Clojure and JavaScript in a Clojure function &lt;code&gt;now&lt;/code&gt;. Now if we want to get the current time string from the &lt;code&gt;luxon&lt;/code&gt; library, we can just call the &lt;code&gt;now&lt;/code&gt; function. The interop is still something quite cumbersome to do, however. In this blog I will show you how to turn it into something way more concise using the macros and other facilities provided by Clojure. Here is a glimpse of it:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; lux/DateTime now toString) &lt;span class="hljs-comment"&gt;;; &amp;quot;2025-11-15T17:04:38.574+08:00&amp;quot;&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-ease-things-with-helper-functions,-macros-and-more" class="outline-2"&gt;
&lt;a href="#ease-things-with-helper-functions,-macros-and-more"&gt;&lt;h2 id="ease-things-with-helper-functions,-macros-and-more" class="cr-self-reference "&gt;Ease Things With Helper Functions, Macros and More&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-ease-things-with-helper-functions,-macros-and-more"&gt;
&lt;p&gt;
You must have noticed the definition of the &lt;code&gt;now&lt;/code&gt; function in the previous example is quite clumsy. In ClojureScript we have the following things that can facilitate the interop between ClojureScript and JavaScript
&lt;/p&gt;
&lt;ul class="org-ul"&gt;
&lt;li&gt;We can require a js module just like a clojure namespace&lt;/li&gt;
&lt;li&gt;A ClojureScript function is just a JavaScript function, we can call JavaScript functions from the ClojureScript side, or we can pass ClojureScript functions to the JavaScript side.&lt;/li&gt;
&lt;li&gt;We have dot macros ( &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;..&lt;/code&gt; and &lt;code&gt;.-&lt;/code&gt; ) and &lt;code&gt;set!&lt;/code&gt; to easily access properites or methods of JavaScript objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
To build something on the same level is probably very hard, however, to build a demonstration of something very similar is indeed very achievable.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id="outline-container-mapping-between-clojure-and-polyglot-values" class="outline-3"&gt;
&lt;a href="#mapping-between-clojure-and-polyglot-values"&gt;&lt;h3 id="mapping-between-clojure-and-polyglot-values" class="cr-self-reference "&gt;Mapping between Clojure and Polyglot Values&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-mapping-between-clojure-and-polyglot-values"&gt;
&lt;p&gt;
We probably don't want to manually convert the result each time we get a value from the JavaScript side as we did in the previous examples. So we would like to put the actual JavaScript functions invoking logics into a wrapper and let the wrapper automatically convert the parameters and the return value for us. To make something like this, and since GraalJS represents each JavaScript value as a Polyglot Value, we first need to establish a mapping between Clojure types and Polyglot Types.
&lt;/p&gt;
&lt;/div&gt;
&lt;div id="outline-container-primitive-types" class="outline-4"&gt;
&lt;a href="#primitive-types"&gt;&lt;h4 id="primitive-types" class="cr-self-reference "&gt;Primitive Types&lt;/h4&gt;&lt;/a&gt;
&lt;div class="outline-text-4" id="text-primitive-types"&gt;
&lt;p&gt;
Each time we call the &lt;code&gt;.execute()&lt;/code&gt; or &lt;code&gt;.invokeMember()&lt;/code&gt; method of the &lt;code&gt;polyglot.Value&lt;/code&gt; class, GraalJS will convert the arguments using &lt;code&gt;.asValue()&lt;/code&gt; method of &lt;code&gt;Context&lt;/code&gt; class. However, we are going to wrap Clojure functions as Polyglot functions in the next section. As of now, we write a Clojure -&amp;gt; Polyglot mapping function only calling the &lt;code&gt;.asValue()&lt;/code&gt; method.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;polyglotalize-clojure&lt;/span&gt; [value]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;;; https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#asValue(java.lang.Object)&lt;/span&gt;
    &lt;span class="hljs-symbol"&gt;:else&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;.asValue&lt;/span&gt; *context* value)))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
As for the mapping from &lt;code&gt;polyglot.Value&lt;/code&gt; to Clojure values, we use the various checking and converting methods described before.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;clojurify-value&lt;/span&gt; [^org.graalvm.polyglot.Value value]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.isHostObject&lt;/span&gt; value)
        (&lt;span class="hljs-name"&gt;.asHostObject&lt;/span&gt; value)

        (&lt;span class="hljs-name"&gt;.isBoolean&lt;/span&gt; value)
        (&lt;span class="hljs-name"&gt;.asBoolean&lt;/span&gt; value)

        (&lt;span class="hljs-name"&gt;.isNull&lt;/span&gt; value)
        &lt;span class="hljs-literal"&gt;nil&lt;/span&gt;

        (&lt;span class="hljs-name"&gt;.isString&lt;/span&gt; value)
        (&lt;span class="hljs-name"&gt;.asString&lt;/span&gt; value)

        (&lt;span class="hljs-name"&gt;.isNumber&lt;/span&gt; value)
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;.fitsInLong&lt;/span&gt; value)
              (&lt;span class="hljs-name"&gt;.asLong&lt;/span&gt; value)

              (&lt;span class="hljs-name"&gt;.fitsInDouble&lt;/span&gt; value)
              (&lt;span class="hljs-name"&gt;.asDouble&lt;/span&gt; value))

        &lt;span class="hljs-symbol"&gt;:else&lt;/span&gt;
        value))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-functions" class="outline-4"&gt;
&lt;a href="#functions"&gt;&lt;h4 id="functions" class="cr-self-reference "&gt;Functions&lt;/h4&gt;&lt;/a&gt;
&lt;div class="outline-text-4" id="text-functions"&gt;
&lt;p&gt;
GraalVM provides various &lt;code&gt;Proxy&lt;/code&gt; objects that we can use to make Clojure objects accessible in the JavaScript environment. To wrap a function, we need to use &lt;code&gt;ProxyExecutable&lt;/code&gt;.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;wrap-clojure-fn&lt;/span&gt; [f]
  (&lt;span class="hljs-name"&gt;.asValue&lt;/span&gt; *context*
            (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;with-meta&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;reify&lt;/span&gt;&lt;/span&gt; org.graalvm.polyglot.proxy.ProxyExecutable
                         #_{&lt;span class="hljs-symbol"&gt;:clj-kondo/ignore&lt;/span&gt; [&lt;span class="hljs-symbol"&gt;:unused-binding&lt;/span&gt;]}
                         &lt;span class="hljs-comment"&gt;;; we ignore `this` for now&lt;/span&gt;
                         (&lt;span class="hljs-name"&gt;execute&lt;/span&gt; [this ^&lt;span class="hljs-string"&gt;&amp;quot;[Lorg.graalvm.polyglot.Value;&amp;quot;&lt;/span&gt; values]
                           (&lt;span class="hljs-name"&gt;polyglotalize-clojure&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;apply&lt;/span&gt;&lt;/span&gt; f (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; clojurify-value values)))))
              {&lt;span class="hljs-symbol"&gt;::raw-fn&lt;/span&gt; f})))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The function takes a Clojure function as an argument, returns a Polyglot executable that we can pass to the JavaScript environment.
&lt;/p&gt;

&lt;p&gt;
In the function body, we use &lt;code&gt;reify&lt;/code&gt; to instantiate an object implementing the &lt;code&gt;ProxyExecutable&lt;/code&gt; interface. We implement the &lt;code&gt;.execute()&lt;/code&gt; method by applying the clojurified arguments to the original Clojure function, and convert the return value back to a Polyglot value using the two functions we wrote in the &lt;a href="#primitive-types"&gt;previous section&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
In case we want to turn the proxy object back into a clojure function (like when a JavaScript function returns the proxy object as is), we save the original Clojure function into the &lt;a href="https://clojure.org/reference/metadata"&gt;metadata&lt;/a&gt; of the proxy object using &lt;code&gt;with-meta&lt;/code&gt;. In the final step, we turn it into a Polyglot Value using &lt;code&gt;.asValue&lt;/code&gt; method from &lt;code&gt;Context&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Wrapping functions from JavaScript follows a similar logic.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;wrap-polyglot-executable&lt;/span&gt; [^org.graalvm.polyglot.Value obj]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;with-meta&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [&amp;amp; args]
               (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;.execute&lt;/span&gt; obj (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; polyglotalize-clojure args)))))
    {&lt;span class="hljs-symbol"&gt;::raw-value&lt;/span&gt; obj}))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here, we also save a reference to the original JavaScript function in the metadata. However, it serves a much more important role: In JavaScript, a function is like any object, it can have all kinds of properties. Therefore, after wrapping a JavaScript function as a Clojure function, we may still need to access its other properties. To do this, we save the original function in the metadata and retrieve it if necessary.
&lt;/p&gt;

&lt;p&gt;
With these two functions defined, we can then augmented our two mapping functions.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;polyglotalize-clojure&lt;/span&gt; [value]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;::raw-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;meta&lt;/span&gt;&lt;/span&gt; value))
        (&lt;span class="hljs-symbol"&gt;::raw-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;meta&lt;/span&gt;&lt;/span&gt; value))

        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn?&lt;/span&gt;&lt;/span&gt; value)
        (&lt;span class="hljs-name"&gt;wrap-clojure-fn&lt;/span&gt; value)

        &lt;span class="hljs-symbol"&gt;:else&lt;/span&gt;
        &lt;span class="hljs-comment"&gt;;; https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#asValue(java.lang.Object)&lt;/span&gt;
        (&lt;span class="hljs-name"&gt;.asValue&lt;/span&gt; *context* value)))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;clojurify-value&lt;/span&gt; [^org.graalvm.polyglot.Value value]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt;

    (&lt;span class="hljs-name"&gt;.isProxyObject&lt;/span&gt; value)
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [prox-obj (&lt;span class="hljs-name"&gt;.asProxyObject&lt;/span&gt; value)]
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;::raw-fn&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;meta&lt;/span&gt;&lt;/span&gt; prox-obj))
        (&lt;span class="hljs-symbol"&gt;::raw-fn&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;meta&lt;/span&gt;&lt;/span&gt; prox-obj))
        prox-obj))

    &lt;span class="hljs-comment"&gt;;;&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;;; ... omitted&lt;/span&gt;
    &lt;span class="hljs-comment"&gt;;;&lt;/span&gt;

    (&lt;span class="hljs-name"&gt;.canExecute&lt;/span&gt; value) 
    (&lt;span class="hljs-name"&gt;wrap-polyglot-executable&lt;/span&gt; value)

    &lt;span class="hljs-symbol"&gt;:else&lt;/span&gt;
    value))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
With these two facilities created, we already achieve something very interesting.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;hello&lt;/span&gt; (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;(function (name){console.log(`hello ${name}`)})&amp;quot;&lt;/span&gt;)))

(&lt;span class="hljs-name"&gt;hello&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;world&amp;quot;&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; output: hello world&lt;/span&gt;
(&lt;span class="hljs-name"&gt;hello&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;graaljs&amp;quot;&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; output: hello graaljs&lt;/span&gt;

(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;to-array&lt;/span&gt; (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt;
               (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;(function (...args){return Array.from(args);})&amp;quot;&lt;/span&gt;)))

(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;to-array&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt; &lt;span class="hljs-number"&gt;4&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0x26e3da6b &amp;quot;(4)[1, 2, 3, 4]&amp;quot;]&lt;/span&gt;

(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;join&lt;/span&gt; (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt;
           (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;(function (s, ...args){return args.join(s);})&amp;quot;&lt;/span&gt;)))

(&lt;span class="hljs-name"&gt;join&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;,&amp;quot;&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt; &lt;span class="hljs-number"&gt;4&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; &amp;quot;1,2,3,4&amp;quot;&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
As you have seen, we can now call a JavaScript function just like a Clojure function. Return values of primitive types will also be automatically converted back to Clojure values.
&lt;/p&gt;

&lt;p&gt;
We can also pass Clojure functions to the JavaScript side:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;sum-term&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt;
   (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;let sum = (term, a, b) =&amp;gt; (a&amp;gt;b)? 0 : term(a) + sum(term, a+1,b); sum&amp;quot;&lt;/span&gt;)))

&lt;span class="hljs-comment"&gt;;; (sum-integers a b) calculate the sum of integers from `a` to `b` (inclusive)&lt;/span&gt;
(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;sum-integers&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;partial&lt;/span&gt;&lt;/span&gt; sum-term identity))
(&lt;span class="hljs-name"&gt;sum-integers&lt;/span&gt; &lt;span class="hljs-number"&gt;0&lt;/span&gt; &lt;span class="hljs-number"&gt;10&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; 55&lt;/span&gt;

&lt;span class="hljs-comment"&gt;;; (sum-cubes a b) calculates the sum of cubes of integers from `a` to `b` (inclusive)&lt;/span&gt;
(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;sum-cubes&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;partial&lt;/span&gt;&lt;/span&gt; sum-term (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [x] (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;*&lt;/span&gt;&lt;/span&gt; x x x))))
(&lt;span class="hljs-name"&gt;sum-cubes&lt;/span&gt; &lt;span class="hljs-number"&gt;0&lt;/span&gt; &lt;span class="hljs-number"&gt;10&lt;/span&gt;) &lt;span class="hljs-comment"&gt;;; 3025&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-mapping_objects" class="outline-4"&gt;
&lt;a href="#mapping_objects"&gt;&lt;h4 id="mapping_objects" class="cr-self-reference "&gt;Objects&lt;/h4&gt;&lt;/a&gt;
&lt;div class="outline-text-4" id="text-mapping_objects"&gt;
&lt;p&gt;
Rougly similar to ClojureScript, We don't do mapping for objects other than those of primitives types and functions. However, in the &lt;code&gt;clojurify-value&lt;/code&gt; function, we wrap all JavaScript functions into Clojure functions and save the reference in the metadata, and as I have explained there, a JavaScript function may have other properties we want to access. Thus, in each place where a Clojure function wrapping a JavaScript function can be taken as arguments, we cannot use methods from &lt;code&gt;polyglot.Value&lt;/code&gt;. Instead, we define helper functions that will wrap the arguments if necessary and then call the target method.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;polyglot-value&lt;/span&gt; [obj]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;::raw-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;meta&lt;/span&gt;&lt;/span&gt; obj))
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;and&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;instance?&lt;/span&gt;&lt;/span&gt; org.graalvm.polyglot.Value obj)
           obj)))

(&lt;span class="hljs-keyword"&gt;defn-&lt;/span&gt; &lt;span class="hljs-title"&gt;to-camel-style&lt;/span&gt; [s]
  (&lt;span class="hljs-name"&gt;string/replace&lt;/span&gt; s &lt;span class="hljs-regex"&gt;#&amp;quot;-([a-z])&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [g]
                                  (&lt;span class="hljs-name"&gt;.toUpperCase&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;second&lt;/span&gt;&lt;/span&gt; g)))))

(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;define-unwrap-executable-alias&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/lint-as&lt;/span&gt; 'clojure.core/declare}
  [name &amp;amp; args]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [docstring? (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;string?&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; args))
        docstring (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; docstring? (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; args))
        args (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; docstring? (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;second&lt;/span&gt;&lt;/span&gt; args) (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; args))
        obj 'obj
        [arglist [_ vararg]] (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;split-with&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [x] (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;not&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; x '&amp;amp;))) args)] 
    `(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; ~&lt;span class="hljs-title"&gt;name&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:doc&lt;/span&gt; ~docstring} [~obj ~@arglist ~@(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; vararg `[&amp;amp; ~vararg] [])]
       (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [~obj (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;polyglot-value&lt;/span&gt; ~obj)
                      ~obj)]
         (~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;.&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;to-camel-style&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; name))))
          ~obj 
          ~@arglist
          ~@(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; vararg
              [`(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object ~vararg)]
              []))))))

(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; get-meta-object)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; is-meta-object)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; get-meta-qualified-name)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; has-meta-parents)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; has-array-elements)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; get-meta-parents)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; get-member [^String identifier])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; put-member [^String identifier ^Object value])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; get-member-keys)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; new-instance [&amp;amp; args])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; can-invoke-member [^String s])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; invoke-member [^String method &amp;amp; args])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; can-instantiate)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; canExecute)
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; execute [&amp;amp; args])
(&lt;span class="hljs-name"&gt;define-unwrap-executable-alias&lt;/span&gt; executeVoid [&amp;amp; args])
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We wrote a macro for this purpose. The macro takes a function name and a parameter list as arguments and defines a function with the name and parameters.
The function defined by the macro retrieves the reference from the metadata if necessary, then calls a method by the name converted from the function name and with arguments from the parameter list.
&lt;/p&gt;

&lt;p&gt;
One nice bonus is that the generated functions assembles all the variadic arguments into an &lt;code&gt;Object[]&lt;/code&gt;, saving us from calling &lt;code&gt;(into-arry Object)&lt;/code&gt; manually if we need to call a method with variadic arguments.
&lt;/p&gt;

&lt;p&gt;
Previously we need to do this:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;.newInstance&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Array&amp;quot;&lt;/span&gt;) (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into-array&lt;/span&gt;&lt;/span&gt; Object [&lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt;]))
&lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0x65b337ef &amp;quot;(3)[1, 2, 3]&amp;quot;]&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now we just need to do this:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;new-instance&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Array&amp;quot;&lt;/span&gt;) &lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt;)
&lt;span class="hljs-comment"&gt;;; #object[org.graalvm.polyglot.Value 0xfdabe76 &amp;quot;(3)[1, 2, 3]&amp;quot;]&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-dot-macros-and-~set!~" class="outline-3"&gt;
&lt;a href="#dot-macros-and-~set!~"&gt;&lt;h3 id="dot-macros-and-~set!~" class="cr-self-reference "&gt;Dot Macros and &lt;code&gt;set!&lt;/code&gt;&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-dot-macros-and-~set!~"&gt;
&lt;p&gt;
In ClojureScript we have dots special forms or macros like &lt;code&gt;.&lt;/code&gt;,  &lt;code&gt;.-&lt;/code&gt; and &lt;code&gt;..&lt;/code&gt; for accessing properties or calling methods of JavaScript objects.
&lt;/p&gt;

&lt;p&gt;
We can relatively easily implement them using macros.
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
There are also &lt;code&gt;(.method obj)&lt;/code&gt; &lt;code&gt;(.-property obj)&lt;/code&gt; as shorthands for &lt;code&gt;(. obj method)&lt;/code&gt; and &lt;code&gt;(.- obj property)&lt;/code&gt; in ClojureScript. However, implementing them would be really difficult if not impossible.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;js.&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/ignore&lt;/span&gt; [&lt;span class="hljs-symbol"&gt;:unresolved-symbol&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:type-mismatch&lt;/span&gt;]}
  [obj method &amp;amp; args]
  `(&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt;
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;apply&lt;/span&gt;&lt;/span&gt; invoke-member ~obj ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; method)
           &lt;span class="hljs-comment"&gt;;; evaluate args before passing them to polyglotalize-clojure&lt;/span&gt;
           (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; polyglotalize-clojure (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;list&lt;/span&gt;&lt;/span&gt; ~@args)))))


(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;js.-&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/ignore&lt;/span&gt; [&lt;span class="hljs-symbol"&gt;:unresolved-symbol&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:type-mismatch&lt;/span&gt;]}
  [obj field]
  `(&lt;span class="hljs-name"&gt;#'clojurify-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;get-member&lt;/span&gt; ~obj ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; field))))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The &lt;code&gt;invoke-member&lt;/code&gt; and &lt;code&gt;get-member&lt;/code&gt; helper functions are defined in the &lt;a href="#mapping_objects"&gt;previous section&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
With these two defined, we can write the more complicated macro &lt;code&gt;js..&lt;/code&gt; based on them.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;js..&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/ignore&lt;/span&gt; [&lt;span class="hljs-symbol"&gt;:unresolved-symbol&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:type-mismatch&lt;/span&gt;]}
  [obj &amp;amp; args]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;empty?&lt;/span&gt;&lt;/span&gt; args)
    obj
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [curr# (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; args)
          rest# (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; args)]
      `(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;cond&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;seq?&lt;/span&gt;&lt;/span&gt; curr#)
                    `(&lt;span class="hljs-name"&gt;js.&lt;/span&gt; ~obj ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; curr#) ~@(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; curr#))

                    (&lt;span class="hljs-name"&gt;.startsWith&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; curr#)
                                 &lt;span class="hljs-string"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;)
                    `(&lt;span class="hljs-name"&gt;js.-&lt;/span&gt; ~obj ~(&lt;span class="hljs-name"&gt;subs&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; curr#) &lt;span class="hljs-number"&gt;1&lt;/span&gt;))

                    &lt;span class="hljs-symbol"&gt;:else&lt;/span&gt;
                    `(&lt;span class="hljs-name"&gt;js.&lt;/span&gt; ~obj ~curr#))
         ~@rest#))))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Finally, we will implement the &lt;code&gt;set!&lt;/code&gt; macro.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;js-set!&lt;/span&gt; [dot-form value]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assert&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;seq?&lt;/span&gt;&lt;/span&gt; dot-form) &lt;span class="hljs-string"&gt;&amp;quot;First argument must be in the form of `(js.. obj -field)` or (js.- obj field)&amp;quot;&lt;/span&gt;)
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [[op &amp;amp; args] dot-form]
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assert&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; op 'js..)
                (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; op 'js.-))
            &lt;span class="hljs-string"&gt;&amp;quot;First argument to js-set! must start with either `js..` or `js.-`&amp;quot;&lt;/span&gt;)
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [remove-hyphen (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; op 'js..)
          lst (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;last&lt;/span&gt;&lt;/span&gt; args)
          last-removed (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;drop-last&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;into&lt;/span&gt;&lt;/span&gt; [op] args))]
      `(&lt;span class="hljs-name"&gt;put-member&lt;/span&gt; ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;count&lt;/span&gt;&lt;/span&gt; last-removed) &lt;span class="hljs-number"&gt;2&lt;/span&gt;)
                      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;second&lt;/span&gt;&lt;/span&gt; last-removed)
                      last-removed)
                   ~(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; remove-hyphen
                      (&lt;span class="hljs-name"&gt;subs&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; lst) &lt;span class="hljs-number"&gt;1&lt;/span&gt;)
                      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; lst))
                   ~value))))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Let's go back to the &lt;code&gt;luxon&lt;/code&gt; example mentioned in the beginning of this blog and check what we can do with these newly defined tools.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; &lt;span class="hljs-title"&gt;luxon&lt;/span&gt; (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;require('luxon')&amp;quot;&lt;/span&gt;))

(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; luxon -DateTime now toString) &lt;span class="hljs-comment"&gt;;; &amp;quot;2025-11-14T16:48:11.324+08:00&amp;quot;&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Compare it to the snippet I showed at the end of the first section:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; lux/DateTime now toString)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
The only thing lacking is a &lt;code&gt;require&lt;/code&gt; mechanism, which is what we are going to implement in the next section.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-~require~-command" class="outline-3"&gt;
&lt;a href="#~require~-command"&gt;&lt;h3 id="~require~-command" class="cr-self-reference "&gt;&lt;code&gt;require&lt;/code&gt; command&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-~require~-command"&gt;
&lt;p&gt;
On the JavaScript side, the &lt;code&gt;require()&lt;/code&gt; function returns an object from which we can access its exported variables or functions.
&lt;/p&gt;

&lt;p&gt;
On the Clojure side, we can dynamically create a namespace with the &lt;code&gt;create-ns&lt;/code&gt; function. After that we can make all the variables from the module object accessible in the newly created namespace with the &lt;code&gt;intern&lt;/code&gt; function.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;defn-&lt;/span&gt; &lt;span class="hljs-title"&gt;require-module&lt;/span&gt; [name]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; *context*
      (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt;
             (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;require('&amp;quot;&lt;/span&gt; name &lt;span class="hljs-string"&gt;&amp;quot;')&amp;quot;&lt;/span&gt;))))

(&lt;span class="hljs-keyword"&gt;defn-&lt;/span&gt; &lt;span class="hljs-title"&gt;parse-flags&lt;/span&gt; [args]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;loop&lt;/span&gt;&lt;/span&gt; [args (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;lazy-seq&lt;/span&gt;&lt;/span&gt; args)
         result (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;hash-map&lt;/span&gt;&lt;/span&gt;)]
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;empty?&lt;/span&gt;&lt;/span&gt; args)
      result
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [curr (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; args)
            rst (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; args)]
        (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;keyword?&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; rst))
                (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;empty?&lt;/span&gt;&lt;/span&gt; rst))
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;recur&lt;/span&gt;&lt;/span&gt; rst (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assoc&lt;/span&gt;&lt;/span&gt; result curr &lt;span class="hljs-literal"&gt;true&lt;/span&gt;))
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;recur&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;rest&lt;/span&gt;&lt;/span&gt; rst)
                 (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;assoc&lt;/span&gt;&lt;/span&gt; result curr (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; rst))))))))

(&lt;span class="hljs-keyword"&gt;defn-&lt;/span&gt; &lt;span class="hljs-title"&gt;normalize-module-name&lt;/span&gt; [name]
  (&lt;span class="hljs-name"&gt;s/replace&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; name) &lt;span class="hljs-regex"&gt;#&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;))

(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;require-js&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/lint-as&lt;/span&gt; 'clojure.core/require}
  [[module-name &amp;amp; flags] &amp;amp; coll]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [flag-map (&lt;span class="hljs-name"&gt;parse-flags&lt;/span&gt; flags)
        module (&lt;span class="hljs-name"&gt;require-module&lt;/span&gt; module-name)
        alias-name (&lt;span class="hljs-symbol"&gt;:as&lt;/span&gt; flag-map)
        qualified-module-name (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;js4clj.modules.&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;normalize-module-name&lt;/span&gt; module-name)))]
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;create-ns&lt;/span&gt;&lt;/span&gt; qualified-module-name)
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [k (&lt;span class="hljs-name"&gt;.getMemberKeys&lt;/span&gt; module)]
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;intern&lt;/span&gt;&lt;/span&gt; qualified-module-name
              (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; k)
              (&lt;span class="hljs-name"&gt;clojurify-value&lt;/span&gt; (&lt;span class="hljs-name"&gt;.getMember&lt;/span&gt; module k))))
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; alias-name
      (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;alias&lt;/span&gt;&lt;/span&gt; alias-name qualified-module-name)))
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;seq&lt;/span&gt;&lt;/span&gt; coll)
    (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;apply&lt;/span&gt;&lt;/span&gt; require-js coll)))
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
&lt;code&gt;(require-js '[luxon :as lux])&lt;/code&gt; is now all we need to require a JavaScript module.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;require-js&lt;/span&gt; '[luxon &lt;span class="hljs-symbol"&gt;:as&lt;/span&gt; lux])

(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; lux/DateTime now toString) &lt;span class="hljs-comment"&gt;;; &amp;quot;2025-11-14T17:08:40.045+08:00&amp;quot;&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Let's try some more examples:
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-name"&gt;js..&lt;/span&gt; lux/DateTime (&lt;span class="hljs-name"&gt;fromISO&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;2017-05-15T08:30:00&amp;quot;&lt;/span&gt;) -year) &lt;span class="hljs-comment"&gt;;; 2017&lt;/span&gt;

&lt;span class="hljs-comment"&gt;;; or write it as&lt;/span&gt;
(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;-&amp;gt;&lt;/span&gt;&lt;/span&gt; lux/DateTime
    (&lt;span class="hljs-name"&gt;js.&lt;/span&gt; fromISO &lt;span class="hljs-string"&gt;&amp;quot;2017-05-15T08:30:00&amp;quot;&lt;/span&gt;)
    (&lt;span class="hljs-name"&gt;js.-&lt;/span&gt; year)) &lt;span class="hljs-comment"&gt;;; 2017&lt;/span&gt;

(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [now (&lt;span class="hljs-name"&gt;js.&lt;/span&gt; lux/DateTime now)
      later (&lt;span class="hljs-name"&gt;js.&lt;/span&gt; lux/DateTime local &lt;span class="hljs-number"&gt;2026&lt;/span&gt; &lt;span class="hljs-number"&gt;10&lt;/span&gt; &lt;span class="hljs-number"&gt;12&lt;/span&gt;)
      i (&lt;span class="hljs-name"&gt;js.&lt;/span&gt; lux/Interval fromDateTimes now later)]
  (&lt;span class="hljs-name"&gt;js.&lt;/span&gt; i length &lt;span class="hljs-string"&gt;&amp;quot;years&amp;quot;&lt;/span&gt;)) &lt;span class="hljs-comment"&gt;;; 0.904136850298072&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-bonus:-special-~js~-namespace" class="outline-3"&gt;
&lt;a href="#bonus:-special-~js~-namespace"&gt;&lt;h3 id="bonus:-special-~js~-namespace" class="cr-self-reference "&gt;Bonus: Special &lt;code&gt;js&lt;/code&gt; namespace&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-bonus:-special-~js~-namespace"&gt;
&lt;p&gt;
ClojureScript provides us a &lt;a href="https://cljs.github.io/api/syntax/js-namespace"&gt;special &lt;code&gt;js&lt;/code&gt; namespace&lt;/a&gt;, from where we can use various JavaScript global objects. We can also implement something like that.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;(&lt;span class="hljs-keyword"&gt;def&lt;/span&gt; ^&lt;span class="hljs-symbol"&gt;:dynamic&lt;/span&gt; &lt;span class="hljs-title"&gt;*no-clojurify*&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt;)

(&lt;span class="hljs-keyword"&gt;defn-&lt;/span&gt; &lt;span class="hljs-title"&gt;define-builtin&lt;/span&gt; [ns primitive &amp;amp; [alias]]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;intern&lt;/span&gt;&lt;/span&gt; ns (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; alias (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; alias) (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;symbol&lt;/span&gt;&lt;/span&gt; primitive))
          ((&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;if&lt;/span&gt;&lt;/span&gt; *no-clojurify* identity clojurify-value)
           (&lt;span class="hljs-name"&gt;.eval&lt;/span&gt; *context* &lt;span class="hljs-string"&gt;&amp;quot;js&amp;quot;&lt;/span&gt; primitive))))

(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;define-builtins&lt;/span&gt;
  {&lt;span class="hljs-symbol"&gt;:clj-kondo/lint-as&lt;/span&gt; 'clojure.core/declare}
  [ns &amp;amp; primitives]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;create-ns&lt;/span&gt;&lt;/span&gt; ns)
  `(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;doseq&lt;/span&gt;&lt;/span&gt; [primitive# '~primitives]
     (&lt;span class="hljs-name"&gt;define-builtin&lt;/span&gt; '~ns (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;str&lt;/span&gt;&lt;/span&gt; primitive#))))

&lt;span class="hljs-comment"&gt;;; In cljs there is also a js/undefined&lt;/span&gt;
&lt;span class="hljs-comment"&gt;;;	in which (= nil js/undefined) but we can't mimic it.&lt;/span&gt;
&lt;span class="hljs-comment"&gt;;; Still, we need a js/undefined in case we need to do some&lt;/span&gt;
&lt;span class="hljs-comment"&gt;;; 	very specific interop.&lt;/span&gt;
(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;declare&lt;/span&gt;&lt;/span&gt; undefined)
(&lt;span class="hljs-name"&gt;with-bindings&lt;/span&gt; {#'*no-clojurify* &lt;span class="hljs-literal"&gt;true&lt;/span&gt;}
  (&lt;span class="hljs-name"&gt;define-builtin&lt;/span&gt; 'js &lt;span class="hljs-string"&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;undefined&amp;quot;&lt;/span&gt;))

#_{&lt;span class="hljs-symbol"&gt;:clojure-lsp/ignore&lt;/span&gt; [&lt;span class="hljs-symbol"&gt;:clojure-lsp/unused-public-var&lt;/span&gt;]}
(&lt;span class="hljs-name"&gt;define-builtins&lt;/span&gt; js
  globalThis
  Infinity
  NaN
  Object
  Function
  Boolean
  Symbol
  Error
  Number
  BigInt
  Math
  Date
  String
  Array
  Map
  Set
  WeakMap
  WeakSet
  JSON
  ArrayBuffer
  Promise
  console)
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
We took a special handling of &lt;code&gt;js/undefined&lt;/code&gt; (note when we clojurify JavaScript values, we turn both &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; into &lt;code&gt;nil&lt;/code&gt;), since a direct equivalent of &lt;code&gt;undefined&lt;/code&gt; in JavaScript may be needed for some interops. However, &lt;code&gt;js/undefined&lt;/code&gt; In ClojureScript has some special properties we can't replicate, most notably, &lt;code&gt;(nil? js/undefined)&lt;/code&gt; and &lt;code&gt;(= js/undefined nil)&lt;/code&gt; results in &lt;code&gt;true&lt;/code&gt; in ClojureScript.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-limitations" class="outline-2"&gt;
&lt;a href="#limitations"&gt;&lt;h2 id="limitations" class="cr-self-reference "&gt;Limitations&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-limitations"&gt;
&lt;/div&gt;
&lt;div id="outline-container-functionalities-specific-to-an-environment" class="outline-3"&gt;
&lt;a href="#functionalities-specific-to-an-environment"&gt;&lt;h3 id="functionalities-specific-to-an-environment" class="cr-self-reference "&gt;Functionalities specific to an environment&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-functionalities-specific-to-an-environment"&gt;
&lt;p&gt;
JavaScript packages are often written under the assumption that, the code will either run on a Browser or a node.js environment. Unfortunately, GraalJS only implements the ECMAScript specification, which means we have neither functions specific to node.js nor functions specific to a browser.
&lt;/p&gt;

&lt;p&gt;
For example, we don't have &lt;code&gt;WebWorker&lt;/code&gt; api from the browser, nor &lt;code&gt;process&lt;/code&gt;, &lt;code&gt;fs&lt;/code&gt; api from node.js.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-multithreading-and-the-~js~-namespace" class="outline-3"&gt;
&lt;a href="#multithreading-and-the-~js~-namespace"&gt;&lt;h3 id="multithreading-and-the-~js~-namespace" class="cr-self-reference "&gt;Multithreading and the &lt;code&gt;js&lt;/code&gt; namespace&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-multithreading-and-the-~js~-namespace"&gt;
&lt;p&gt;
When writing programs in Java, we usually use blocking operations and multithreading. However, &lt;code&gt;polyglot.Context&lt;/code&gt; is not thread-safe. It isn't a problem in itself, since we can spin up multiple contexts. However, variables in &lt;code&gt;js&lt;/code&gt; refer to variables in a specific context. Thus, if we want to use multiple contexts, we cannot refer to variables in the &lt;code&gt;js&lt;/code&gt; namespace with the current settings. We may be able to mitigate or solve this problem with dynamic bindings or using a dedicated thread for JavaScript operations.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-shorthands-for-dot-macros" class="outline-3"&gt;
&lt;a href="#shorthands-for-dot-macros"&gt;&lt;h3 id="shorthands-for-dot-macros" class="cr-self-reference "&gt;Shorthands for dot macros&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-shorthands-for-dot-macros"&gt;
&lt;p&gt;
We have already talked about it in the &lt;a href="#dot-macros-and-~set!~"&gt;Dot Macros&lt;/a&gt; section. In ClojureScript we can &lt;code&gt;(ClassName.)&lt;/code&gt; for instantiate an instance or &lt;code&gt;(.method obj)&lt;/code&gt; for invoking an method. Implementing them would be really hard if not impossible.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-importing-ecmascript-modules" class="outline-3"&gt;
&lt;a href="#importing-ecmascript-modules"&gt;&lt;h3 id="importing-ecmascript-modules" class="cr-self-reference "&gt;Importing ECMAScript Modules&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-importing-ecmascript-modules"&gt;
&lt;p&gt;
The &lt;code&gt;require-js&lt;/code&gt; function can only import CommonJS modules. More and more projects are choosing ECMAScript modules over CommonJS modules these days. However, implementing an importing mechanism for ECMAScript modules is entirely feasible. GraalJS provides a &lt;code&gt;js.esm-eval-returns-exports&lt;/code&gt; option, with this option enabled, we can import a ECMAScript module by loading the source file. However, it will take some time to write support for things like &lt;code&gt;exports&lt;/code&gt; fields in &lt;code&gt;package.json&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-using-javascript-array-in-clojure" class="outline-3"&gt;
&lt;a href="#using-javascript-array-in-clojure"&gt;&lt;h3 id="using-javascript-array-in-clojure" class="cr-self-reference "&gt;Using JavaScript array in Clojure&lt;/h3&gt;&lt;/a&gt;
&lt;div class="outline-text-3" id="text-using-javascript-array-in-clojure"&gt;
&lt;p&gt;
In ClojureScript, many times we can use a JavaScript array just like a ClojureScript vector (not vice versa though).
We haven't implement something similar to this.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;;; ClojureScript&lt;/span&gt;
(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [x] (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;*&lt;/span&gt;&lt;/span&gt; x &lt;span class="hljs-number"&gt;2&lt;/span&gt;)) #js [&lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-number"&gt;2&lt;/span&gt; &lt;span class="hljs-number"&gt;3&lt;/span&gt;])
&lt;span class="hljs-comment"&gt;;; (2 4 6)&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-to-be-continue..." class="outline-2"&gt;
&lt;a href="#to-be-continue..."&gt;&lt;h2 id="to-be-continue..." class="cr-self-reference "&gt;To Be Continue…&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-to-be-continue..."&gt;
&lt;p&gt;
Despite the limitations, I still believe this approach is something worth exploring. I'm planning on making an isomorphic React demonstration with Server Side Rendering and Client Side Rehydration using only a thin wrapper over React and React DOM Server (instead of reimplementing the SSR logics on the JVM). The code presented here is also expanded and refined when I'm writing the blog, and the code is open sourced at &lt;a href="https://github.com/imakira/js4clj"&gt;imakira/js4clj&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Build a ClojureScript Application Running on Node Using Nix</title>
    <link href="https://coruscation.net/blogs/build-a-clojurescript-application-running-on-node-using-nix.html"/>
    <published>2025-11-03T17:25:27+08:00</published>
    <updated>2026-01-17T17:39:46+08:00</updated>
    <id>https://coruscation.net/blogs/build-a-clojurescript-application-running-on-node-using-nix.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
To build a ClojureScript application, we need to pull dependencies from two package managers. That is, JavaScript packages from &lt;code&gt;npm&lt;/code&gt; and Clojure packages from &lt;code&gt;deps.edn&lt;/code&gt;. After pulling the dependencies, we can then let &lt;code&gt;shadow-cljs&lt;/code&gt; compiles the ClojureScript files into a single javascript and make the result a npm package. In this post, we rely on &lt;code&gt;nixpkgs&lt;/code&gt;&amp;#x27;s builtin &lt;code&gt;fetchNpmDeps&lt;/code&gt; and &lt;code&gt;buildNpmPackage&lt;/code&gt; for the npm side, and &lt;a href="https://github.com/jlesquembre/clj-nix"&gt;clj-nix&lt;/a&gt; for the nix side.
&lt;/p&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;ul class="org-ul"&gt;
&lt;li&gt;&lt;b&gt;changelog&lt;/b&gt;   Jan 17, 2026: use a new method to build the nix package, supports git repos, reduces output size.&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div id="outline-container-prerequisites" class="outline-2"&gt;&lt;a href="#prerequisites"&gt;&lt;h2 id="prerequisites" class="cr-self-reference "&gt;Prerequisites&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-prerequisites" class="outline-text-2"&gt;&lt;p&gt;
I will skip the details that are not unique to Nix. The following contents assume we already have a working shadow-cljs project that can produce a node.js target when running &lt;code&gt;npm run release&lt;/code&gt;. Which is basically:
&lt;/p&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;a &lt;code&gt;:node-script&lt;/code&gt; target in &lt;code&gt;shadow-cljs.edn&lt;/code&gt;, with &lt;code&gt;:main&lt;/code&gt; function specified&lt;/li&gt;&lt;li&gt;a &lt;code&gt;release&lt;/code&gt; script in package.json, most probably &lt;code&gt;shadow-cljs release script&lt;/code&gt;&lt;/li&gt;&lt;li&gt;an entry script specified in &lt;code&gt;bin&lt;/code&gt; in package.json.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-prefetch-and-generate-lock-file-for-dependencies" class="outline-2"&gt;&lt;a href="#prefetch-and-generate-lock-file-for-dependencies"&gt;&lt;h2 id="prefetch-and-generate-lock-file-for-dependencies" class="cr-self-reference "&gt;Prefetch and generate lock file for dependencies&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-prefetch-and-generate-lock-file-for-dependencies" class="outline-text-2"&gt;&lt;p&gt;
During the &lt;i&gt;build&lt;/i&gt; phase of nix package, the process cannot perform any network request, as that will defeat the whole point of &lt;i&gt;determinism&lt;/i&gt;. The common practice is to use a &lt;i&gt;lock file&lt;/i&gt;. Which is essentially a recipe of all the necessary resources (and their checksums) for the building process. We can then prefetch all the resources into the nix store and tell the building process where to find the necessary resources during the actual building.
&lt;/p&gt;&lt;p&gt;
On the npm side, we do it by running the following command. It will output a sha256 code, we save it for later.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;nix run nixpkgs#prefetch-npm-deps package-lock.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
On the Clojure side, we execute the following command. It will generate a &lt;code&gt;deps-lock.json&lt;/code&gt; file. We will refer it in the &lt;code&gt;flake.nix&lt;/code&gt;.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-bash"&gt;nix run github:jlesquembre/clj-nix#deps-lock
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-build-with-shadow-cljs-and-~mkcljlib~" class="outline-2"&gt;&lt;a href="#build-with-shadow-cljs-and-~mkcljlib~"&gt;&lt;h2 id="build-with-shadow-cljs-and-~mkcljlib~" class="cr-self-reference "&gt;Build with shadow-cljs and &lt;code&gt;mkCljLib&lt;/code&gt;&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-build-with-shadow-cljs-and-~mkcljlib~" class="outline-text-2"&gt;&lt;p&gt;
We need to add &lt;code&gt;clj-nix&lt;/code&gt;&amp;#x27;s overlays to our flake.nix to be able to use &lt;code&gt;mkCljLib&lt;/code&gt;.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;p&lt;span class="hljs-attr"&gt;kgs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-built_in"&gt;import&lt;/span&gt; nixpkgs {
  &lt;span class="hljs-keyword"&gt;inherit&lt;/span&gt; system;
  &lt;span class="hljs-attr"&gt;overlays&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; [
    clj-nix.overlays.default
  ];
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
First, we create a &lt;code&gt;node_modules&lt;/code&gt; derivative which we will use later.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;d&lt;span class="hljs-attr"&gt;eps-hash&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;deps-hash&amp;quot;&lt;/span&gt;;

&lt;span class="hljs-attr"&gt;npm-deps&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.buildNpmPackage(&lt;span class="hljs-params"&gt;finalAttrs:&lt;/span&gt; {
  &lt;span class="hljs-attr"&gt;src&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; self;
  &lt;span class="hljs-attr"&gt;pname&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;package-npm-deps&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;version&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;0.0&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;dontNpmBuild&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;npmDepsHash&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; deps-hash;
  &lt;span class="hljs-attr"&gt;installPhase&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;#x27;&amp;#x27;
  mkdir $out
  cp -r ./node_modules $out/node_modules
  &amp;#x27;&amp;#x27;&lt;/span&gt;;
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
We will use &lt;code&gt;mkCljLib&lt;/code&gt; to setup Clojure dependencies for us, while we copy JavaScript dependencies from the earlier step manually.
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;b&lt;span class="hljs-attr"&gt;uild&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.mkCljLib {
  &lt;span class="hljs-attr"&gt;projectSrc&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; self;
  &lt;span class="hljs-attr"&gt;name&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;espoir&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;buildCommand&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;
  # copy node_modules from earlier step to build directory
  cp -r &lt;span class="hljs-subst"&gt;${npm-deps}&lt;/span&gt;/node_modules ./node_modules
  &lt;span class="hljs-subst"&gt;${pkgs.nodejs}&lt;/span&gt;/bin/npm run release
  &amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;installPhase&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;#x27;&amp;#x27;
  mkdir -p $out
  cp -R * $out/
  &amp;#x27;&amp;#x27;&lt;/span&gt;;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;
In the &lt;code&gt;buildCommand&lt;/code&gt;, we setup the JavaScript dependencies, and call &lt;code&gt;npm run release&lt;/code&gt; which in turn calls &lt;code&gt;shadow-cljs&lt;/code&gt; to build the project.
&lt;/p&gt;&lt;p&gt;
In &lt;code&gt;installPhase&lt;/code&gt;, we override the install process provided by &lt;code&gt;mkCljLib&lt;/code&gt;. Instead, we simply use all the files in the build directory as output.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-package-results-as-a-npm-package" class="outline-2"&gt;&lt;a href="#package-results-as-a-npm-package"&gt;&lt;h2 id="package-results-as-a-npm-package" class="cr-self-reference "&gt;Package results as a npm package&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-package-results-as-a-npm-package" class="outline-text-2"&gt;&lt;p&gt;
We can directly feed output from the earlier example to &lt;code&gt;builNpmPackage&lt;/code&gt;. Since we already build the package, we will set &lt;code&gt;dontNpmBuild = true;&lt;/code&gt;.
&lt;/p&gt;&lt;p&gt;
The install process provided by &lt;code&gt;buildNpmPackage&lt;/code&gt; will package necessary dependencies and generate an executable calling the entry script. 
&lt;/p&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;p&lt;span class="hljs-attr"&gt;ackages.default&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.buildNpmPackage {
  &lt;span class="hljs-attr"&gt;pname&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;espoir&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;src&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; build;
  &lt;span class="hljs-attr"&gt;dontNpmBuild&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;version&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;0.0.1&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;npmDepsHash&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; deps-hash;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-tips" class="outline-2"&gt;&lt;a href="#tips"&gt;&lt;h2 id="tips" class="cr-self-reference "&gt;Tips&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-tips" class="outline-text-2"&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;Check &lt;a href="https://github.com/imakira/espoir/blob/main/flake.nix"&gt;imakira/espoir/blob/main/flake.nix&lt;/a&gt; for a working example.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Develop and Build a Common Lisp Project using Nix</title>
    <link href="https://coruscation.net/blogs/develop-and-build-a-common-lisp-project-using-nix.html"/>
    <published>2025-10-27T17:50:17+08:00</published>
    <updated>2025-10-27T17:50:17+08:00</updated>
    <id>https://coruscation.net/blogs/develop-and-build-a-common-lisp-project-using-nix.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;p&gt;
I recently tried to build a Common Lisp project using Nix and found it is quite easy with just the &lt;code&gt;buildASDFSystem&lt;/code&gt; function in nixpkgs and ASDF alone. I will share how I have done it here in case someone else finds it useful.
&lt;/p&gt;
&lt;div id="outline-container-simple-configuration-when-developing" class="outline-2"&gt;
&lt;a href="#simple-configuration-when-developing"&gt;&lt;h2 id="simple-configuration-when-developing" class="cr-self-reference "&gt;Simple Configuration When Developing&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-simple-configuration-when-developing"&gt;
&lt;p&gt;
On the Nix we will have something like this:
&lt;/p&gt;
&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;# flake.nix&lt;/span&gt;
{
  &lt;span class="hljs-attr"&gt;description&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;inputs.flake-utils.url&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;github:numtide/flake-utils&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;inputs.nixpkgs.url&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;github:NixOS/nixpkgs/nixos-unstable&amp;quot;&lt;/span&gt;;
  &lt;span class="hljs-attr"&gt;outputs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; { self, flake-utils, nixpkgs }:
    flake-utils.lib.eachDefaultSystem (&lt;span class="hljs-params"&gt;system:&lt;/span&gt;
      &lt;span class="hljs-keyword"&gt;let&lt;/span&gt; pkgs &lt;span class="hljs-operator"&gt;=&lt;/span&gt; nixpkgs.legacyPackages.${system};
      &lt;span class="hljs-keyword"&gt;in&lt;/span&gt; &lt;span class="hljs-keyword"&gt;rec&lt;/span&gt; {
        &lt;span class="hljs-attr"&gt;packages.default&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.sbcl.buildASDFSystem {
          &lt;span class="hljs-attr"&gt;pname&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;proj-name&amp;quot;&lt;/span&gt;;
          &lt;span class="hljs-attr"&gt;version&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;0.1&amp;quot;&lt;/span&gt;;
          &lt;span class="hljs-attr"&gt;src&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; self;
          &lt;span class="hljs-attr"&gt;lispLibs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; pkgs.sbclPackages; [
            alexandria
            &lt;span class="hljs-comment"&gt;# lisp packages in nixpkgs go here&lt;/span&gt;
          ];
          &lt;span class="hljs-attr"&gt;nativeLibs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; [
            &lt;span class="hljs-comment"&gt;# native libs go here&lt;/span&gt;
          ];
        };
      }
    );
}
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
On the Lisp side we will have an &lt;code&gt;asd&lt;/code&gt; file
&lt;/p&gt;
&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-lisp"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;;; proj-name.asd&lt;/span&gt;
(&lt;span class="hljs-name"&gt;require&lt;/span&gt; 'asdf)
(&lt;span class="hljs-name"&gt;asdf&lt;/span&gt;&lt;span class="hljs-symbol"&gt;:defsystem&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;proj-name&amp;quot;&lt;/span&gt;
  &lt;span class="hljs-symbol"&gt;:depends-on&lt;/span&gt; (&lt;span class="hljs-name"&gt;#&lt;/span&gt;&lt;span class="hljs-symbol"&gt;:alexandria&lt;/span&gt;)
  &lt;span class="hljs-symbol"&gt;:components&lt;/span&gt; ((&lt;span class="hljs-symbol"&gt;:file&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;))) &lt;span class="hljs-comment"&gt;;; we will have a main.lisp file&lt;/span&gt;
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
With these two files we can then start developing the project with the following steps
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;Enter nix develop environment by executing &lt;code&gt;nix develop .&lt;/code&gt; in the directory the project.&lt;/li&gt;
&lt;li&gt;Launch Emacs inside the developing environment.&lt;/li&gt;
&lt;li&gt;Launch &lt;code&gt;sly&lt;/code&gt; (or &lt;code&gt;slime&lt;/code&gt;) in Emacs, and load the &lt;code&gt;asd&lt;/code&gt; file by &lt;code&gt;sly-compile-and-load-file&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Execute &lt;code&gt;(asdf:load-system &amp;quot;proj-name&amp;quot;)&lt;/code&gt; in the &lt;code&gt;sly&lt;/code&gt; repl.&lt;/li&gt;
&lt;li&gt;Enjoy!&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-building-an-executable" class="outline-2"&gt;
&lt;a href="#building-an-executable"&gt;&lt;h2 id="building-an-executable" class="cr-self-reference "&gt;Building an Executable&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-building-an-executable"&gt;
&lt;p&gt;
To build an executable we need a few more snippets on the Nix side
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-nix"&gt;&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;span class="hljs-comment"&gt;#...&lt;/span&gt;

&lt;span class="hljs-attr"&gt;packages.default&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.sbcl.buildASDFSystem {
  &lt;span class="hljs-comment"&gt;# ...&lt;/span&gt;
  &lt;span class="hljs-comment"&gt;# other code is omitted here&lt;/span&gt;
  &lt;span class="hljs-attr"&gt;lispLibs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; &lt;span class="hljs-keyword"&gt;with&lt;/span&gt; pkgs.sbclPackages; [
    alexandria
    &lt;span class="hljs-comment"&gt;# lisp packages in nixpkgs go here&lt;/span&gt;
  ];

  &lt;span class="hljs-attr"&gt;nativeBuildInputs&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; [
    pkgs.makeWrapper
  ];

  &lt;span class="hljs-attr"&gt;buildScript&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt; pkgs.writeText &lt;span class="hljs-string"&gt;&amp;quot;build-awesomes&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;''
    (require 'asdf)
    (asdf:load-system &amp;quot;proj-name&amp;quot;)
    (sb-ext:save-lisp-and-die
                &amp;quot;proj-name&amp;quot;
                :executable t
                #+sb-core-compression :compression
                #+sb-core-compression t
                ;; assume we have the `main' function defined and exported in the main.lisp file
                :toplevel #'main:main) 
  ''&lt;/span&gt;;

  &lt;span class="hljs-attr"&gt;installPhase&lt;/span&gt; &lt;span class="hljs-operator"&gt;=&lt;/span&gt;   &lt;span class="hljs-string"&gt;''
    runHook preInstall
    mkdir -p $out/bin
    cp proj-name $out/bin

    # make sure the executable can find dynamically linked libraries
    wrapProgram $out/bin/proj-name \
                --prefix LD_LIBRARY_PATH : $LD_LIBRARY_PATH
    runHook postInstall
  ''&lt;/span&gt;;
};
&lt;/body&gt;&lt;/html&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
When we execute &lt;code&gt;nix build .&lt;/code&gt; in the project directory, lisp scripts in &lt;code&gt;buildScript&lt;/code&gt; will be executed and generates a binary file &lt;code&gt;proj-name&lt;/code&gt;. The binary file will then be copied into &lt;code&gt;$out/bin&lt;/code&gt; directory by the scripts inside &lt;code&gt;installPhase&lt;/code&gt;. After the &lt;code&gt;nix build .&lt;/code&gt; finished, we can find the executable in the &lt;code&gt;result/bin/&lt;/code&gt; directory
&lt;/p&gt;

&lt;p&gt;
We can also use &lt;code&gt;nix run .&lt;/code&gt; to run the result executable directly.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id="outline-container-limitations-of-this-method-and-other-notes" class="outline-2"&gt;
&lt;a href="#limitations-of-this-method-and-other-notes"&gt;&lt;h2 id="limitations-of-this-method-and-other-notes" class="cr-self-reference "&gt;Limitations of This Method and Other Notes&lt;/h2&gt;&lt;/a&gt;
&lt;div class="outline-text-2" id="text-limitations-of-this-method-and-other-notes"&gt;
&lt;p&gt;
The biggest limitation of this solution may be you need to restart the REPL (or even the Emacs launched inside the develop environment) every time you add a package into the &lt;code&gt;flake.nix&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
You can find the lisp section of the nixpkgs documentation &lt;a href="https://nixos.org/manual/nixpkgs/stable/#lisp-overview"&gt;here&lt;/a&gt;. &lt;a href="https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/development/lisp-modules/packages.nix"&gt;packages.nix&lt;/a&gt; in the nixpkgs also has plenty lisp project definitions we can take references from.
&lt;/p&gt;

&lt;p&gt;
I have a &lt;a href="https://github.com/imakira/awesomes"&gt;little project&lt;/a&gt; built this way and it runs on github actions simply by using &lt;code&gt;nix run .&lt;/code&gt;, you can also check that.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</content>
  </entry>
  <entry>
    <title type="html">Demonstration</title>
    <link href="https://coruscation.net/blogs/demonstration.html"/>
    <published>2024-10-13T22:15:21+08:00</published>
    <updated>2026-01-03T01:45:44+08:00</updated>
    <id>https://coruscation.net/blogs/demonstration.html</id>
    <content type="html">&lt;div class="cr-document md:mt-1"&gt;&lt;div id="outline-container-code-blocks" class="outline-2"&gt;&lt;a href="#code-blocks"&gt;&lt;h2 id="code-blocks" class="cr-self-reference "&gt;Code Blocks&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-code-blocks" class="outline-text-2"&gt;&lt;/div&gt;&lt;div id="outline-container-inline-code-block" class="outline-3"&gt;&lt;a href="#inline-code-block"&gt;&lt;h3 id="inline-code-block" class="cr-self-reference "&gt;Inline Code Block&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-inline-code-block" class="outline-text-3"&gt;&lt;p&gt;
Text around &lt;!-- --&gt;(&lt;span class="hljs-name"&gt;uix.dom/create-root&lt;/span&gt; (&lt;span class="hljs-name"&gt;js/document.getElementById&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;))&lt;!-- --&gt; the inline code block.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-code-blocks3" class="outline-3"&gt;&lt;a href="#code-blocks3"&gt;&lt;h3 id="code-blocks3" class="cr-self-reference "&gt;Code Blocks&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-code-blocks3" class="outline-text-3"&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;Java&lt;/li&gt;&lt;/ul&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-java"&gt;&lt;span class="hljs-keyword"&gt;public&lt;/span&gt; &lt;span class="hljs-keyword"&gt;static&lt;/span&gt; &lt;span class="hljs-type"&gt;int&lt;/span&gt; &lt;span class="hljs-title function_"&gt;fib&lt;/span&gt;&lt;span class="hljs-params"&gt;(&lt;span class="hljs-type"&gt;int&lt;/span&gt; n)&lt;/span&gt; { 
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (n &amp;lt;= &lt;span class="hljs-number"&gt;1&lt;/span&gt;) {
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; n;
    }
    &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; fib(n - &lt;span class="hljs-number"&gt;1&lt;/span&gt;) + fib(n - &lt;span class="hljs-number"&gt;2&lt;/span&gt;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;Clojure&lt;/li&gt;&lt;/ul&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; app [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [initial-route]}]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [[show-header? set-header!]
        (&lt;span class="hljs-name"&gt;use-state&lt;/span&gt;
         (&lt;span class="hljs-name"&gt;some&lt;/span&gt; #(&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; % initial-route)
               [&lt;span class="hljs-string"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;/home.html&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;/template.html&amp;quot;&lt;/span&gt;
                &lt;span class="hljs-string"&gt;&amp;quot;/index.html&amp;quot;&lt;/span&gt;]))]
    (&lt;span class="hljs-name"&gt;context-binding&lt;/span&gt; [*header-context* [show-header? set-header!]]
      ($ router/router {&lt;span class="hljs-symbol"&gt;:routes&lt;/span&gt; routes &lt;span class="hljs-symbol"&gt;:initial-route&lt;/span&gt; initial-route}
         ($ main {})))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;Emacs Lisp&lt;/li&gt;&lt;/ul&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;(&lt;span class="hljs-name"&gt;save-excursion&lt;/span&gt;                 
    (&lt;span class="hljs-name"&gt;goto-char&lt;/span&gt; (&lt;span class="hljs-name"&gt;point-min&lt;/span&gt;))    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="org-src-container"&gt;&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-emacs-lisp"&gt;(&lt;span class="hljs-name"&gt;with-current-buffer&lt;/span&gt; (&lt;span class="hljs-name"&gt;current-buffer&lt;/span&gt;)
  (&lt;span class="hljs-name"&gt;let&lt;/span&gt; ((&lt;span class="hljs-name"&gt;ids&lt;/span&gt; (&lt;span class="hljs-name"&gt;org-map-entries&lt;/span&gt; (&lt;span class="hljs-name"&gt;lambda&lt;/span&gt; ()
                                (&lt;span class="hljs-name"&gt;org-entry-get&lt;/span&gt; &lt;span class="hljs-literal"&gt;nil&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;custom_id&amp;quot;&lt;/span&gt;)))))
    (&lt;span class="hljs-name"&gt;org-map-entries&lt;/span&gt; (&lt;span class="hljs-name"&gt;lambda&lt;/span&gt; ()
                       (&lt;span class="hljs-name"&gt;when&lt;/span&gt; (&lt;span class="hljs-name"&gt;not&lt;/span&gt; (&lt;span class="hljs-name"&gt;org-entry-get&lt;/span&gt; &lt;span class="hljs-literal"&gt;nil&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;custom_id&amp;quot;&lt;/span&gt;))
                         (&lt;span class="hljs-name"&gt;let*&lt;/span&gt; ((&lt;span class="hljs-name"&gt;candidate-id&lt;/span&gt; (&lt;span class="hljs-name"&gt;concat&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;blog_&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;url-encode-url&lt;/span&gt; (&lt;span class="hljs-name"&gt;nth&lt;/span&gt; &lt;span class="hljs-number"&gt;4&lt;/span&gt; (&lt;span class="hljs-name"&gt;org-heading-components&lt;/span&gt;)))))
                                (&lt;span class="hljs-name"&gt;duplicates&lt;/span&gt; (&lt;span class="hljs-name"&gt;cl-count&lt;/span&gt; candidate-id ids)))
                           (&lt;span class="hljs-name"&gt;org-entry-put&lt;/span&gt; &lt;span class="hljs-literal"&gt;nil&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;custom_id&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;concat&lt;/span&gt; candidate-id
                                                                  (&lt;span class="hljs-name"&gt;prin1-to-string&lt;/span&gt; (&lt;span class="hljs-name"&gt;+&lt;/span&gt; &lt;span class="hljs-number"&gt;1&lt;/span&gt; duplicates))))))
                       (&lt;span class="hljs-name"&gt;setq&lt;/span&gt; ids (&lt;span class="hljs-name"&gt;cons&lt;/span&gt; (&lt;span class="hljs-name"&gt;org-entry-get&lt;/span&gt; &lt;span class="hljs-literal"&gt;nil&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;custom_id&amp;quot;&lt;/span&gt;)
                                       ids))))))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-h2-sample-text" class="outline-2"&gt;&lt;a href="#h2-sample-text"&gt;&lt;h2 id="h2-sample-text" class="cr-self-reference "&gt;H2 Sample Text&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-h2-sample-text" class="outline-text-2"&gt;&lt;/div&gt;&lt;div id="outline-container-h3-sample-text-sample-text" class="outline-3"&gt;&lt;a href="#h3-sample-text-sample-text"&gt;&lt;h3 id="h3-sample-text-sample-text" class="cr-self-reference "&gt;H3 Sample Text Sample Text&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-h3-sample-text-sample-text" class="outline-text-3"&gt;&lt;p&gt;
Some text in between
&lt;/p&gt;&lt;/div&gt;&lt;div id="outline-container-h4-sample-text-sample-text" class="outline-4"&gt;&lt;a href="#h4-sample-text-sample-text"&gt;&lt;h4 id="h4-sample-text-sample-text" class="cr-self-reference "&gt;H4 Sample Text Sample Text&lt;/h4&gt;&lt;/a&gt;&lt;div id="text-h4-sample-text-sample-text" class="outline-text-4"&gt;&lt;p&gt;
Some text in between
&lt;/p&gt;&lt;/div&gt;&lt;div id="outline-container-h5-sample-text-sample-text" class="outline-5"&gt;&lt;a href="#h5-sample-text-sample-text"&gt;&lt;h5 id="h5-sample-text-sample-text" class="cr-self-reference "&gt;H5 Sample Text Sample Text&lt;/h5&gt;&lt;/a&gt;&lt;div id="text-h5-sample-text-sample-text" class="outline-text-5"&gt;&lt;p&gt;
Some text in between
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-common-elements" class="outline-2"&gt;&lt;a href="#common-elements"&gt;&lt;h2 id="common-elements" class="cr-self-reference "&gt;Common Elements&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-common-elements" class="outline-text-2"&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;&lt;i&gt;italic&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;bold&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="underline"&gt;underline&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;verbatim&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;code&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;del&gt;strike-through&lt;/del&gt;&lt;/li&gt;&lt;li&gt;Horizontal Rule&lt;/li&gt;&lt;li&gt;&lt;code&gt;code&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr/&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-other-elements" class="outline-2"&gt;&lt;a href="#other-elements"&gt;&lt;h2 id="other-elements" class="cr-self-reference "&gt;Other Elements&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-other-elements" class="outline-text-2"&gt;&lt;/div&gt;&lt;div id="outline-container-table" class="outline-3"&gt;&lt;a href="#table"&gt;&lt;h3 id="table" class="cr-self-reference "&gt;Table&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-table" class="outline-text-3"&gt;&lt;table&gt;&lt;colgroup&gt;&lt;col class="org-left"/&gt;&lt;col class="org-right"/&gt;&lt;col class="org-right"/&gt;&lt;/colgroup&gt;&lt;thead&gt;&lt;tr&gt;&lt;th class="org-left" scope="col"&gt;Name&lt;/th&gt;&lt;th class="org-right" scope="col"&gt;Phone&lt;/th&gt;&lt;th class="org-right" scope="col"&gt;Age&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="org-left"&gt;Peter&lt;/td&gt;&lt;td class="org-right"&gt;1234&lt;/td&gt;&lt;td class="org-right"&gt;17&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="org-left"&gt;Anna&lt;/td&gt;&lt;td class="org-right"&gt;4321&lt;/td&gt;&lt;td class="org-right"&gt;25&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-reference" class="outline-3"&gt;&lt;a href="#reference"&gt;&lt;h3 id="reference" class="cr-self-reference "&gt;Reference&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-reference" class="outline-text-3"&gt;&lt;blockquote&gt;&lt;p&gt;
Everything should be made as simple as possible,
but not any simpler – Albert Einstein
&lt;/p&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-unordered-list" class="outline-3"&gt;&lt;a href="#unordered-list"&gt;&lt;h3 id="unordered-list" class="cr-self-reference "&gt;Unordered List&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-unordered-list" class="outline-text-3"&gt;&lt;ul class="org-ul"&gt;&lt;li&gt;Item 1&lt;/li&gt;&lt;li&gt;Item 2
&lt;ul class="org-ul"&gt;&lt;li&gt;Level 2
&lt;ul class="org-ul"&gt;&lt;li&gt;Level 3
&lt;ul class="org-ul"&gt;&lt;li&gt;Level 4&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Another Mark&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Item 3&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id="outline-container-ordered-list" class="outline-5"&gt;&lt;a href="#ordered-list"&gt;&lt;h5 id="ordered-list" class="cr-self-reference "&gt;Ordered List&lt;/h5&gt;&lt;/a&gt;&lt;div id="text-ordered-list" class="outline-text-5"&gt;&lt;ol class="org-ol"&gt;&lt;li&gt;Item 1&lt;/li&gt;&lt;li&gt;Item 2&lt;/li&gt;&lt;li&gt;Item 3&lt;/li&gt;&lt;li&gt;Item 4&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-description-list" class="outline-3"&gt;&lt;a href="#description-list"&gt;&lt;h3 id="description-list" class="cr-self-reference "&gt;Description List&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-description-list" class="outline-text-3"&gt;&lt;dl class="org-dl"&gt;&lt;dt&gt;Name&lt;/dt&gt;&lt;dd&gt;Description
&lt;dl class="org-dl"&gt;&lt;dt&gt;Nested&lt;/dt&gt;&lt;dd&gt;Nested Description&lt;/dd&gt;&lt;/dl&gt;&lt;/dd&gt;&lt;dt&gt;Name&lt;/dt&gt;&lt;dd&gt;Description&lt;/dd&gt;&lt;/dl&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-sample-image" class="outline-3"&gt;&lt;a href="#sample-image"&gt;&lt;h3 id="sample-image" class="cr-self-reference "&gt;Sample Image&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-sample-image" class="outline-text-3"&gt;&lt;figure id="org7945d1e"&gt;&lt;img width="550" height="368" src="imgs/1.jpg" alt="1.jpg"/&gt;&lt;figcaption&gt;&lt;span class="figure-number"&gt;Figure 1: &lt;/span&gt;This is an image&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure id="orgb3cbb86"&gt;&lt;img width="550" height="368" src="imgs/1.webp" alt="1.webp"/&gt;&lt;/figure&gt;&lt;figure id="orgea2ba69"&gt;&lt;img width="2624" height="3936" src="https://images.unsplash.com/photo-1746717410283-f4017128c38f?ixlib=rb-4.1.0&amp;amp;q=85&amp;amp;fm=jpg&amp;amp;crop=entropy&amp;amp;cs=srgb&amp;amp;dl=natalia-grela-sFINbLpdfqw-unsplash.jpg" alt="photo-1746717410283-f4017128c38f?ixlib=rb-4.1.0&amp;amp;q=85&amp;amp;fm=jpg&amp;amp;crop=entropy&amp;amp;cs=srgb&amp;amp;dl=natalia-grela-sFINbLpdfqw-unsplash.jpg"/&gt;&lt;figcaption&gt;&lt;span class="figure-number"&gt;Figure 2: &lt;/span&gt;sample high resolution vertical image&lt;/figcaption&gt;&lt;/figure&gt;&lt;figure id="org27f30ec"&gt;&lt;img width="4928" height="3280" src="https://images.unsplash.com/photo-1653384236127-c61634419fe0?ixlib=rb-4.1.0&amp;amp;q=85&amp;amp;fm=jpg&amp;amp;crop=entropy&amp;amp;cs=srgb&amp;amp;dl=johann-walter-bantz-Bp7hIvZnj9I-unsplash.jpg" alt="photo-1653384236127-c61634419fe0?ixlib=rb-4.1.0&amp;amp;q=85&amp;amp;fm=jpg&amp;amp;crop=entropy&amp;amp;cs=srgb&amp;amp;dl=johann-walter-bantz-Bp7hIvZnj9I-unsplash.jpg"/&gt;&lt;figcaption&gt;&lt;span class="figure-number"&gt;Figure 3: &lt;/span&gt;sample high resolution horizontal iamge&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-verbatim" class="outline-3"&gt;&lt;a href="#verbatim"&gt;&lt;h3 id="verbatim" class="cr-self-reference "&gt;Verbatim&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-verbatim" class="outline-text-3"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-inline-cljc-code" class="outline-2"&gt;&lt;a href="#inline-cljc-code"&gt;&lt;h2 id="inline-cljc-code" class="cr-self-reference "&gt;Inline CLJC Code (OrgX)&lt;/h2&gt;&lt;/a&gt;&lt;div id="text-inline-cljc-code" class="outline-text-2"&gt;&lt;p&gt;
You can embedded Clojure code inside a blog file using &lt;code&gt;#+begin_orgx&lt;/code&gt; blocks.
&lt;/p&gt;&lt;p&gt;
Enable this feature first in the org metadata:
&lt;/p&gt;&lt;pre id="org90926bc" class="example"&gt;#+ORGX: true
&lt;/pre&gt;&lt;p&gt;
With the following snippet embedded in a org file.
&lt;/p&gt;&lt;pre id="org43dffbb" class="example"&gt;#+begin_orgx
  ;; You can style it using tailwindcss
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot; :on-click (fn [&amp;amp; _] #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))} &amp;quot;Click Me&amp;quot;)
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
We can get a clickable button in the generated page:
&lt;/p&gt;&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;&lt;p&gt;
Since the code is in CLJC, this feature works very well with static page generation / server side rendering. However, you must wrap plaform specified code in read macros like we do in a normal CLJC file.
&lt;/p&gt;&lt;p&gt;
We can access the blog page&amp;#x27;s meta data using &lt;code&gt;post-props&lt;/code&gt; variable.
&lt;/p&gt;&lt;pre id="orgc3823e2" class="example"&gt;#+begin_orgx
($ :div {:class &amp;quot;bg-stone-50 pl-4 py-2 border-l-3 border-sky-500&amp;quot;} (str (keys post-props)))
#+end_orgx
&lt;/pre&gt;&lt;div class="bg-stone-50 pl-4 py-2 border-l-3 border-sky-500"&gt;(:blog/orgx :blog/tags :blog/unlisted :blog/title :blog/show-toc? :blog/file-path :blog/author :blog/email :blog/description :blog/id :blog/category :blog/language :blog/published-date :blog/content :blog/orgx-require :blog/modified-date)&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-inline-clojure-snippet" class="outline-3"&gt;&lt;a href="#inline-clojure-snippet"&gt;&lt;h3 id="inline-clojure-snippet" class="cr-self-reference "&gt;Inline Clojure Snippet&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-inline-clojure-snippet" class="outline-text-3"&gt;&lt;pre id="org5988fe9" class="example"&gt;We can @@orgx:($ :span.bg-cyan-50.mt-2.pl-2.py-1.border-l-3.border-sky-500 &amp;quot;also have inline Clojure snippets&amp;quot;)@@ like this.
&lt;/pre&gt;&lt;p&gt;
Will be render as
&lt;/p&gt;&lt;p&gt;
We can &lt;span class="bg-cyan-50 mt-2 pl-2 py-2 border-l-3 border-sky-500"&gt;also have inline Clojure snippets&lt;/span&gt; like this.
&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-using-other-orgx-files-as-components" class="outline-3"&gt;&lt;a href="#using-other-orgx-files-as-components"&gt;&lt;h3 id="using-other-orgx-files-as-components" class="cr-self-reference "&gt;Using Other OrgX files as components&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-using-other-orgx-files-as-components" class="outline-text-3"&gt;&lt;p&gt;
Like with MDX, we can use other orgx files as components.
&lt;/p&gt;&lt;p&gt;
First we make a &lt;code&gt;note.org&lt;/code&gt; file with the following as contents, note the &lt;code&gt;#+UNLISTED&lt;/code&gt; property.
&lt;/p&gt;&lt;pre id="orgc287e0c" class="example"&gt;#+ORGX: true
#+UNLISTED: true
#+begin_orgx
($ :div
    ($ :div {:class &amp;quot;bg-stone-50 pl-4 py-2 border-l-3 border-rose-500&amp;quot;}
      ($ :div {:class &amp;quot;font-semibold mb-1 text-neutral-600&amp;quot;} &amp;quot;TIP&amp;quot;)
      ($ :div (:children post-props))))
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
When we want to use this OrgX file as a components, we need to add a &lt;code&gt;require&lt;/code&gt; declaration first.
&lt;/p&gt;&lt;pre id="orga4706af" class="example"&gt;#+ORGX_REQUIRE: [[orgx.note :as note]]
&lt;/pre&gt;&lt;p&gt;
Then we could use it like this
&lt;/p&gt;&lt;pre id="orgca6ee06" class="example"&gt;#+begin_orgx
($ note/component  &amp;quot;This is a note&amp;quot;)
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
It will be rendered as:
&lt;/p&gt;&lt;div&gt;&lt;div class="bg-stone-50 pl-4 py-2 border-l-3 border-rose-500"&gt;&lt;div class="font-semibold mb-1 text-neutral-600"&gt;TIP&lt;/div&gt;&lt;div&gt;This is a note&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-builtin-components" class="outline-3"&gt;&lt;a href="#builtin-components"&gt;&lt;h3 id="builtin-components" class="cr-self-reference "&gt;Builtin Components&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-builtin-components" class="outline-text-3"&gt;&lt;/div&gt;&lt;div id="outline-container-simple-remarks" class="outline-4"&gt;&lt;a href="#simple-remarks"&gt;&lt;h4 id="simple-remarks" class="cr-self-reference "&gt;Simple Remarks&lt;/h4&gt;&lt;/a&gt;&lt;div id="text-simple-remarks" class="outline-text-4"&gt;&lt;p&gt;
It has several builtin components, notebly, the following snippet:
&lt;/p&gt;&lt;pre id="orge6daffe" class="example"&gt;#+begin_orgx
($ info &amp;quot;This is an info&amp;quot;)
($ note &amp;quot;This is a note&amp;quot;)
($ warn &amp;quot;This is a warn&amp;quot;)
($ error &amp;quot;This is an error&amp;quot;)
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
Will be rendered as:
&lt;/p&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-lime-500"&gt;&lt;div class="not-italic"&gt;This is an info&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;This is a note&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-rose-500"&gt;&lt;div class="not-italic"&gt;This is a warn&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-red-600"&gt;&lt;div class="not-italic"&gt;This is an error&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-tabs" class="outline-4"&gt;&lt;a href="#tabs"&gt;&lt;h4 id="tabs" class="cr-self-reference "&gt;Tabs&lt;/h4&gt;&lt;/a&gt;&lt;div id="text-tabs" class="outline-text-4"&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;tab_demo.org:&lt;/i&gt;&lt;pre id="org8987296" class="example"&gt;#+attr_orgx_defui: true
#+begin_orgx_code_clj
#+begin_src clojure
(defui tabs [{:keys [tab-list default-table class]}]
  (let [[selected-tab set-selected-tab!] (use-state (or default-table
                                                        (:name (first tab-list))))]
    ($ :div.my-4.relative.border-sky-300.border-l-2.border-l-neutral-100 {:class class}
       ($ :div.my-0.flex.relative.bg-neutral-100
          (map (fn [{:keys [name]}]
                 ($ :button.font-medium.text-neutral-700.bg-neutral-50.py-1.px-2.border-t-2.border-neutral-50.min-w-28.bg-neutral-50.border-t-neutral-100
                    {:key name
                     :class (when (= name selected-tab)
                              &amp;quot; text-sky-800 border-sky-400 bg-sky-100 border-t-sky-400&amp;quot;)
                     :on-click (fn []
                                 #?(:cljs
                                    (set-selected-tab! name)))}
                    name))
               tab-list))
       ($ :div.my-0.bg-neutral-50.overflow-hidden.px-2.h-full
          (:content (first (filter (fn [{:keys [name]}]
                                     (= name selected-tab))
                                   tab-list)))))))

#+end_src
#+end_orgx_code_clj

#+attr_orgx_defui: true
#+begin_orgx_code_org
#+begin_example
Well we can&amp;#x27;t display the contents recurisvely
#+end_example
#+end_orgx_code_org


#+begin_orgx
($ tabs {:tab-list [{:name &amp;quot;tab_demo.org&amp;quot; :content ($ code_org)} {:name &amp;quot;tabs.clj&amp;quot; :content ($ code_clj)}]})
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;div class="hidden"&gt;&lt;i&gt;tabs.clj:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;(&lt;span class="hljs-name"&gt;defui&lt;/span&gt; tabs [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [tab-list default-table class]}]
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [[selected-tab set-selected-tab!] (&lt;span class="hljs-name"&gt;use-state&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;or&lt;/span&gt;&lt;/span&gt; default-table
                                                        (&lt;span class="hljs-symbol"&gt;:name&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; tab-list))))]
    ($ &lt;span class="hljs-symbol"&gt;:div.my-4.relative.border-sky-300.border-l-2.border-l-neutral-100&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; class}
       ($ &lt;span class="hljs-symbol"&gt;:div.my-0.flex.relative.bg-neutral-100&lt;/span&gt;
          (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;map&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [name]}]
                 ($ &lt;span class="hljs-symbol"&gt;:button.font-medium.text-neutral-700.bg-neutral-50.py-1.px-2.border-t-2.border-neutral-50.min-w-28.bg-neutral-50.border-t-neutral-100&lt;/span&gt;
                    {&lt;span class="hljs-symbol"&gt;:key&lt;/span&gt; name
                     &lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;when&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; name selected-tab)
                              &lt;span class="hljs-string"&gt;&amp;quot; text-sky-800 border-sky-400 bg-sky-100 border-t-sky-400&amp;quot;&lt;/span&gt;)
                     &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; []
                                 #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt;
                                    (&lt;span class="hljs-name"&gt;set-selected-tab!&lt;/span&gt; name)))}
                    name))
               tab-list))
       ($ &lt;span class="hljs-symbol"&gt;:div.my-0.bg-neutral-50.overflow-hidden.px-2.h-full&lt;/span&gt;
          (&lt;span class="hljs-symbol"&gt;:content&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;first&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;filter&lt;/span&gt;&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [{&lt;span class="hljs-symbol"&gt;:keys&lt;/span&gt; [name]}]
                                     (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;=&lt;/span&gt;&lt;/span&gt; name selected-tab))
                                   tab-list)))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-split-layout" class="outline-4"&gt;&lt;a href="#split-layout"&gt;&lt;h4 id="split-layout" class="cr-self-reference "&gt;Split Layout&lt;/h4&gt;&lt;/a&gt;&lt;div id="text-split-layout" class="outline-text-4"&gt;&lt;p&gt;
Split layout lets you show two things side by side:
&lt;/p&gt;&lt;pre id="orgf29e9fd" class="example"&gt;#+attr_orgx_defui: true
#+begin_orgx_split_1
#+begin_src clojure
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
              :on-click (fn [&amp;amp; _]
                          #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))}
     &amp;quot;Click Me&amp;quot;)
#+end_src
#+end_orgx_split_1

#+attr_orgx_defui: true
#+begin_orgx_split_2
#+begin_orgx
  ($ :button {:class &amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;
              :on-click (fn [&amp;amp; _]
                          #?(:cljs (js/alert &amp;quot;clicked!&amp;quot;)))}
     &amp;quot;Click Me&amp;quot;)
#+end_orgx
#+end_orgx_split_2

#+begin_orgx
($ split-layout
($ tabs {:tab-list [{:name &amp;quot;button&amp;quot; :content ($ split_1)}]})
($ tabs {:tab-list [{:name &amp;quot;showcase&amp;quot; :content ($ split_2)}]}))
#+end_orgx
&lt;/pre&gt;&lt;p&gt;
Will be rendered as:
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;button:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;($ &lt;span class="hljs-symbol"&gt;:button&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;&lt;/span&gt;
            &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [&amp;amp; _]
                        #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt; (&lt;span class="hljs-name"&gt;js/alert&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;clicked!&amp;quot;&lt;/span&gt;)))}
   &lt;span class="hljs-string"&gt;&amp;quot;Click Me&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;showcase:&lt;/i&gt;&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-showcase" class="outline-4"&gt;&lt;a href="#showcase"&gt;&lt;h4 id="showcase" class="cr-self-reference "&gt;Showcase&lt;/h4&gt;&lt;/a&gt;&lt;div id="text-showcase" class="outline-text-4"&gt;&lt;p&gt;
Showcase is a simple wrapper over &lt;code&gt;split-layout&lt;/code&gt;.
&lt;/p&gt;&lt;div class="grid overflow-hidden grid-rows-2 lg:grid-rows-1 lg:grid-cols-2 "&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;showcase demo:&lt;/i&gt;&lt;pre id="orge967bb6" class="example"&gt;#+begin_orgx
($ showcase
  ($ tabs {:tab-list [{:name &amp;quot;button&amp;quot; :content ($ split_1)}]})
  ($ split_2))
#+end_orgx
&lt;/pre&gt;

&lt;/div&gt;&lt;div class="hidden"&gt;&lt;i&gt;button:&lt;/i&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="cr-highlighted"&gt;&lt;code class="lang-clojure"&gt;($ &lt;span class="hljs-symbol"&gt;:button&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:class&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg&amp;quot;&lt;/span&gt;
            &lt;span class="hljs-symbol"&gt;:on-click&lt;/span&gt; (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;fn&lt;/span&gt;&lt;/span&gt; [&amp;amp; _]
                        #?(&lt;span class="hljs-symbol"&gt;:cljs&lt;/span&gt; (&lt;span class="hljs-name"&gt;js/alert&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;clicked!&amp;quot;&lt;/span&gt;)))}
   &lt;span class="hljs-string"&gt;&amp;quot;Click Me&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;section class="my-4 relative border-1 border-neutral-100"&gt;&lt;div class="my-0 overflow-hidden px-2 h-full"&gt;&lt;div&gt;&lt;i&gt;Result:&lt;/i&gt;&lt;button class="bg-sky-600 text-neutral-50 py-1 px-2 rounded-lg"&gt;Click Me&lt;/button&gt;

&lt;/div&gt;&lt;/div&gt;&lt;/section&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id="outline-container-use-uix-components-with-org-mode-markups" class="outline-3"&gt;&lt;a href="#use-uix-components-with-org-mode-markups"&gt;&lt;h3 id="use-uix-components-with-org-mode-markups" class="cr-self-reference "&gt;Use uix components with org-mode markups&lt;/h3&gt;&lt;/a&gt;&lt;div id="text-use-uix-components-with-org-mode-markups" class="outline-text-3"&gt;&lt;div&gt;&lt;blockquote class="not-italic bg-stone-50 pl-4 py-2 border-l-3  my-4 border-sky-500"&gt;&lt;div class="not-italic"&gt;&lt;p&gt;
Hello
&lt;/p&gt;

&lt;/div&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content>
  </entry>
</feed>
