<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Between Two Parens</title>
  <subtitle>A blog about life between two parens.</subtitle>
  <link href="https://betweentwoparens.com/feed.xml" rel="self"/>
  <link href="https://betweentwoparens.com"/>
  <updated>2024-11-11T22:08:33Z</updated>
  <id>https://betweentwoparens.com</id>
  <author>
    <name>Thomas Mattacchione</name>
    <email>thomasmattacchione@gmail.com</email>
  </author>
  
  <entry>
    <title>Rich Comment Blocks</title>
    <link href="https://betweentwoparens.com/blog/rich-comment-blocks/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/rich-comment-blocks/</id>
    <content type="html">&lt;p&gt;The three main types of comments in Clojure are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/guides/weird_characters#_comment&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;comment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/guides/weird_characters#_discard&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;discard comment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojuredocs.org/clojure.core/comment&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;comment macro&lt;/a&gt; (&lt;code&gt;Rich Comment&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one, the &lt;code&gt;Rich Comment&lt;/code&gt;, is a pretty cool feature of Clojure.&lt;/p&gt;
&lt;h2 id=&quot;comment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#comment&quot;&gt;Comment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The first type of comment is a literal &lt;a href=&quot;https://clojure.org/guides/weird_characters#_comment&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;comment&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; I&#39;m a comment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Anything that follows the &lt;code&gt;;&lt;/code&gt; is ignored by Clojure until the end of the line.
A common use for a &lt;code&gt;comment&lt;/code&gt; is to add human readable documentation to your
code to help the people reading our code understand it&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#comments&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;comments-ref&quot;&gt;.&lt;/a&gt;
We can also comment out blocks of code which we don&#39;t want our program
to run.&lt;/p&gt;
&lt;h2 id=&quot;discard-comment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#discard-comment&quot;&gt;Discard Comment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The second type of comment is a &lt;a href=&quot;https://clojure.org/guides/weird_characters#_discard&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;discard comment&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; inc inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;; 8&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; inc &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;; 7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;#_&lt;/code&gt; will comment out the form directly behind it.  In the above, the code
commented out is the second &lt;code&gt;inc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I actually ignored this tool for an embarasignly long time, but it&#39;s wildly
useful and actually makes coding faster!&lt;/p&gt;
&lt;p&gt;At a high level, what makes the &lt;code&gt;discard&lt;/code&gt; comment great is that it doesn&#39;t
return a value, they nest and you can insert it into the middle of a line of
Clojure code and it only comments the form directly behind it.&lt;/p&gt;
&lt;p&gt;Additionally, if you&#39;re commenting out an entire block of code you only have
to add the &lt;code&gt;discard&lt;/code&gt; to the top level of the form and the entire form will be
commented.  This means the formatting of the code block won&#39;t be affected
and you have very little code to remove.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of nesting:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; you could discard each form in turn&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; or you could stack them&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here are some examples of where you might find the &lt;code&gt;discard comment&lt;/code&gt; useful:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;int?&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Thomas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;my-number &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ another-number &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token symbol&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Between Two Parens&quot;&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Thomas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The second take away is that you don&#39;t have to add spaces after the
&lt;code&gt;discard comment&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;;; these all produce the same result&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; space&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_inc &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;; no space&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_ inc inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; space&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_&lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;_inc inc inc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;; no space&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You may have noticed that I used &lt;code&gt;;;&lt;/code&gt; and &lt;code&gt;;&lt;/code&gt; in the above code block.
This is a common idiom when writing Clojure and is often used to denote a
hierarchy.  You can find more information about this convention in
&lt;a href=&quot;https://github.com/bbatsov/clojure-style-guide#comments&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;bbatsov&#39;s community clojure style guide&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The difference between adding the space or removing the space is which one
&lt;em&gt;you&lt;/em&gt; find more readable&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#discard-comment-credit&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;discard-comment-credit-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;rich-comment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#rich-comment&quot;&gt;Rich Comment&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, we have the &lt;code&gt;comment macro&lt;/code&gt; which is more affectionatley known as a
&lt;code&gt;Rich Comment Block&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;comment&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;; everything in here is ignored...returns nil&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first time I heard of a &lt;code&gt;Rich Comment&lt;/code&gt; was in Stuart Halloway&#39;s excellent
talk &lt;a href=&quot;https://youtu.be/Qx0-pViyIDU?t=1229&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Running With Scissors&lt;/a&gt; where he notes:&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&amp;quot;These comments are rich because they provide rich detail about the development
process and because they were written by a person named Rich.&amp;quot;&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Yet, even after watching &lt;code&gt;Running With Scissors&lt;/code&gt; the use of the &lt;code&gt;Rich Comment&lt;/code&gt;
hadn&#39;t started to click yet.  Two more things would need to happen:  The first,
I would witness REPL Driven Development used in person by &lt;a href=&quot;https://github.com/sponsors/swannodette&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;David Nolen&lt;/a&gt;.  The
second, I would start to use REPL Driven Development in my own workflow.  When
I did these things, I was able to better see the benefits of the &lt;code&gt;comment macro&lt;/code&gt;
as&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;documentation&lt;/li&gt;
&lt;li&gt;a save point&lt;/li&gt;
&lt;li&gt;code setup&lt;/li&gt;
&lt;li&gt;improved code exploration&lt;/li&gt;
&lt;li&gt;preservation of syntax highlighting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that, let&#39;s review a few examples of the &lt;code&gt;Rich Comment&lt;/code&gt; from real life
Clojure codebases&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#example-comments&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;example-comments-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first example illusrates the &lt;code&gt;documentation&lt;/code&gt; and &lt;code&gt;save point&lt;/code&gt; ideas.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;comment&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;println&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ls&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-l&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;println&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ls&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-l&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/no-such-thing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;println&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sed&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s/[aeiou]/oo/g&quot;&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello there&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;println&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;sed&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s/[aeiou]/oo/g&quot;&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;java.io.StringReader.&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello there&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;; ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above comes from the &lt;a href=&quot;https://github.com/clojure/clojure/blob/4ef4b1ed7a2e8bb0aaaacfb0942729252c2c3091/src/clj/clojure/java/shell.clj&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;clojure codebase&lt;/a&gt; itself and is a code example of
how to use &lt;a href=&quot;https://clojuredocs.org/clojure.java.shell/sh&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;sh&lt;/a&gt;.  For me, the value is that we have an example of how to use
&lt;code&gt;sh&lt;/code&gt; (&lt;code&gt;documentation&lt;/code&gt;) and we have some code ready for us to run through our
REPL (&lt;code&gt;a save point&lt;/code&gt;). This idea of having a &lt;code&gt;save point&lt;/code&gt; becomes more powerful
in the next example:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;comment&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt; &#39;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;my.app.db &lt;span class=&quot;token symbol&quot;&gt;:as&lt;/span&gt; app.db&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt; &#39;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;my.app.cart &lt;span class=&quot;token symbol&quot;&gt;:as&lt;/span&gt; cart&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;app.db/connection!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cart/add&lt;/span&gt; db &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:item-name&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;iPhone&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above builds on the idea of having a &lt;code&gt;save point&lt;/code&gt; and layers on some
&lt;code&gt;code setup&lt;/code&gt; helpers.  What the above does is add in a few lines of code
which, when run, will provide us with a &lt;code&gt;db connection&lt;/code&gt;. Through this, I can
quickly begin interacting with my app&#39;s database code and building out features.&lt;/p&gt;
&lt;p&gt;Of course, there are other types of setup code that you may want.  For example,
you might be working on a pure function which is just going to transform some
data.  In this case, we might setup a &lt;code&gt;comment&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;comment&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; xs &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:d&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:d&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:d&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:f&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; ys &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:e&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;token symbol&quot;&gt;:e&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:a&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:b&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token symbol&quot;&gt;:e&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;join&lt;/span&gt; xs ys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above is the &lt;a href=&quot;https://github.com/clojure/clojure/blob/4ef4b1ed7a2e8bb0aaaacfb0942729252c2c3091/src/clj/clojure/set.clj#L158&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;example Stuart provided&lt;/a&gt; in his talk which provides us with
some sample data allowing us to immediately begin using our functions to
transform said data.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These are just a few examples of how to use a &lt;code&gt;Rich Comment Block&lt;/code&gt;.  The most
interesting part of the &lt;code&gt;Rich Comment Block&lt;/code&gt; for me is that it&#39;s a tangible
example of the pragmatism of Clojure.  In this case, the &lt;code&gt;comment macro&lt;/code&gt; provides
an additional mechanism for speeding up my workflow and making our code more
maintainable overall because of the improved documentation and context we get
from these comments.&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;comments&quot;&gt;&lt;p&gt;Of course, there are arguments on both sides about how much to use comments.
As I see it, don&#39;t shy away from them in the pursuit of &amp;quot;self documenting code&amp;quot;
and also don&#39;t lean on them too heavily.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#comments-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;discard-comment-credit&quot;&gt;&lt;p&gt;Much love to &lt;a href=&quot;https://twitter.com/seancorfield&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Sean Corfield&lt;/a&gt; for pointing out nesting and the spacing points
for the discard comment.  Very cool!&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#discard-comment-credit-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;example-comments&quot;&gt;&lt;p&gt;Each example I provided in this post are really just my interpretations of how
they may be used.  The author may have had a different intent.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/rich-comment-blocks/#example-comments-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>What are the Clojure Tools?</title>
    <link href="https://betweentwoparens.com/blog/what-are-the-clojure-tools/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/what-are-the-clojure-tools/</id>
    <content type="html">&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Want to install the &lt;code&gt;Clojure CLI&lt;/code&gt;? Visit the &lt;a href=&quot;https://clojure.org/guides/getting_started&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Official Getting Started Guide&lt;/a&gt; or
watch &lt;a href=&quot;https://www.youtube.com/watch?v=5_q5pLoz9b0&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Installing Clojure on Mac&lt;/a&gt;.  Sorry Linux and Windows, friends.  I will
get to those videos in time!&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The &lt;code&gt;Clojure Tools&lt;/code&gt; are a group of convenience tools which currently consist of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Clojure CLI&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tools.build&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;Clojure Tools&lt;/code&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#cli-tool-v-dev-tools&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;cli-tool-v-dev-tools-ref&quot;&gt;.&lt;/a&gt;
were designed to answer some of the following questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do I &lt;strong&gt;install&lt;/strong&gt; Clojure? (&lt;code&gt;Clojure CLI&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How do I &lt;strong&gt;run&lt;/strong&gt; a Clojure program? (&lt;code&gt;Clojure CLI&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How do I &lt;strong&gt;manage&lt;/strong&gt; Clojure packages (dependencies)? (&lt;code&gt;Clojure CLI&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How do I &lt;strong&gt;configure&lt;/strong&gt; a Clojure project? (&lt;code&gt;Clojure CLI&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How do I &lt;strong&gt;build&lt;/strong&gt; Clojure for production? (&lt;code&gt;tools.build&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rest of this post will dig into each of these tools.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The alternatives to &lt;code&gt;Clojure CLI&lt;/code&gt; are &lt;a href=&quot;https://leiningen.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;lein&lt;/a&gt; and &lt;a href=&quot;https://boot-clj.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;boot&lt;/a&gt;. We&#39;ll chat about these
later.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;clojure-cli&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#clojure-cli&quot;&gt;Clojure CLI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Clojure CLI&lt;/code&gt; is a CLI program. Here is what it looks like to use the
&lt;code&gt;Clojure CLI&lt;/code&gt; and some of the things it can do:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Run&lt;/strong&gt; a Clojure repl&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Run&lt;/strong&gt; a Clojure program&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; your-clojure-program
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;manage&lt;/strong&gt; Clojure dependencies&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-Sdeps&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;{:deps {bidi/bidi {:mvn/version &quot;2.1.6&quot;}}}&#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Like all &lt;code&gt;Clojure&lt;/code&gt; programs, the &lt;code&gt;Clojure CLI&lt;/code&gt; is built on a few libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clojure/brew-install&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;clj/clojure&lt;/a&gt; - a bash script&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clojure/tools.deps&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;tools.deps&lt;/a&gt; a clojure library (commonly referred to as &lt;code&gt;deps&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.clojure.org/guides/deps_and_cli&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;deps.edn&lt;/a&gt; - an &lt;a href=&quot;https://github.com/edn-format/edn&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;edn&lt;/a&gt; file with a specific structure&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following sections will provide overviews of each of the above tools.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Clojure CLI&lt;/code&gt; is invoked by calling either &lt;code&gt;clj&lt;/code&gt; or &lt;code&gt;clojure&lt;/code&gt; shell commands:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# clj&lt;/span&gt;
clj &lt;span class=&quot;token parameter variable&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; your-clojure-program

&lt;span class=&quot;token comment&quot;&gt;# clojure&lt;/span&gt;
clojure &lt;span class=&quot;token parameter variable&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; your-clojure-program
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Under the hood, &lt;code&gt;clj&lt;/code&gt; actually calls &lt;code&gt;clojure&lt;/code&gt;.  The difference is that &lt;code&gt;clj&lt;/code&gt;
wraps the &lt;code&gt;clojure&lt;/code&gt; command with a tool called &lt;a href=&quot;https://linux.die.net/man/1/rlwraps&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;rlwrap&lt;/a&gt;. &lt;code&gt;rlwrap&lt;/code&gt;
improves the developer experience by making it easier for you, a human, to type
in the terminal while you&#39;re running your Clojure REPL.  However, even though
it&#39;s easier for you to type, &lt;code&gt;rlwrap&lt;/code&gt; &lt;em&gt;can&lt;/em&gt; make it hard to compose the &lt;code&gt;clj&lt;/code&gt;
command with other tools.  As a result, it&#39;s a common practice to use &lt;code&gt;clojure&lt;/code&gt;
in production/ci environments &lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#when-to-use-clojure-script&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;when-to-use-clojure-script-ref&quot;&gt;.&lt;/a&gt;
Additionally, not all environments have access to &lt;code&gt;rlwrap&lt;/code&gt; so it&#39;s another
dependency you have to install.&lt;/p&gt;
&lt;p&gt;Okay, so they do the same thing.  What do they do?  &lt;code&gt;clj/clojure&lt;/code&gt; has one job:
run Clojure programs against a classpath.&lt;/p&gt;
&lt;p&gt;The next sections will outline the tools that make up the &lt;code&gt;Clojure CLI&lt;/code&gt; tool.&lt;/p&gt;
&lt;h3 id=&quot;clj%2Fclojure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#clj%2Fclojure&quot;&gt;clj/clojure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you dig into the &lt;code&gt;clj/clojure&lt;/code&gt; is just a bash script which ultimatley calls
a command like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;java&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;java-opt*&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-cp&lt;/span&gt; classpath clojure.main &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;init-opt*&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;main-opt&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;arg*&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thus, the &lt;code&gt;Clojure CLI&lt;/code&gt; tool makes it easier to run Clojure programs.  It saves
you having to type out a gnarly &lt;code&gt;Java&lt;/code&gt; command and make it work on different
environments (windows, linux, mac etc).  However, it orchestrates the building
of the classpath by calling out to &lt;code&gt;tools.deps&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;tools.deps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#tools.deps&quot;&gt;tools.deps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;tools.deps&lt;/code&gt; is a Clojure libary responsible for managing your dependencies.
It does the following things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reads in dependencies from a &lt;code&gt;deps.edn&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;resolves the dependencies and their transitive dependencies&lt;/li&gt;
&lt;li&gt;builds a classpath&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&#39;s interesting about this program is that it&#39;s just a Clojure library.
This means that you can use it outside of the &lt;code&gt;Clojure CLI&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The other thing that makes &lt;code&gt;tools.deps&lt;/code&gt; great is that it&#39;s a small and
focused library.  Why this is great is that if something goes wrong it&#39;s easy
to read and learn the library in a short period of time.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;if you&#39;re of the
opinion that you shouldn&#39;t have to know implementation details of the tools you
use, well, welcome to professional software development.  It doesn&#39;t matter what
language or tool you use, you will run across outdated docs, bugs or undefined
behaviour.  You could choose to wait for someone to save you, or solve the
problem yourself.  This is where small, well designed and focused libraries
win out over &amp;quot;battery included&amp;quot; solutions.  To learn more about the history,
development and goals of the tool from the Clojure team I recommend listening
to this episode of &lt;a href=&quot;https://soundcloud.com/user-959992602&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clojure Weekly Podcast&lt;/a&gt; which features Alex Miller,
the author of &lt;code&gt;tools.deps&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;deps.edn&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#deps.edn&quot;&gt;deps.edn&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;deps.edn&lt;/code&gt; is just an &lt;a href=&quot;https://github.com/edn-format/edn&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;edn&lt;/a&gt; file where you configure your project and specify
project dependencies. You can think of it like Clojure&#39;s version of
&lt;code&gt;package.json&lt;/code&gt;.  The &lt;code&gt;deps.edn&lt;/code&gt; file is a Clojure map
with a specific structure.  Here&#39;s an example of some of the properties of
a &lt;code&gt;deps.edn&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
 &lt;span class=&quot;token symbol&quot;&gt;:aliases&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;...&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, we use the keywords &lt;code&gt;:deps&lt;/code&gt;, &lt;code&gt;:paths&lt;/code&gt; and &lt;code&gt;:aliases&lt;/code&gt; and more
to start to describe your project and the dependencies it requires.&lt;/p&gt;
&lt;p&gt;As we noted above, &lt;code&gt;deps.edn&lt;/code&gt; is read in when you run &lt;code&gt;clj/clojure&lt;/code&gt; and tells &lt;code&gt;clj/clojure&lt;/code&gt;
which dependencies are requires to run your project.&lt;/p&gt;
&lt;h2 id=&quot;tools.build&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#tools.build&quot;&gt;Tools.Build&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tools.build&lt;/code&gt; is a Clojure library with functions for building clojure projects.
For example, build a &lt;code&gt;jar&lt;/code&gt; or &lt;code&gt;uberjar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The way you would use &lt;code&gt;tools.build&lt;/code&gt; is by writing a separate program inside
your app which knows how to build your app.  The convention is to create a
&lt;code&gt;build.clj&lt;/code&gt; file in the root of your project.  Import &lt;code&gt;tools.build&lt;/code&gt; and use
the functions provides by &lt;code&gt;tools.build&lt;/code&gt; to build your program.&lt;/p&gt;
&lt;p&gt;The 3 main types of Clojure programs one might build into 3 sub categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;tool&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;library&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;app&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When you run your &lt;code&gt;build.clj&lt;/code&gt; file, you will use &lt;code&gt;Clojure CLI&lt;/code&gt;&#39;s &lt;code&gt;-T&lt;/code&gt; switch.
The &lt;code&gt;-T&lt;/code&gt; switch is meant to run general clojure programs via the &lt;code&gt;Clojure CLI&lt;/code&gt;
and since &lt;code&gt;build.clj&lt;/code&gt; is a separate program, distinct form the app you are
writing, you would run it via the &lt;code&gt;-T&lt;/code&gt; switch.&lt;/p&gt;
&lt;p&gt;You would use &lt;code&gt;-T&lt;/code&gt; for Clojure programs that you want to run as a &amp;quot;tool&amp;quot;.  For
example, &lt;a href=&quot;https://github.com/seancorfield/deps-new&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;deps-new&lt;/a&gt; is a Clojure library which creates new Clojure projects
based on a template you provide.  This is a great example of a Clojure project
which is built to be a &amp;quot;tool&amp;quot;.&lt;/p&gt;
&lt;p&gt;I don&#39;t want to go into more detail about &lt;code&gt;-T&lt;/code&gt; now because that means we would
have to dive into other &lt;code&gt;Clojure CLI&lt;/code&gt; switches like &lt;code&gt;-X&lt;/code&gt; and &lt;code&gt;-M&lt;/code&gt;.  That&#39;s for
another post. On to the Installer!&lt;/p&gt;
&lt;h2 id=&quot;installer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#installer&quot;&gt;Installer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &amp;quot;Clojure CLI Installer&amp;quot; is a fancy way of referring to the &lt;code&gt;brew tap&lt;/code&gt; used
to install Clojure on mac and linux machines. As of February 2020, Clojure
started maintaining their own &lt;a href=&quot;https://clojure.org/news/2020/02/28/clojure-tap&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;brew tap&lt;/a&gt;.  Thus, if you installed the
&lt;code&gt;Clojure CLI&lt;/code&gt; via&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; clojure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;you will likely want to uninstall &lt;code&gt;clojure&lt;/code&gt; and install the following:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; clojure/tools/clojure
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In all likelihood, you would probably be fine with &lt;code&gt;brew install clojure&lt;/code&gt; as it
will recieve updates.  However, while &lt;code&gt;brew install clojure&lt;/code&gt; will still see some
love, it won&#39;t be as active as the &lt;code&gt;clojure/tools/clojure&lt;/code&gt; tap.&lt;/p&gt;
&lt;h2 id=&quot;clj-v-lein-v-boot&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#clj-v-lein-v-boot&quot;&gt;clj v lein v boot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section will provide a quick comparison of &lt;code&gt;clj&lt;/code&gt;, &lt;code&gt;lein&lt;/code&gt; and &lt;code&gt;boot&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;I won&#39;t dive into the history, for this I recommend the blog post &lt;a href=&quot;https://corfield.org/blog/2018/04/18/all-the-paths/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;All the Paths&lt;/a&gt;
by Sean Corfield.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Firstly, all of the above tools are more or less addressing the same problems
in their own way.  Your job is to choose the one you like best.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Understanding that you have to choose one should be a relief, but note that some
people have experimented
with combining these tools.  Specifically, combining &lt;code&gt;Clojure CLI&lt;/code&gt; and &lt;code&gt;lein&lt;/code&gt;.
Here is an example of &lt;a href=&quot;https://github.com/oakes/full-stack-clj-example&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;clj calling to lein&lt;/a&gt;.  This was desireable years ago
because the &lt;code&gt;Clojure CLI&lt;/code&gt; didn&#39;t cover building CLJ artifacts.  Having
said this, there isn&#39;t a need to do this anymore because you have libraries like
&lt;a href=&quot;https://github.com/seancorfield/depstar&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;depstar&lt;/a&gt; which handle the &amp;quot;build&amp;quot; story.  In addition, you have &lt;code&gt;tools.build&lt;/code&gt;
which is Clojure&#39;s official answer to the build question.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;If you&#39;re curious which to choose, my answer is the &lt;code&gt;Clojure CLI&lt;/code&gt;.
The reason I like the &lt;code&gt;Clojure CLI&lt;/code&gt; is because the tool is simple.
You can read through &lt;code&gt;clj&lt;/code&gt; and &lt;code&gt;tools.deps&lt;/code&gt; in an afternoon and understand
what they are doing.  The same (subjectively of course) cannot be
said for &lt;code&gt;lein&lt;/code&gt; or &lt;code&gt;boot&lt;/code&gt;.  I will note that &lt;code&gt;Clojure CLI&lt;/code&gt;&#39;s API is not
straightforward and can be confusing.&lt;/p&gt;
&lt;p&gt;Secondly, the &lt;code&gt;Clojure Tools&lt;/code&gt; promote libraries over frameworks.  This is
important when working with a language like Clojure because it really does
reward you for breaking down your thinking.&lt;/p&gt;
&lt;p&gt;Finally, the Clojure community is really leaning into
building tools for &lt;code&gt;Clojure CLI&lt;/code&gt;.  For example, where &lt;code&gt;lein&lt;/code&gt; used to have significantly
more functionality, the community has built a ton of &lt;a href=&quot;https://github.com/clojure/tools.deps.alpha/wiki/Tools&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;incredible tools&lt;/a&gt; that
will cover many of your essential requirements.&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;cli-tool-v-dev-tools&quot;&gt;&lt;p&gt;In earlier versions of this blog post I referred to the &lt;code&gt;Clojure CLI&lt;/code&gt; as
&lt;code&gt;Clojure Tools&lt;/code&gt;.  The reason I now refer to them as the &amp;quot;Clojure CLI&amp;quot; is
because on August 21, 2020 it was announced in Clojurians (The official Clojure Slack Org)
that cognitect released a free set of tools called &lt;a href=&quot;https://cognitect.com/dev-tools/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Cognitect Dev Tools&lt;/a&gt;.
Thus, I made the change to be very clear that there is a difference.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#cli-tool-v-dev-tools-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;when-to-use-clojure-script&quot;&gt;&lt;p&gt;Of course, production scripts are not the only times you would want to use the
&lt;code&gt;clojure&lt;/code&gt; command.  Other times include when you are combining it with other tools
e.g. emacs.  In general, if you are finding the &lt;code&gt;clj&lt;/code&gt; command is causing some
headaches when composing tools, give &lt;code&gt;clojure&lt;/code&gt; a try.  Thanks, sogaiu for the tip!&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#when-to-use-clojure-script-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;monorepo-comment&quot;&gt;&lt;p&gt;To clarify the &amp;quot;monorepo&amp;quot; comment: Choosing a sane structure for your monorepo
is important to making this work.  I have a personal project which has 4 or 5
sub-projects and I have not run into any issues as of yet.  I would eventually
love to write about my approach, but until then checkout Sean Corfield&#39;s Blog
Post about &lt;a href=&quot;https://corfield.org/blog/2021/02/23/deps-edn-monorepo/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clojure Monorepo using Clojure CLI Tools&lt;/a&gt;.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/#monorepo-comment-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>Manage your Java JDKs</title>
    <link href="https://betweentwoparens.com/blog/jenv/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/jenv/</id>
    <content type="html">&lt;p&gt;Pro tip for anyone working with &lt;em&gt;any&lt;/em&gt; programming language: Find a clean and easy
way to switch versions of your programming language of choice.&lt;/p&gt;
&lt;p&gt;All it takes is a &lt;a href=&quot;https://www.thoughtworks.com/continuous-integration&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CI&lt;/a&gt; environment running a different version of your
programming language and the world goes Pete Tong.&lt;/p&gt;
&lt;p&gt;My approach is to use a language version manager.  If you&#39;re using JavaScript,
&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;nvm&lt;/a&gt; is a great option, Ruby has &lt;a href=&quot;https://rvm.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;rvm&lt;/a&gt; and for Clojure developers we have
&lt;a href=&quot;https://github.com/clojure/tools.deps.alpha&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;tools.deps&lt;/a&gt; for managing versions of Clojure and &lt;a href=&quot;https://www.jenv.be/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;jEnv&lt;/a&gt; for managing our JDKs.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Some languages, Clojure included, don&#39;t need a tool for this.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;why-version-management-tools&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#why-version-management-tools&quot;&gt;Why Version Management Tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Version management tools allow us to quickly and easily manage (add, switch,
remove et al.) the version of our programming languages. This enables us to
easily test our code against different languages.  Example scenarios where I&#39;ve
had to switch language versions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Debugging CI environments&lt;/li&gt;
&lt;li&gt;Resolving &amp;quot;works on my machine&amp;quot; issues&lt;/li&gt;
&lt;li&gt;Regression testing an app or library against an older version of a language&lt;/li&gt;
&lt;li&gt;Switching between multiple projects with different language version requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The need to do this exists with all programming languages.  Some languages
are easier to do this with than others.  For example, with Clojure you don&#39;t
need a tool, you just use &lt;a href=&quot;https://github.com/clojure/tools.deps.alpha&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;tools.deps&lt;/a&gt; to specify the version of the language
you want to use.  With Java, it&#39;s more complicated so I use a tool called &lt;code&gt;jEnv&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jEnv&lt;/code&gt; is a tool that allows you to manage your Java JDK installations.  It
you switch between versions of the JDK.  One thing to note is that this tool
does not allow you to install a JDK.  You have to do this separatley.  Further,
while it&#39;s straightforward to setup &lt;code&gt;jEnv&lt;/code&gt;, there are some gotchas
which is why i&#39;m writing this guide.&lt;/p&gt;
&lt;h2 id=&quot;install-jenv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#install-jenv&quot;&gt;Install jEnv&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Please note that at the time of this writing I have two versions of the JDK
installed right now: &lt;strong&gt;AdoptOpenJDK 11&lt;/strong&gt; and &lt;strong&gt;AdoptOpenJDK 13&lt;/strong&gt;.  I&#39;m also
running MacOS 10.15.2.  If you are using a different OS please head over to
&lt;a href=&quot;https://www.jenv.be/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;The official jEnv guide&lt;/a&gt; to see how to install &lt;code&gt;jEnv&lt;/code&gt; on linux.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The first thing we have to do is install &lt;code&gt;jEnv&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; jenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above is actually the only step that is different for linux.  So macos and
linux users can follow everything that comes next together&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;and now let&#39;s do a sanity check to see if it&#39;s installed correctly.  Run:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;jenv doctor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and if the above worked you should see something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Java binary &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; path is not &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; the jenv shims.
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Please check your path, or try using /path/to/java/home &lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Jenv is not loaded &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; your &lt;span class=&quot;token function&quot;&gt;zsh&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	To fix &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;jenv init -&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; /Users/&lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Note that the above output is truncated because I&#39;m choosing to focus on what
I consider the important details.  Further, the pieces I truncated may be
specific to my machine.  For example, i&#39;m using &lt;code&gt;zsh&lt;/code&gt;.  If you&#39;re using &lt;code&gt;bash&lt;/code&gt;,
then your output on line 3 will read &lt;code&gt;bash&lt;/code&gt;.  Everything truncated is
identified with &lt;code&gt;# ...&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;configure-jenv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#configure-jenv&quot;&gt;Configure jEnv&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Assuming the above worked, we can now configure &lt;code&gt;jEnv&lt;/code&gt;.  The next step is to
add &lt;code&gt;jEnv&lt;/code&gt; to our &lt;code&gt;PATH&lt;/code&gt; by updating our configuration file.&lt;/p&gt;
&lt;p&gt;To do this, you need to know which &lt;code&gt;shell&lt;/code&gt; you&#39;re running.  Type the following
into your terminal to figure out the &lt;code&gt;shell&lt;/code&gt; you&#39;re running:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you are using &lt;code&gt;bash&lt;/code&gt;, the above will print out &lt;code&gt;-bash&lt;/code&gt; and if you&#39;re using
&lt;code&gt;zsh&lt;/code&gt; the above will print out &lt;code&gt;-zsh&lt;/code&gt;.  Once you discover which &lt;code&gt;shell&lt;/code&gt; you are
using, please choose the associated code block below and run the code inside of
it line by line:&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You only have to run the code from &lt;strong&gt;one&lt;/strong&gt; of the following blocks&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;&lt;strong&gt;zsh shell&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;export PATH=&quot;$HOME/.jenv/bin:$PATH&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.zshrc
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;eval &quot;$(jenv init -)&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;bash shell&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;export PATH=&quot;$HOME/.jenv/bin:$PATH&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.bashrc
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;eval &quot;$(jenv init -)&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can once again run a sanity check:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;jenv doctor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Which will return something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	No JAVA_HOME &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Java binary &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; path is not &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; the jenv shims.
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Please check your path, or try using /path/to/java/home &lt;span class=&quot;token comment&quot;&gt;#...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Jenv is correctly loaded
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see, we now have two less errors.  We&#39;re making progress!  From here, we want to run the following:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;jenv enable-plugin &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token environment constant&quot;&gt;$SHELL&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and now running &lt;code&gt;jenv doctor&lt;/code&gt; returns this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	JAVA_HOME variable probably &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; by jenv PROMPT
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Java binary &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; path is not &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; the jenv shims.
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ERROR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Please check your path, or try using /path/to/java/home &lt;span class=&quot;token comment&quot;&gt;#...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;OK&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;	Jenv is correctly loaded
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point, &lt;code&gt;jEnv&lt;/code&gt; is setup and the last item on our list is to install a
Java JDK.  If you don&#39;t have one installed checkout &lt;a href=&quot;https://adoptium.net/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Adoptium&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;add-a-jdk-to-jenv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#add-a-jdk-to-jenv&quot;&gt;Add a JDK to jEnv&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not sure if you have a Java JDK installed?  No worries, we&#39;ll find out
together!&lt;/p&gt;
&lt;p&gt;Run the following command in your terminal to see which Java JDKs we have installed.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;/usr/libexec/java_home &lt;span class=&quot;token parameter variable&quot;&gt;-V&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Note that the &lt;code&gt;V&lt;/code&gt; above is uppercase.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;and that will print something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;Matching Java Virtual Machines &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;:
    &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Eclipse Adoptium&quot;&lt;/span&gt; - &lt;span class=&quot;token string&quot;&gt;&quot;OpenJDK 21.0.3&quot;&lt;/span&gt; /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
    &lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt;.11 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Eclipse Adoptium&quot;&lt;/span&gt; - &lt;span class=&quot;token string&quot;&gt;&quot;OpenJDK 17.0.11&quot;&lt;/span&gt; /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you see something like the above, it means you have at least one Java JDK
installed and you can continue on with this section.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Also note that the above is specific to me.  So while you may have JDk&#39;s installed, they may be different distributions and versions compared to mine.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Now we can go ahead and add JDK&#39;s to &lt;code&gt;jEnv&lt;/code&gt; so it can manage them for us.  Run the following command&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;jenv &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Again, the path you use might be different.  The trick to finding the path you need to provide &lt;code&gt;jenv add&lt;/code&gt; is to use the path after each JDK name.  e.g. &lt;code&gt;&amp;quot;AdoptOpenJDK 13&amp;quot;&lt;/code&gt; is followed by a path.  Copy that and provide it to the &lt;code&gt;jenv add&lt;/code&gt; command.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;When you run the above, you will see something like this returned:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;temurin64-21.0.3 added
&lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3 added
&lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt; added
&lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt; added
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As a sanity check, we can run &lt;code&gt;jenv versions&lt;/code&gt; to see if &lt;code&gt;jEnv&lt;/code&gt; knows about our JDK:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;* system &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;set by /Users/username/.jenv/version&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3
  temurin64-21.0.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Great, but remember how I have two JDK&#39;s installed?  The above indicates that
only one of them is being managed by &lt;code&gt;jEnv&lt;/code&gt;.  This means I have to run through
the above step again to have &lt;code&gt;jEnv&lt;/code&gt; know about the other version of the JDK I
have installed.  So, let&#39;s repeat those steps:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;jenv &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;again we get our success output&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;temurin64-17.0.11 added
&lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt;.11 added
&lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt; added
&lt;span class=&quot;token number&quot;&gt;17&lt;/span&gt; added
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and when we check versions available now by running &lt;code&gt;jenv versions&lt;/code&gt; we have both 11 and 13 available to us:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;* system &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;set by /Users/username/.jenv/version&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;17&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;17.0&lt;/span&gt;.11
  &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;
  &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3
  temurin64-17.0.11
  temurin64-21.0.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&lt;code&gt;username&lt;/code&gt; in the &lt;code&gt;system&lt;/code&gt; path is my actual username, but I changed it here
to avoid confusion&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;set-a-jdk-version-via-jenv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#set-a-jdk-version-via-jenv&quot;&gt;Set a JDK version via jEnv&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As a final step, we want to actualy set a JDK to be the one we use.  You have two options for this: &lt;code&gt;jenv local&lt;/code&gt; and &lt;code&gt;jenv global&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;jenv local&lt;/code&gt; is going to set your JDK of choice for your current terminal session.  &lt;code&gt;jenv global&lt;/code&gt; is going to set your chosen JDK as the default for all terminal sessions.  For now, let&#39;s set a global version.  In my case, i&#39;m going to set my &lt;code&gt;jenv global&lt;/code&gt; to &lt;code&gt;AdoptOpenJDK 11&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;jenv global &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, in order for the above to take effect, we have to open a new terminal window.  Once you open a new terminal window run the following command to be sure our specified version of Java was set:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;java&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and you should see something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;openjdk &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3 &lt;span class=&quot;token number&quot;&gt;2024&lt;/span&gt;-04-16 LTS
OpenJDK Runtime Environment Temurin-21.0.3+9 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;build &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3+9-LTS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
OpenJDK &lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;-Bit Server VM Temurin-21.0.3+9 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;build &lt;span class=&quot;token number&quot;&gt;21.0&lt;/span&gt;.3+9-LTS, mixed mode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&#39;s  everything involved in setting a &lt;code&gt;global&lt;/code&gt; version of JDK through &lt;code&gt;jEnv&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;uninstalling-jenv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/jenv/#uninstalling-jenv&quot;&gt;Uninstalling Jenv&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If for any reason you feel like something went wrong while installing &lt;code&gt;jenv&lt;/code&gt;, or maybe you just don&#39;t like &lt;code&gt;jEnv&lt;/code&gt; and you want to cleanup your environment the following steps will help you remove it.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;brew uninstall jenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remove the &lt;code&gt;.jenv&lt;/code&gt; directory&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; ~/.jenv
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;remove the &lt;code&gt;PATH&lt;/code&gt; and init script we added to our shell (either &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;That&#39;s everything involved in setting up and working with Jenv.  I hoped this helped.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Reagent &amp; Hiccup</title>
    <link href="https://betweentwoparens.com/blog/reagent-and-hiccup/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/reagent-and-hiccup/</id>
    <content type="html">&lt;p&gt;I&#39;m writing this post because &lt;code&gt;hiccup&lt;/code&gt; in the context of Reagent
confused me and I wanted to work through some of the confusion.&lt;/p&gt;
&lt;p&gt;Things that confused me: I apparently don&#39;t need to import a library,
modify my build tools or do anything and I just get to write &lt;code&gt;hiccup&lt;/code&gt; for free?
How is this possible? Also, what is &lt;code&gt;hiccup&lt;/code&gt; and is it the same everywhere?&lt;/p&gt;
&lt;p&gt;In React (JavaScript) you primarily write your HTML markup with &lt;a href=&quot;https://react.dev/learn/writing-markup-with-jsx&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;JSX&lt;/a&gt;.  In
Reagent (a ClojureScript wrapper around React) we write our HTML markup with
something called &lt;code&gt;hiccup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here is a React &lt;a href=&quot;https://reactjs.org/docs/hello-world.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;hello world&lt;/a&gt; written in JS uxing &lt;code&gt;jsx&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-js&quot;&gt;&lt;code class=&quot;bride-code-js&quot;&gt;ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; world&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- JSX&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is the same React hello world written in Reagent using hiccup:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.dom/render&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; &amp;lt;-- Hiccup&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&#39;s pull the &lt;code&gt;JSX&lt;/code&gt; and &lt;code&gt;hiccup&lt;/code&gt; out so we can see them clearly:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-js&quot;&gt;&lt;code class=&quot;bride-code-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// JSX&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1 className&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; world&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;


&lt;span class=&quot;token comment&quot;&gt;// hiccup&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;h1 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&lt;code&gt;reagent.dom/render&lt;/code&gt; is Reagent&#39;s wrapper around &lt;code&gt;ReactDOM.render&lt;/code&gt;.  This was
introduced in version &lt;code&gt;0.10.0&lt;/code&gt; of &lt;code&gt;Reagent&lt;/code&gt;.  I also want to note that there
are many implementations of &lt;code&gt;hiccup&lt;/code&gt;.  Some run on the server and some run in
the browser and some can be run in both places.  Hiccup is actually very simple
to implement.  The result is you have several implementations which were built
for different purposes.  I will cover these at the end of this post.  The majority
of this post is covering &lt;code&gt;reagent hiccup&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;For fun, here is some more hiccup:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:ul&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;list&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;list-item&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Item 1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;list-item&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Item 2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:li&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;list-item&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Item 3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The rest of this post is going to dig into the questions asked in the
introductory paragraph.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;This post is geared toward beginner and intermediate ClojureScript developers
who want to understand a little more about how &lt;code&gt;Reagent Hiccup&lt;/code&gt; works.  As a
result, we won&#39;t cover how to write Hiccup, but if that&#39;s your goal, please see
this &lt;a href=&quot;https://purelyfunctional.tv/guide/reagent/#hiccup&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Guide to Writing Hiccup&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;reagent-hiccup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#reagent-hiccup&quot;&gt;Reagent Hiccup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s return to the original reagent code snippet we started with:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.dom/render&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; &amp;lt;-- hiccup&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On &lt;strong&gt;line 2&lt;/strong&gt; we have a Clojure vector.  Don&#39;t overthink it.  It&#39;s just a
vector.  However, because of the order and type of the arguments, it becomes
&lt;code&gt;hiccup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To be considered valid &lt;code&gt;Reagent Hiccup&lt;/code&gt;, the vector you pass to Reagent needs
to take on one of the following shapes:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; =&gt; [:h1]&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag attributes&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; =&gt; [:h1 {:class &quot;welcome&quot;}]&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag children&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; =&gt; [:h1 &quot;Hello world!&quot;]&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tag attributes children&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; =&gt; [:h1 {:class &quot;welcome&quot;} &quot;Hello world!&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is another way to break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;tag&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A keyword (&lt;code&gt;:h1&lt;/code&gt;) or symbol (&lt;code&gt;hi&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;attributes&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A map &lt;code&gt;{:class &amp;quot;welcome&amp;quot;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;children&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A string (&lt;code&gt;&amp;quot;Hello world!&amp;quot;&lt;/code&gt;), vector (&lt;code&gt;[:p &amp;quot;hi&amp;quot;]&lt;/code&gt;) or symbol (&lt;code&gt;hi&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above are the main flavours, but there are more ways to do things.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;How does Reagent know what do with &lt;code&gt;hiccup&lt;/code&gt;?  The &lt;code&gt;reagent.dom/render&lt;/code&gt; accepts
either &lt;code&gt;Reagent Hiccup&lt;/code&gt; or a &lt;code&gt;React Element&lt;/code&gt; as the first argument.  So by
providing a &lt;code&gt;vector&lt;/code&gt;, Reagent automatically treats it like &lt;code&gt;Reagent Hiccup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thus, if we were to pass something that&#39;s not actually &lt;code&gt;Reagent Hiccup&lt;/code&gt;,
Reagent is kind enough to throw a JavaScript assertion error in the browser
console letting us know what went wrong.&lt;/p&gt;
&lt;p&gt;Okay, so Reagent can just accept &lt;code&gt;hiccup&lt;/code&gt;.  How does Reagent understand Hiccup
and know what to do with it?  We didn&#39;t import a library or add a plugin to
our build tools?&lt;/p&gt;
&lt;p&gt;The answer is that Reagent comes with a Hiccup compiler built-in which converts
Reagent&#39;s &lt;code&gt;hiccup&lt;/code&gt; to &lt;code&gt;React Elements&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;reagent-hiccup-to-react-element&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#reagent-hiccup-to-react-element&quot;&gt;Reagent Hiccup to React Element&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The process begins by Reagent passing the &lt;code&gt;component&lt;/code&gt; given to &lt;code&gt;reagent.dom/render&lt;/code&gt;
to a function called &lt;code&gt;create-class&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;create-class&lt;/code&gt; has &lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;other jobs&lt;/a&gt; aside from handling Hiccup, but
one of it&#39;s jobs is to compile &lt;code&gt;Reagent Hiccup&lt;/code&gt; to &lt;code&gt;React.createElement&lt;/code&gt; calls.
This step is handled by the &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/88e9833be9c3135548d760286ffd84d88a0a0489/src/reagent/impl/template.cljs#L382&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;as-element&lt;/a&gt; function.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as-element&lt;/code&gt; accepts &lt;code&gt;Reagent Hiccup&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compiles it to &lt;code&gt;React.createElement&lt;/code&gt; function calls like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;h1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;welcome&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above is given to React which actually runs the &lt;code&gt;React.createElement&lt;/code&gt; calls
turning them into &lt;code&gt;React Elements&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;h1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;greeting&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which ultimatley gets turned into HTML&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-html&quot;&gt;&lt;code class=&quot;bride-code-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello, world!&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Understanding that everything is turned into &lt;code&gt;React.createElement&lt;/code&gt; calls you might be asking, &lt;em&gt;&amp;quot;Could we just use React.createElement and not use Reagent Hiccup?&amp;quot;&lt;/em&gt;.  The answer? Yup!&lt;/p&gt;
&lt;h2 id=&quot;reagent-without-hiccup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#reagent-without-hiccup&quot;&gt;Reagent Without Hiccup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Similar to React and JSX, you can use plain old &lt;code&gt;React.createElement&lt;/code&gt; to create &lt;code&gt;Reagent Components&lt;/code&gt;.  For example, where we wrote the original example as:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.dom/render&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;we could also use &lt;code&gt;reagent.core/create-element&lt;/code&gt; to write a &lt;code&gt;Reagent component&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.dom/render&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.core/create-element&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;h1&quot;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;js&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:className&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thus, the following are equivalent&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; hiccup&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; reagent function&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reagent.core/create-element&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;h1&quot;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;#&lt;/span&gt;js&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:className&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;welcome&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;Hello, world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&lt;code&gt;reagent.core/create-element&lt;/code&gt; is a Reagent helper function which wraps &lt;code&gt;React.createElement&lt;/code&gt;.  It&#39;s the equivalent of calling &lt;code&gt;React.createElement&lt;/code&gt;, but &lt;code&gt;reagent.core/create-element&lt;/code&gt; provides a &amp;quot;natural&amp;quot; way to write &lt;code&gt;React.createElement&lt;/code&gt; in Clojure and also provides a few conveniences.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Understanding this, are there any reasons to use &lt;code&gt;reagent.core/create-element&lt;/code&gt;
over &lt;code&gt;Reagent Hiccup&lt;/code&gt;?&lt;/p&gt;
&lt;h3 id=&quot;why-reagent-hiccup%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#why-reagent-hiccup%3F&quot;&gt;Why Reagent Hiccup?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;From a technical perspective, you can argue that there is less work being done
if you don&#39;t use hiccup because you don&#39;t have to convert &lt;code&gt;hiccup&lt;/code&gt; to &lt;code&gt;createElement&lt;/code&gt;
calls.  However, i&#39;m not sure this optimization would be worth it. Especially
because you could just change the implementation of hiccup to be run at compile
time and see the performance improvements and still have the advantage of
writing your components in &lt;code&gt;hiccup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From a developer experience perspective, you might suggest that using
&lt;code&gt;reagent.core/create-element&lt;/code&gt; over &lt;code&gt;hiccup&lt;/code&gt; initially feels easier to teach
new developers how to create components in React/Reagent.  However, this is
subjective and I could argue that &lt;code&gt;hiccup&lt;/code&gt; is far friendlier and because of its
uniquity is a better tool to rely on.&lt;/p&gt;
&lt;p&gt;Some more reasons we use Hiccup in Reagent is similar to the reasons for using
JSX in React.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separation of concerns: Separate by component vs. technology&lt;/li&gt;
&lt;li&gt;Accessibility: easier to read and write than &lt;code&gt;React.createElement&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Expressivity: it&#39;s a Clojure data structure, so we have the full power of Clojure&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above is a summary of the design goals of the React team when they introduced JSX.  What I have done is adapted the rationale for Clojure.  For more information, I encourage you to watch &lt;a href=&quot;https://www.youtube.com/watch?v=x7cQ3mrcKaY&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;React: Rethinking Best Practices&lt;/a&gt;.  Note that this talk is for React, but the design principles are still valid and applicable to Clojure&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The second point, &lt;em&gt;Accessibility&lt;/em&gt;, is particularly interesting.  One of the things I mean by this is that because Hiccup is a popular DSL in Clojure land, and not specific to &lt;code&gt;Reagent&lt;/code&gt;, it can be quickly be adopted by developers already familiar with Hiccup.&lt;/p&gt;
&lt;h2 id=&quot;hiccup-and-clojure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#hiccup-and-clojure&quot;&gt;Hiccup and Clojure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I mentioned at the top, there are many flavours of &lt;code&gt;hiccup&lt;/code&gt;. &lt;code&gt;hiccup&lt;/code&gt; is
not a Reagent thing, but a DSL which was adapted from a server-side tool called
&lt;a href=&quot;https://github.com/weavejester/hiccup&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Hiccup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hiccup&lt;/code&gt; was introduced by &lt;a href=&quot;https://github.com/weavejester&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;James Reeves&lt;/a&gt; and has become a standard DSL for
Clojure developers looking to represent HTML in Clojure.  This means that there
are many 3rd party libraries which allow you to write Hiccup in your app even
if you aren&#39;t using Reagent.  For example, the following are all examples of
popular Hiccup libraries.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/weavejester/hiccup&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Hiccup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/r0man/sablono&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Soblano&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/rauhs/hicada&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Hicada&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cgrand/enlive&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;enlive&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And I think this is the beginning of some of the confusion when it comes to
&lt;code&gt;hiccup&lt;/code&gt; and Reagent.&lt;/p&gt;
&lt;p&gt;When one starts to learn ClojureScript, they often start with Clojure.  The
Clojure guides, references and libraries are generally oriented towards Clojure.
While this is understanable, it can create a challenge when trying to figure
out how to write HTML in Clojure.&lt;/p&gt;
&lt;p&gt;My story was that I started with Clojure building a little MPA with &lt;code&gt;hiccup&lt;/code&gt;.
I found my library of choice and made stuff appear on the screen by calling
the &lt;code&gt;hiccup&lt;/code&gt; library I chose.  Then I tried to make the same thing
happen in Reagent and noticed that I didn&#39;t need a library or to call to anything
and it all just worked.  I eventually learned what was happening, hence this
post, but it was irritating at first to not get what was really going on.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/reagent-and-hiccup/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The overarching point is that &lt;code&gt;hiccup&lt;/code&gt; is a common way of writing HTML is
Clojure.  Unlike JSX, which for a long while was a React only thing, Hiccup is
not specific to Reagent/React.  So, this point is meant to provide the context.&lt;/p&gt;
&lt;p&gt;Want to learn more about &lt;code&gt;hiccup&lt;/code&gt;? Tonsky&#39;s &lt;a href=&quot;https://tonsky.me/blog/hiccup/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;article on hiccup&lt;/a&gt; is pretty great.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Clojure Text Editors</title>
    <link href="https://betweentwoparens.com/blog/clojure-text-editors/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/clojure-text-editors/</id>
    <content type="html">&lt;p&gt;One of the most common beginner Clojure/Script questions I see is, &amp;quot;which text
editor should I use?&amp;quot;. I can relate to this question because it&#39;s the same one
I had when I started.  Most of the answers I found led me to using &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;emacs&lt;/a&gt;. So, I started to
learn Clojure and emacs at the same time.  This was a bad decision becuase it
was simply too many things to learn at once.&lt;/p&gt;
&lt;p&gt;What I should have done is stuck with the editor that I knew best and focused on
learning Clojure.&lt;/p&gt;
&lt;p&gt;My goal with this post to provide an outline of the popular editors and some
insight into which editor I feel will suit developers at different levels of
experience.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Text Editors are a source of furious debate amongst programmers.  So, if the
opinions expressed herein enrage, please know that is not my intention.
I love you.  Also note that my recommendations are for both Clojure and
ClojureScript.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;clojure-text-editors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojure-text-editors/#clojure-text-editors&quot;&gt;Clojure Text Editors&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s start by introducing the top Text Editors for Clojure(Script) development based on the &lt;a href=&quot;https://clojure.org/news/2023/06/30/state-of-clojure-2023&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;2023 State of Clojure Survey&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/emacs/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jetbrains.com/idea/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;IntelliJ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;VS code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.vim.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Vim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sublimetext.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Sublime&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For those who&#39;ve been in the programming game for a little while, the above list
is probably unsurprising.  For those new to programming, the above list can feel
overwhelming.&lt;/p&gt;
&lt;p&gt;The best thing to know about the above list: they are all good choices and it&#39;s
going to be your personal preferences which determines which one is going to be
the best for your workflow.  Additionally,  You &lt;strong&gt;DO NOT&lt;/strong&gt; need to use Emacs or
IntelliJ to learn or become excellent/get the most out of Clojure.&lt;/p&gt;
&lt;h2 id=&quot;which-text-editor-to-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojure-text-editors/#which-text-editor-to-use&quot;&gt;Which Text Editor to Use&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In general, there are two groups of developers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A&lt;/strong&gt;. &amp;quot;Experienced&amp;quot; developers (hobbyist/professionals)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B&lt;/strong&gt;. New developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;re &lt;strong&gt;A&lt;/strong&gt;, stick with the editor your currently using.  If you&#39;re &lt;strong&gt;B&lt;/strong&gt;,
try &lt;code&gt;Sublime&lt;/code&gt; or &lt;code&gt;VS Code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A Text Editor is a developer&#39;s primary tool.  We spend most of our work life
inside of them.  Given time, you&#39;re going to develop an opinion about what you
like and don&#39;t like about your text editor of choice.  For example, I want
to know that I&#39;m productive in whichever Text Editor I&#39;m using so I want to
know that it&#39;s fast and that I can customize it when I need to so I can adapt it
to my changing development requirements.  So, I want it to start fast, I want
to be able to quickly and easily setup my editor on other machines, I don&#39;t
want to see lag when I&#39;m typing, searching large codebases or opening files. When
I want to customize something with the editor, I want to be in control where
it makes sense.&lt;/p&gt;
&lt;p&gt;All of this is to say that these are my preferences that I have built through
years of experimentation and self-analysis.  If you have been developing for a
while, you will have likely gone through a similar process.  But let&#39;s go back
to the original question of &amp;quot;which text editor to choose?&amp;quot;.&lt;/p&gt;
&lt;p&gt;As I said earlier, if you&#39;re an experienced developer, go with the editor you know.
If you are a new programmer and don&#39;t have deep ties to any particular editor,
choose &lt;code&gt;Sublime&lt;/code&gt; or &lt;code&gt;VS Code&lt;/code&gt;.  The reason for this recommendation is because
these editors are easy to use, work on all operating systems, have active and
easy to access communities and support all the modern Clojure tooling one could
ever want.&lt;/p&gt;
&lt;p&gt;Im comparison, if you choose an editor like Emacs, Vim, or Intellij you are going
to spend more time learning and configuring the editors than learning Clojure.
You can always try these editors when you feel more accomplished with Clojure
and want to optimize your workflow.  But at least when you get to this point
you will have a frame of reference.&lt;/p&gt;
&lt;p&gt;Knowing this, lets move onto how I setup Atom for my development workflow.&lt;/p&gt;
&lt;h2 id=&quot;my-text-editor-setup&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojure-text-editors/#my-text-editor-setup&quot;&gt;My Text Editor Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use &lt;code&gt;nvim&lt;/code&gt; as my daily text editor for all development because it&#39;s fast,
customizable and I can control how much or little I want &lt;code&gt;nvim&lt;/code&gt; to do.  The
problem with Vim is that it&#39;s not friendly to people new to software
development.  For those interested in my &lt;code&gt;nvim&lt;/code&gt; setup you can see my &lt;a href=&quot;https://github.com/athomasoriginal/dotfiles&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Dotfiles&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojure-text-editors/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Programming communities always form around text editors. No matter which programming
language you choose there are always going to be a large number of decisions to make.
The important thing to remember is that in the beginning it&#39;s often easier if
you focus on learning one thing at a time.   When it comes to programming, learn
the language first and choose tools which allow you to focus on learning your
language of choice.  Learning new things is hard enough, so be good to
yourself in your learning journey and try not to obsess over all the details or
aligning to anyone&#39;s perception of the &lt;em&gt;ideal programmer&lt;/em&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Deploy ClojureScript on Nginx</title>
    <link href="https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/</id>
    <content type="html">&lt;p&gt;My &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;first blog post&lt;/a&gt; outlined how to deploy a static ClojureScript website to
Github Pages. This is an excellent choice for personal websites, or an open
source project&#39;s documentation because you get free hosting infrastructure with
relatively little effort.  Having said this, what happens if you can&#39;t use
static hosting providers like Github Pages or &lt;a href=&quot;https://www.netlify.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Netlify&lt;/a&gt;?  What if you need to
control more of the hosting service?  This post will show you how to deploy
your ClojureScript site on a webserver you control.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Beyond creating a simple ClojureScript app, this post is not really about
ClojureScript. I see it as clarifying the process of deploying static sites in
general.  Specifically, we will focus on deploying ClojureScript to a webserver
(&lt;a href=&quot;https://www.nginx.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nginx&lt;/a&gt;).  If you are following along, you can see the &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-nginx&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;source code here&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;the-deploy-process&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#the-deploy-process&quot;&gt;The Deploy Process&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to make our site available to the internet we need a &lt;code&gt;physical webserver&lt;/code&gt; and a &lt;code&gt;software webserver&lt;/code&gt;.  Once we have these, we just have to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Store your website&#39;s artifacts (&lt;code&gt;html&lt;/code&gt;, &lt;code&gt;css&lt;/code&gt; and &lt;code&gt;js&lt;/code&gt;) on a &lt;code&gt;physical server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Teach your &lt;code&gt;software webserver&lt;/code&gt; where those files live&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In order to do the above, we need to perform the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build your website&#39;s production artifacts&lt;/li&gt;
&lt;li&gt;Move your website&#39;s  production artifacts to a &lt;code&gt;physical webserver&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Configure your &lt;code&gt;software webserver&lt;/code&gt; to deliver your website&#39;s artifacts to users&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These steps are the same whether you are writing &lt;code&gt;JavaScript&lt;/code&gt;, &lt;code&gt;ClojureScript&lt;/code&gt;,
&lt;code&gt;Reason&lt;/code&gt; etc.&lt;/p&gt;
&lt;p&gt;We can illustrate the whole process on your computer right now by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using your as your &lt;code&gt;physical server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://www.nginx.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nginx&lt;/a&gt; as our &lt;code&gt;software server&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;ClojureScript&lt;/code&gt; for our static website&lt;/li&gt;
&lt;li&gt;Using &lt;a href=&quot;https://www.docker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;docker&lt;/a&gt; to make the deploy consistent and predictable&lt;/li&gt;
&lt;/ol&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;We are using &lt;code&gt;Nginx&lt;/code&gt; because as far as webservers go it&#39;s easy to setup, configure and find documentation for.  Finally, because it&#39;s ready to use you can use this solution in your workplace today to quickly deploy static documentation or a prototype app.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;housekeeping&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#housekeeping&quot;&gt;Housekeeping&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are going to follow along with this post please make sure you have the following tools installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/v17.09/engine/installation/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Install Docker&lt;/a&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#why-docker&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;why-docker-ref&quot;&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/guides/quick-start&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Install Clojure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;create-app&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#create-app&quot;&gt;Create App&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;This whole process starts with a ClojureScript app.  If you already have an app
you can skip this part.  If you don&#39;t have an app, please follow along with
this section and we will set you up with your very own ClojureScript app.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Start by creating a basic ClojureScript app.  The easiest way to do this is by
following the &lt;a href=&quot;https://github.com/athomasoriginal/templates#getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;templates getting started guide&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&lt;code&gt;templates&lt;/code&gt; is a repo of my personal &amp;quot;start projects&amp;quot;. Using the Reagent template,
as outlined in the getting started guide linked above, will quickly get you
started with a modern ClojureScript app for us.&lt;/p&gt;
&lt;p&gt;You can think of the above as a lightweight ClojureScript version of
&lt;a href=&quot;https://create-react-app.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;create-react-app&lt;/a&gt;. If you&#39;re curious about the &lt;code&gt;reagent&lt;/code&gt; template generated
you can read all about it in &lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Start a ClojureScript App from Scratch&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Once the above is complete you should have a project that looks like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
├── README.md
├── deps.edn
├── dev.cljs.edn
├── resources
│   └── public
│       ├── index.html
│       └── style.css
├── src
│   └── demo_clojurescript_nginx
│       └── demo_clojurescript_nginx.cljs
└── &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;
    └── demo_clojurescript_nginx
        └── demo_clojurescript_nginx_test.cljs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Note that your project will have a different name than mine (&lt;code&gt;demo_clojurescript_nginx&lt;/code&gt;).
This app comes with commands for running the app in &lt;code&gt;dev&lt;/code&gt; and building a
&lt;code&gt;prod&lt;/code&gt; version of the app.  The commands are &lt;code&gt;clj -M:dev&lt;/code&gt; and &lt;code&gt;clj -M:prod&lt;/code&gt; respectively.  Feel free to play with the app.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;sanity-check-webserver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#sanity-check-webserver&quot;&gt;Sanity Check Webserver&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I always start with a sanity check.  A sanity check is us setting a baseline
to make sure things are working.  If you were decorating a tree, this step would
be us making sure the lightbulbs are working before we decorate the tree.&lt;/p&gt;
&lt;p&gt;We&#39;re going to verify that we can use docker to pull and run an &lt;code&gt;Nginx&lt;/code&gt;
container locally. To begin, &lt;code&gt;pull&lt;/code&gt; an nginx docker image into your local
filesystem:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; pull nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can verify that the image was successfully pulled in by running the following command&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; images
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and if all went well we should see an &lt;code&gt;Nginx&lt;/code&gt; image in your local filesystem like:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;REPOSITORY  TAG    IMAGE ID     CREATED     SIZE
nginx       latest 540a289bab6c &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; days ago  126MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If that went well, we can try to run our nginx docker container&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; demo-clojurescript-nginx &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;:80 &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and once again we will verify that the container is running&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ps&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and you should see something like&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;CONTAINER ID  IMAGE  COMMAND                  CREATED        STATUS
9118c08ed0a6  nginx  &lt;span class=&quot;token string&quot;&gt;&quot;nginx -g &#39;daemon of…&quot;&lt;/span&gt;   &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt; seconds ago  Up &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; seconds
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and now you should be able to visit your docker container at
&lt;code&gt;http://localhost:80&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the above is working we can move onto the next step which is deploying our
app.  The reason I&#39;m manually going through these steps is so that we have a
clear understanding of what we&#39;ll eventually automate.&lt;/p&gt;
&lt;p&gt;Before we continue, make sure you stop your &lt;code&gt;Nginx&lt;/code&gt; docker container and remove
it like so:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; stop demo-clojurescript-nginx &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; demo-clojurescript-nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and let&#39;s start it again except this time we will start it on port &lt;code&gt;4001&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; demo-clojurescript-nginx &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4001&lt;/span&gt;:4001 &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&quot;build-production-artifacts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#build-production-artifacts&quot;&gt;Build Production Artifacts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section is about building production artifacts.  To clear things up, when I say &lt;code&gt;artifact&lt;/code&gt; I mean the code that will be run by our webserver.  In the case of a web development project, the &lt;code&gt;artifact&lt;/code&gt; will be the minified and dead code eliminated JavaScript produced by the ClojureScript compiler.&lt;/p&gt;
&lt;p&gt;To create this artifact we have to tell the ClojureScript compiler to build it for us.  We do this with the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clojure &lt;span class=&quot;token parameter variable&quot;&gt;-M:prod&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After the above command is run we can verify that we have a production &lt;code&gt;artifact&lt;/code&gt; by looking into the &lt;code&gt;out&lt;/code&gt; directory and finding a file called &lt;code&gt;dev-main.js&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;out
├── cljs
│   ├── core
│   ├── core.cljs
│   └── core.js
├── dev-main.js
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.more stuff
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If that has worked, we can move to the next step: putting our production artifacts on the &lt;code&gt;physical webserver&lt;/code&gt; (docker container).&lt;/p&gt;
&lt;h2 id=&quot;move-production-artifacts-to-webserver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#move-production-artifacts-to-webserver&quot;&gt;Move Production Artifacts to Webserver&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This step is about creating a place for our production artifacts to live. To do this, we are going to manually go inside our nginx container and create the folder structure.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-it&lt;/span&gt; demo-clojurescript-nginx &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and how create the folder like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; var/www/app/cljs-out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then exit the docker container.  From here we can move the production artifacts from our local machine to the docker container.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# move the js artifact&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; out/dev-main.js demo-clojurescript-nginx:var/www/app/cljs-out/
&lt;span class=&quot;token comment&quot;&gt;# move the css artifact&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; resources/public/style.css demo-clojurescript-nginx:var/www/app/style.css
&lt;span class=&quot;token comment&quot;&gt;# move the html artifact&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; resources/public/index.html demo-clojurescript-nginx:var/www/app/index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From here, we just have to teach our webserver how to serve these files.&lt;/p&gt;
&lt;h2 id=&quot;teach-webserver-to-serve-artifacts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#teach-webserver-to-serve-artifacts&quot;&gt;Teach Webserver to Serve Artifacts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point we just have to configure our &lt;code&gt;Nginx&lt;/code&gt; server to know where our production artifacts live.  To do this, we have to remove the default &lt;code&gt;Nginx&lt;/code&gt; configuration file and replace it with a new one.&lt;/p&gt;
&lt;p&gt;Start by execing into the &lt;code&gt;Nginx&lt;/code&gt; docker container:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-it&lt;/span&gt; demo-clojurescript-nginx &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Remove the old configuration file:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then exit out of the docker container.  At this point, we want to create a custom configuration file called &lt;code&gt;nginx.conf&lt;/code&gt;.  This configuration file will live in the root of our ClojureScript app in a folder structure like &lt;code&gt;tools/nginx/nginx.conf&lt;/code&gt; inside the root of our &lt;code&gt;demo-clojurescript-nginx&lt;/code&gt; ClojureScript app.  So go ahead and create the folder structure:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; tools/nginx &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; tools/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then you can open &lt;code&gt;nginx.conf&lt;/code&gt; and make it look like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;events &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

http &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  include mime.types&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;gzip&lt;/span&gt; on&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  server_tokens off&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  server &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    listen &lt;span class=&quot;token number&quot;&gt;4001&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    root /var/www/app&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we want give this &lt;code&gt;nginx.conf&lt;/code&gt; file to our &lt;code&gt;Nginx&lt;/code&gt; container so it knows how and where to serve our project from.  To do this, run the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; tools/nginx/nginx.conf demo-clojurescript-nginx:etc/nginx/nginx.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;at this point we want to stop our docker container so the configuration file takes effect&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; stop demo-clojurescript-nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and then we can start the container again.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; start demo-clojurescript-nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we should be able to visit our site at &lt;code&gt;http://localhost:4001&lt;/code&gt; and see the following:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/005-demo-clojurescript-nginx-final.png&quot; alt=&quot;demo clojurescript nginx&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;automate-process&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#automate-process&quot;&gt;Automate Process&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything we just did is very manual and we can save time and reduce chances
of human error by automating the above process.  The following will show you
how to do this.&lt;/p&gt;
&lt;h3 id=&quot;automate-prod-artifact-builds&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#automate-prod-artifact-builds&quot;&gt;Automate Prod Artifact Builds&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Go into the &lt;code&gt;tools/nginx&lt;/code&gt; directory and create a file called &lt;code&gt;Dockerfile.build&lt;/code&gt;
and make it look like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# base image&lt;/span&gt;
FROM clojure:openjdk-11-tools-deps-slim-buster

&lt;span class=&quot;token comment&quot;&gt;# create dir for our app to live in&lt;/span&gt;
WORKDIR /app

&lt;span class=&quot;token comment&quot;&gt;# copy the app from our local filesystem to the docker container app dir&lt;/span&gt;
COPY &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; /app

&lt;span class=&quot;token comment&quot;&gt;# build our prod clojurescript artifact&lt;/span&gt;
RUN clojure &lt;span class=&quot;token parameter variable&quot;&gt;-M:prod&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# The end.  No need for a CMD to be specified because this is a build&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# docker containers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;In the above the goal is really to keep everything as light as possible. We just want &lt;code&gt;Java&lt;/code&gt; so we can build our project and if you have to build anything with &lt;code&gt;node&lt;/code&gt; you will have to also add that to the docker container.  Stuff you might do with node?  Build your style sheets?  Run tests in a headless environment? etc. It&#39;s going to download eveything and then run the container.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;A few things to note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we use &lt;code&gt;clojure&lt;/code&gt; instead of &lt;code&gt;clj&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;when you run this container you want to run it from the root of the app&lt;/li&gt;
&lt;li&gt;this will copy everything in the root project to a generically name folder called &lt;code&gt;app&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This docker file is responsible for building our artifacts that we performed in
step 2 earlier.  Now lets go ahead and move to the root of our project and run
that dockerfile and see if everything works:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; build &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
             demo-clojurescript-nginx/build:0.0.0 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
             &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tools/nginx/Dockerfile.build&quot;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above is going to build our image and the production clojurescript object.
The next step is to run a container based off the above image so that we can
get the production artifacts&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; demo-clojurescript-nginx-build &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           demo-clojurescript-nginx/build:0.0.0 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you&#39;re curious about the content of your docker build container you can exec
into it like this &lt;code&gt;docker exec -it demo-clojurescript-nginx-build bash&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;move-production-artifacts-to-local-filesystem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#move-production-artifacts-to-local-filesystem&quot;&gt;Move Production Artifacts to Local FileSystem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At this point, we want to copy the built files from the docker container to our local machine.  If this were running in a CI/CD process we would have a special spot in the CI/CD environment for these temporary files.  Because this is our local system, we have to create a temporary place for these things to live.  Lets call this place &lt;code&gt;temp/cljs-out&lt;/code&gt; and we will create it in the root of our &lt;code&gt;demo-clojurescript-nginx&lt;/code&gt; repo.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; temp/cljs-out
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;from here we can grab the files from our &lt;code&gt;Dockerfile.build&lt;/code&gt; container and move them to our temp dir like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; demo-clojurescript-nginx-build:app/resources/public/index.html ./temp/index.html
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; demo-clojurescript-nginx-build:app/resources/public/style.css ./temp/style.css
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; demo-clojurescript-nginx-build:app/out/dev-main.js ./temp/cljs-out/dev-main.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Note that if you are running in CI/CD tool like circleci or travis or anything really the whole manual copy things over step does not have to be done because there is a temporary file system there where you can store things.  In our case, we are setting this up to run locally so we will create a holding place in our repo which will act as this temporary file system.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;automate-nginx-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#automate-nginx-configuration&quot;&gt;Automate Nginx Configuration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next step is automate step 3 from above: nginx configuration and moving the artifacts from the above to the nginx container.  To do this, we need to build our own nginx container which is going to be the docker container you would actually run.  SO go ahead and create another docker container inside of &lt;code&gt;tools/nginx&lt;/code&gt; called &lt;code&gt;Dockerfile&lt;/code&gt; which looks like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# base image&lt;/span&gt;
FROM nginx:1.17.5

&lt;span class=&quot;token comment&quot;&gt;# remove the default nginx configuration&lt;/span&gt;
RUN &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; /etc/nginx/nginx.conf

&lt;span class=&quot;token comment&quot;&gt;# add custom nginx configuration&lt;/span&gt;
COPY ./tools/nginx/nginx.conf /etc/nginx

&lt;span class=&quot;token comment&quot;&gt;# allow nginx conf to be executable&lt;/span&gt;
RUN &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /etc/nginx &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x /etc/nginx/nginx.conf

&lt;span class=&quot;token comment&quot;&gt;# create working directory&lt;/span&gt;
WORKDIR /var/www/app

&lt;span class=&quot;token comment&quot;&gt;# copy our temp artifacts&lt;/span&gt;
COPY ./temp /var/www/app

&lt;span class=&quot;token comment&quot;&gt;# start nginx container&lt;/span&gt;
CMD /bin/bash &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nginx -g &#39;daemon off;&#39;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;now build the image&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; build &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
             demo-clojurescript-nginx/prod:0.0.0 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
             &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tools/nginx/Dockerfile&quot;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and before we run our final image stop any instances of &lt;code&gt;Nginx&lt;/code&gt; docker containers you may still have running on port &lt;code&gt;4001&lt;/code&gt;.  e.g.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; stop demo-clojurescript-nginx
&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; stop demo-clojurescript-nginx-build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and now we should be able to run our &lt;code&gt;Nginx&lt;/code&gt; container&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;docker&lt;/span&gt; run &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4001&lt;/span&gt;:4001 &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           &lt;span class=&quot;token parameter variable&quot;&gt;--name&lt;/span&gt; demo-clojurescript-nginx-prod &lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
           demo-clojurescript-nginx/prod:0.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we should be able to visit &lt;code&gt;http://localhost:4001&lt;/code&gt; and we should be able to see&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/005-demo-clojurescript-nginx-final.png&quot; alt=&quot;demo clojurescript nginx&quot; /&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And with that we have successfully deployed our ClojureScript app to our own &lt;code&gt;Nginx&lt;/code&gt; webserver. At this point, the next step is to deploy this on a server.  Unfortunatley, that is out of the scope of this post, but if you are using a service like &lt;a href=&quot;https://aws.amazon.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;AWS&lt;/a&gt; or &lt;a href=&quot;https://cloud.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Google Cloud Platform&lt;/a&gt; they should have some awesome guides for deploying Nginx on their infrastructure.&lt;/p&gt;
&lt;p&gt;Again, my hope is to outline a piece of the process.  Let me know if this helped!&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;why-docker&quot;&gt;&lt;p&gt;The reason I am using docker is because I want to reach as many OS&#39;s as I can and I feel that docker is pretty standard.  If I did not use docker, I would just write this with shell scripts because this work is straightforward and does not require much more than that, but perhaps it would be fun to write a CLJS node script in the future to show what that would look like.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-on-nginx/#why-docker-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>Students of the Game: Reloadable Code</title>
    <link href="https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/</id>
    <content type="html">&lt;p&gt;About two years ago I built a small ClojureScript app that looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/004-01-calendar-app-intro.png&quot; alt=&quot;calendar app&quot; /&gt;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The source code can be found &lt;a href=&quot;https://github.com/athomasoriginal/demo-reloadable-code&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;This app was meant to be a bite sized learning project to level up my ClojureScript interop skills.&lt;/p&gt;
&lt;p&gt;Aside from being gorgeoous, it had only two things to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User presses the &lt;code&gt;Add&lt;/code&gt; button and &lt;code&gt;1&lt;/code&gt; new &lt;code&gt;Calendar Event&lt;/code&gt; is created&lt;/li&gt;
&lt;li&gt;User can see a &lt;code&gt;List&lt;/code&gt; of &lt;code&gt;Calendar Events&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I started the app &lt;a href=&quot;http://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;as I always do&lt;/a&gt; which includes running &lt;code&gt;figwheel&lt;/code&gt; and &lt;code&gt;Hot Module Reloading&lt;/code&gt; (HMR).  As I&#39;m jamming away on the code I started to notice some interesting behaviour.&lt;/p&gt;
&lt;p&gt;When I pressed the &lt;code&gt;Add&lt;/code&gt; button, instead of &lt;code&gt;1&lt;/code&gt; new &lt;code&gt;Calendar Event&lt;/code&gt; being added, &lt;code&gt;5&lt;/code&gt; were added!  I paused for a moment before hard refreshing the browser.  Then I clicked the &lt;code&gt;Add&lt;/code&gt; button again.  Unlike the first time, everything worked as expected; only &lt;code&gt;1&lt;/code&gt; new &lt;code&gt;Calendar Event&lt;/code&gt; was added.  I smiled to myself and marvelled at my incredible detective skills: obviously the problem was &lt;code&gt;HMR&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since I &lt;em&gt;obviously&lt;/em&gt; identified the source of the problem I decided to resolve the issue by ignoring it.  So any time I made a change which triggered an &lt;code&gt;HMR&lt;/code&gt; reload I would hard refresh the browser like a savage&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#full-savage&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;full-savage-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some time later I realized that, no, the problem was not &lt;code&gt;HMR&lt;/code&gt;...it was &lt;em&gt;my&lt;/em&gt; code.  As it turns out, &lt;code&gt;HMR&lt;/code&gt; isn&#39;t free.  It requires the code author to design and build the code to be &lt;a href=&quot;https://figwheel.org/docs/reloadable_code.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;reloadable code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So in the intrepid spirit of craftsmanship, I have resurected my Calendar App and refactored it to be &lt;code&gt;reloadable code&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;intro-to-hot-module-reloading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#intro-to-hot-module-reloading&quot;&gt;Intro to Hot Module Reloading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HMR&lt;/code&gt; is a program which runs alongside our app which watches for changes to
our &lt;code&gt;.cljs&lt;/code&gt; files and when it sees that one of these &lt;code&gt;.cljs&lt;/code&gt; files has changed
it tells the browser to fetch the latest changes and trigger a &amp;quot;reload&amp;quot;. This
means our running app is automatically updated with the new code and the app
state is exactly where we left it&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#what-hmr&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;what-hmr-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We like &lt;code&gt;HMR&lt;/code&gt; because it allows us to develop faster and with less friction.
Specifically, &lt;code&gt;HMR&lt;/code&gt; can make it so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We don&#39;t have to manually refresh our browsers&lt;/li&gt;
&lt;li&gt;We don&#39;t have to lose our applications state&lt;/li&gt;
&lt;li&gt;We don&#39;t have to manually recompile our code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;HMR&lt;/code&gt; is provided by programs like &lt;a href=&quot;https://github.com/bhauman/figwheel-main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;figwheel&lt;/a&gt;, &lt;a href=&quot;https://github.com/thheller/shadow-cljs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;shadow-cljs&lt;/a&gt; or &lt;a href=&quot;https://webpack.js.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;webpack&lt;/a&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#build-tools&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;build-tools-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Each of the above tools does far more than just &lt;code&gt;HMR&lt;/code&gt;, but &lt;code&gt;HMR&lt;/code&gt; is one of
their standout features.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Having said the above, just because you use &lt;code&gt;figwheel&lt;/code&gt; or &lt;code&gt;shadow-cljs&lt;/code&gt; doesn&#39;t
mean you can get the benefits of &lt;code&gt;HMR&lt;/code&gt;.  You also have to architect your
code in a specific way. Namely, you have to control side effects.  In other words,
you have to write &lt;code&gt;reloadale code&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The exception to the above paragraph is if you are using &lt;code&gt;React&lt;/code&gt;.  If you use
&lt;code&gt;React&lt;/code&gt;, then HMR will pretty much work for free.  This article is for
developers who want use HMR with their vanilla CLJS or JavaScript code.  Yet,
even if you are writing &lt;code&gt;React&lt;/code&gt; this article is still a good overview and will
hopefully provide a deeper appreciation for the architectural decisions of
React.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;%22submit%22-event-listeners&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#%22submit%22-event-listeners&quot;&gt;&amp;quot;Submit&amp;quot; Event Listeners&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you save the &lt;code&gt;calendar.cljs&lt;/code&gt; file 5 times and then press the &lt;code&gt;Add&lt;/code&gt; button in the
Calendar App you will see it creates 5 &lt;code&gt;Calendar Events&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If we inspect the console we can see that this is because our &amp;quot;submit&amp;quot; event
listener is attached 5 times to the &lt;code&gt;submit&lt;/code&gt; event.  This is why when we click the
&lt;code&gt;Add&lt;/code&gt; button, we get 5 &lt;code&gt;Calendar Events&lt;/code&gt; added instead of the expected 1&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#debugging-event-listeners&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;debugging-event-listeners-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Why is this happening?  As it turns out, if you look to the &lt;a href=&quot;https://github.com/athomasoriginal/demo-reloadable-code/commit/b26c1aac8e9c9d6e2d5c7407cc1806dac9b92724#diff-9f16cf6f6db4d58c84ae2d61fd54ec7fR168&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;code here&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.calendar-form&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;
  handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The code above is invoked in our &lt;code&gt;ns&lt;/code&gt; meaning that it runs everytime a &lt;code&gt;reload&lt;/code&gt; is triggered.  In other words, if you trigger 5 &lt;code&gt;reloads&lt;/code&gt; it would be as if you wrote this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt; handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt; handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt; handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt; handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt; handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Wait.  Didn&#39;t we say that each &lt;code&gt;reload&lt;/code&gt; triggers a browser refresh?  Not exactly.  What we mean is that the ClojureScript in your app is sent to the DOM and re-run.  The effect makes it appear like the browser is refreshing.  Thus, triggering a &lt;code&gt;reload&lt;/code&gt; updates your ClojureScript and re-runs your ClojureScript, but unlike your ClojureScript, whatever you did the DOM previously prior to a &lt;code&gt;reload&lt;/code&gt; stays done.&lt;/p&gt;
&lt;p&gt;This is why when we write reloadable code we have to control what we do to the DOM so we don&#39;t cause unexpected behaviours like 5 &lt;code&gt;Calendar Events&lt;/code&gt; added at a time.&lt;/p&gt;
&lt;p&gt;So how do we control what we do to the DOM to avoid these unpredictable side effects?  We write &lt;code&gt;reloadable code&lt;/code&gt; and to do this we have to know two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;when is our code going to reload?&lt;/li&gt;
&lt;li&gt;when is our code going to finish reloading?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;figwheel&lt;/code&gt;, as well as other programs, provides us with a mechanism so we can answer the above 2 questions and that mechanism looks like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:before-load teardown &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;; ...do stuff&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:after-load setup &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;; ...do stuff&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before we go further, lets breakdown what the above is doing.  &lt;code&gt;teardown&lt;/code&gt; and &lt;code&gt;setup&lt;/code&gt; are nothing more than clojure functions.  The only part we have to care about from the above are the &lt;code&gt;^:before-load&lt;/code&gt; and &lt;code&gt;^:after-load&lt;/code&gt; words that come before &lt;code&gt;teardown&lt;/code&gt; and &lt;code&gt;setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;^:before-load&lt;/code&gt; and &lt;code&gt;^:after-load&lt;/code&gt; are called &lt;a href=&quot;https://clojure.org/reference/metadata&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;metadata&lt;/a&gt; in Clojure(Script).
What makes them &lt;code&gt;metadata&lt;/code&gt; is the &lt;code&gt;^&lt;/code&gt; that comes before the &lt;code&gt;:&lt;/code&gt; (colon).&lt;/p&gt;
&lt;p&gt;When figwheel sees these particular pieces of metdata infront of a function it knows that it has to run our functions before and after the CLJS reloads.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Please note that like any function you can rename &lt;code&gt;teardown&lt;/code&gt; and  &lt;code&gt;setup&lt;/code&gt; to whatever you like.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Now that we know we can write code that runs before and after load we just have to figure out what we should put in these functions to make our code &lt;code&gt;reloadable code&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Going back to the &amp;quot;submit&amp;quot; &lt;code&gt;event listener&lt;/code&gt; scenario, the problem is that everytime our code reloads, a new &lt;code&gt;event listener&lt;/code&gt; is attached to the &amp;quot;submit&amp;quot; event.  But what we want is to only have 1 &lt;code&gt;event listener&lt;/code&gt;, the newest &lt;code&gt;event listener&lt;/code&gt;, attached to our submit.  So what we need to make our code do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;before reload: remove old &amp;quot;submit&amp;quot; event listener&lt;/li&gt;
&lt;li&gt;after reload: add new &amp;quot;submit&amp;quot; event listener&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following is what the above looks like in our code:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; before reload: remove old &quot;submit&quot; event listener&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:before-load teardown &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/removeAll&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;.querySelector&lt;/span&gt; js/document &lt;span class=&quot;token string&quot;&gt;&quot;.calendar-form&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; after reload: add new &quot;submit&quot; event listener&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:after-load setup &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.calendar-form&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;
    handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defonce&lt;/span&gt; initial-load &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;See the &lt;a href=&quot;https://github.com/athomasoriginal/demo-reloadable-code/commit/ceb1ae2b907eb8c04befcb30c21e9bab81706000&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;code&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;What we did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;before-load&lt;/code&gt; - figwheel is going to call our &lt;code&gt;teardown&lt;/code&gt; function which deletes event listeners from &lt;code&gt;submit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;after-load&lt;/code&gt; - figwheel is going to call our &lt;code&gt;setup&lt;/code&gt; function which adds event listeners to &lt;code&gt;submit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You might have also noticed that I snuck in a little something extra: &lt;code&gt;initial-load&lt;/code&gt;.  Remember how we said that &lt;code&gt;before-load&lt;/code&gt; happens before a reload and &lt;code&gt;after-load&lt;/code&gt; happens after a reload?  This means those are &lt;em&gt;only&lt;/em&gt; triggered when a reload is triggered.  If we left it like that, our code would not work when we first visit the app.  So we add a &lt;code&gt;defonce&lt;/code&gt; so that the code which runs on the  &lt;em&gt;first&lt;/em&gt;, and only the first time, your app loads in the browser.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you&#39;re following allong with the code, I encourage you to comment out &lt;code&gt;initial-load&lt;/code&gt; and see what happens.  Also note that you do not need to call &lt;code&gt;setup&lt;/code&gt; in &lt;code&gt;initial-load&lt;/code&gt;, you could write a totally separate function.  I just did the above to keep the example cleaner&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;With the above in place go ahead and try to trigger some reloads.  If everything worked, no matter how many time you trigger a reload only 1 &lt;code&gt;Calendar Event&lt;/code&gt; should ever be created.&lt;/p&gt;
&lt;p&gt;If you are lost at this point for any reason take comfort in the fact that writing &lt;code&gt;reloadable code&lt;/code&gt; is not always straighforward and does require you to think deeply about what your code is doing.  This is a skill that can take some time to learn.&lt;/p&gt;
&lt;h2 id=&quot;%22change%22-event-listeners&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#%22change%22-event-listeners&quot;&gt;&amp;quot;Change&amp;quot; Event Listeners&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here is the second opportunity for making our code &lt;code&gt;reloadable code&lt;/code&gt;.  Similar to the &amp;quot;submit&amp;quot; example above, we are invoking another &lt;code&gt;event listener&lt;/code&gt; in our file for the &lt;code&gt;change&lt;/code&gt; event:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#event_start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt;
  update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you have the code infront stop for a moment.  Read the src code for &lt;code&gt;update-event-end-dropdown!&lt;/code&gt; and try to see what the bug is.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;If you read the code, or even ran the code, you will see that this code is not a problem.  Yes, if we &lt;code&gt;reload&lt;/code&gt; our app 5 times it would do this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt; update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt; update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt; update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt; update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt; element &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt; update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But it&#39;s still not causing any bugs.  The reason is because the code inside of &lt;code&gt;update-event-end-dropdown!&lt;/code&gt; is destructive and not performing an additive effect like &amp;quot;submit&amp;quot;.  The worst that happens is that if we &lt;code&gt;reload&lt;/code&gt; 5 times the &lt;code&gt;option&lt;/code&gt; will get set 5 times because of &lt;code&gt;(.-innerHTML start-time-dropdown)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So if this is not a bug, then why talk about it?  Because even if the code is not causing problems now, it is stacking &lt;code&gt;event listeners&lt;/code&gt; and if we change &lt;code&gt;update-event-end-dropdown!&lt;/code&gt; to accidentally do something different, we are going to set ourselves up nicely for an interesting bug.&lt;/p&gt;
&lt;p&gt;If neither of these arguments persuade you, that is fine and highlights the interesting part about writing &lt;code&gt;reloadable code&lt;/code&gt;:  many elements of designing your code in this way are going to be subjective and based on how &lt;em&gt;you&lt;/em&gt; want your code to run.&lt;/p&gt;
&lt;p&gt;Having said this, for this scenario I am going to play it safe and show you how we could fix the code:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:after-load setup &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.calendar-form&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;
    handle-add-event!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;events/listen&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; js/document &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#event_start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;change&quot;&lt;/span&gt;
    update-event-end-dropdown!&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see the above change &lt;a href=&quot;https://github.com/athomasoriginal/demo-reloadable-code&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;here&lt;/a&gt;.  In the next section we are going to
explore more subjective goodness.&lt;/p&gt;
&lt;h2 id=&quot;populating-dropdown-options&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#populating-dropdown-options&quot;&gt;Populating Dropdown Options&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reading [along with the code] in Calendar App, we have another invocation when
the &lt;code&gt;ns&lt;/code&gt; loads.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;set!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; start-time-dropdown -innerHTML&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time-option-list&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;set!&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;..&lt;/span&gt; end-time-dropdown -innerHTML&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time-option-list&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time-range&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9.25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All these do is populate the time options in our forms time dropdowns.  So the question is, if we run this multiple times in a row what happens?  Similar to the &amp;quot;change&amp;quot; event listeners, the above is performing a destructive action.  each time they are run they will delete the content of the &lt;code&gt;select&lt;/code&gt; boxes and replace them with the same options.  Also, unlike &lt;code&gt;event listeners&lt;/code&gt; these do not stack.  Will there be a bug?  What are the problems with this?&lt;/p&gt;
&lt;p&gt;Each time we run this code, it clears out our dropdowns and re-adds options.  What if we put this in &lt;code&gt;initial-load&lt;/code&gt;?  It would only run once meaning that if we made changes to &lt;code&gt;time-option-list&lt;/code&gt; we would not see the effect take place.  But what if we know we are 100% done with &lt;code&gt;time-option-list&lt;/code&gt;?  Perhaps we don&#39;t believe their will be more changes?  Maybe this justifies only putting it into the &lt;code&gt;initial-load&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, if you are in the camp that believe we should re-run this action just to be safe, then we can put it into the &lt;code&gt;initial-load&lt;/code&gt; and &lt;code&gt;after-load&lt;/code&gt;.  But if we do this there is something that could happen.  Imagine this is what I did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;select a &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; time&lt;/li&gt;
&lt;li&gt;realize I need to make a change to the code&lt;/li&gt;
&lt;li&gt;change the code + trigger a &lt;code&gt;reload&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we move the &lt;code&gt;time-option-list&lt;/code&gt; inside the &lt;code&gt;after-load&lt;/code&gt; everytime a &lt;code&gt;reload&lt;/code&gt; is triggered we are going to lose our &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; time we selected.  We are losing app state.  If this is concerning to &lt;em&gt;you&lt;/em&gt;, then it is not enough to add our &lt;code&gt;time-option-list&lt;/code&gt; to the &lt;code&gt;after-load&lt;/code&gt; we also have to add additional code to our app to potentially save the state of the application so we don&#39;t lose it.  I won&#39;t walk through what that looks like, as I wanted to bring it up as a lead to what makes &lt;code&gt;HMR&lt;/code&gt; feel like magic:  app state.&lt;/p&gt;
&lt;h2 id=&quot;managing-app-state&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#managing-app-state&quot;&gt;Managing App State&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;App State is a memory of what you did in the app.  When we trigger a reload we can make it so our add does not reset its app state.  For example, let&#39;s pretend I am working on my add, I add a few &lt;code&gt;Calendar Events&lt;/code&gt; and trigger a reload.  Those &lt;code&gt;Calendar Events&lt;/code&gt; I just added will be lost.  We go back to 0.  This does not have to be the case though.  We could tell our add to not reset the state.&lt;/p&gt;
&lt;p&gt;To make this happen all you have to do, based on how I wrote Calendar App, is this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; update this line&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; app-state &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;atom&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;; to look like this&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defonce&lt;/span&gt; app-state &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;atom&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&#39;s it.  Now, whenever your app &lt;code&gt;reloads&lt;/code&gt;, your state is never forgotten.
The way this works is explained nicely in &lt;a href=&quot;https://code.thheller.com/blog/shadow-cljs/2019/08/25/hot-reload-in-clojurescript.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Hot Reload in ClojureScript&lt;/a&gt;.  The
short answer: &lt;code&gt;defonce&lt;/code&gt; means that &lt;code&gt;app-state&lt;/code&gt; will not reset to &lt;code&gt;(atom [])&lt;/code&gt;
when the app &lt;code&gt;reloads&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a simple example, but it should provide some ideas for what needs to be done to make our &lt;code&gt;reloadable code&lt;/code&gt; capable of managing state.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Writing &lt;code&gt;reloadable code&lt;/code&gt; can seem tricky at first, but hopefully we can see that with ClojureScript it is an achievable and worthwhile goal.  For me the benefits of writing your code like this and even thinking about these things is the understanding you gain about how your code works.&lt;/p&gt;
&lt;p&gt;The other gain is the power that ClojureScript gives you out of the box.  It takes very little to setup HMR and start writing reloadable code with the tools provided by Clojure(Script) core library.  You don&#39;t need additional dependencies.&lt;/p&gt;
&lt;p&gt;Hopefully this provides a decent example set with which to start your reloadable code journey.&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;full-savage&quot;&gt;&lt;p&gt;In my head I was a heroic.  Crushing out code.  Delivering... I was a Titan in that moment.  The truth is this is savagery at its finest.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#full-savage-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;what-hmr&quot;&gt;&lt;p&gt;Two points here: &lt;strong&gt;First,&lt;/strong&gt; &lt;code&gt;HMR&lt;/code&gt; is not specific to ClojureScript.  It can be done in JavaScript, C++ etc.  I am only referencing ClojureScript because that is the focus of this article.  These techiques can be shared 1:1 with JavaScript, but I have not tried yet.  &lt;strong&gt;Second,&lt;/strong&gt; When I said that app state is exactly where we left it, this is &lt;em&gt;only&lt;/em&gt; true when you setup your reloadable code to work this way. I write about this in the &lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#managing-app-state&quot;&gt;Managing App State&lt;/a&gt; section of this post.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#what-hmr-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;build-tools&quot;&gt;&lt;p&gt;You do not use all of these tools, you only need to choose one.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#build-tools-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;debugging-event-listeners&quot;&gt;&lt;p&gt;If you like to debug using &lt;code&gt;console.log&lt;/code&gt; statements you are going to run into a bug while debugging like this.  If you run the app, add a &lt;code&gt;console.log&lt;/code&gt; to &lt;code&gt;handle-add-event!&lt;/code&gt; and save you will trigger a reload.  Then, if you click the &lt;code&gt;add&lt;/code&gt; button you will notice that even though you have 2 event listeners attached, only 1  &lt;code&gt;console.log&lt;/code&gt; will fire.  This is because the first event listener has the old &lt;code&gt;handle-add-event!&lt;/code&gt; function without the &lt;code&gt;console.log&lt;/code&gt;.  So it will seem like your only 1 event listeners is firing.  You can verify this again by saving the file, without making changes, and now you should see 2 logs fire.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game-reloadable-code/#debugging-event-listeners-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;p&gt;[along with the code](https://github.com/athomasoriginal/demo-reloadable-code/blob/c87c9b13562856191c3374ffe521c5d97875f281/src/demo_reloadable_code/calendar.cljs#L188&lt;/p&gt;
&lt;/ol&gt;&lt;/aside&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>ClojureScript Test Setup</title>
    <link href="https://betweentwoparens.com/blog/clojurescript-test-setup/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/clojurescript-test-setup/</id>
    <content type="html">&lt;p&gt;This post will walk through how to setup a &lt;code&gt;Test Toolchain&lt;/code&gt; from scratch for a
ClojureScript app.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;When I say &lt;code&gt;Test Toolchain&lt;/code&gt; I mean all the programming tools you need to write,
find, run and report on the tests you write.  Also, if you&#39;re following along
please make sure you have Clojure setup on your local machine.  If you haven&#39;t
done this already, I&#39;ve created a &lt;strong&gt;FREE&lt;/strong&gt; youtube series that will show you
how to &lt;a href=&quot;https://www.youtube.com/watch?v=P60dMljS-OM&amp;amp;list=PLaGDS2KB3-ArG0WqAytE9GsZgrM-USsZA&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Setup Clojure(Script)&lt;/a&gt;.  Furthermore, we won&#39;t be discussing topics
like RDD, best practices etc.  This post is dedicated to understanding &lt;em&gt;how&lt;/em&gt; to
setup a basic &lt;code&gt;Test Toolchain&lt;/code&gt; in ClojureScript using the tools that
ClojureScript provides.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;create-a-project&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#create-a-project&quot;&gt;Create a Project&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Start by creating a basic ClojureScript app.  The easiest way to do this is by
following my &lt;a href=&quot;https://github.com/athomasoriginal/templates&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;templates projects&lt;/a&gt; Quickstart guide.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;&lt;code&gt;templates&lt;/code&gt; a tool which automates the creation of some of my personal
starter projects. Using the &lt;code&gt;Reagent&lt;/code&gt; template, as outlined in the Quickstart
linked above, will get you up and running with a modern ClojureScript app.&lt;/p&gt;
&lt;p&gt;You can think of the above as a lightweight ClojureScript version of
&lt;a href=&quot;https://create-react-app.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;create-react-app&lt;/a&gt;. If you&#39;re curious about the &lt;code&gt;reagent&lt;/code&gt; template generated
you can read all about it in &lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Start a ClojureScript App from Scratch&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Assuming you&#39;re using the &lt;code&gt;templates&lt;/code&gt; tool from above, you would run the
command in the quickstart guide and you should have a project called &lt;code&gt;my-app-name&lt;/code&gt;
which has the following folder structure:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;my-app-name
├── README.md
├── deps.edn
├── dev.cljs.edn
├── prod.cljs.edn
├── resources
│   └── public
│       ├── index.html
│       └── style.css
├── src
│   └── myusername
│       └── my_app_name.cljs
└── &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;
    └── myusername
        └── my_app_name.cljs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, move into the project you just created&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; my-app-name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Install the project&#39;s JS dependencies&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;yarn&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let&#39;s make sure everything is working as expected by running the following
command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M:dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Remember that you should be running the above command from inside the root of
&lt;code&gt;my-app-name&lt;/code&gt;.  Also note that &lt;code&gt;-M&lt;/code&gt; is a flag which is part of &lt;code&gt;Clojure CLI Tools&lt;/code&gt;
version &lt;code&gt;1.10.1.697&lt;/code&gt; or later.  You can check your version of the &lt;code&gt;Clojure CLI Tools&lt;/code&gt; by running &lt;code&gt;clj -h&lt;/code&gt; if you find that &lt;code&gt;-M&lt;/code&gt; doesn&#39;t work.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;If everything worked, a new browser window should automatically open to
&lt;code&gt;http://localhost:9500/&lt;/code&gt; and you should see the following:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/003-sanity-check.png&quot; alt=&quot;screenshot of example hello clojurescript site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I now want to draw your attention to the names of the file and folders:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;├── src
│   └── myusername
│       └── my_app_name.cljs
└── &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;
    └── myusername
        └── my_app_name_test.cljs &lt;span class=&quot;token comment&quot;&gt;# &amp;lt;--- notice the `_test`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&#39;s a convention in Clojure to have your tests mirror your &lt;code&gt;src&lt;/code&gt;
directory structure.  Additionally, when you name the actual files containing
your tests they get suffixed with &lt;code&gt;_test&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;write-a-test&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#write-a-test&quot;&gt;Write a Test&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have a project to work in, let&#39;s write some code and test it!&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;my_app_name.cljs&lt;/code&gt;.  You will notice that some code already exists in this
file.  Delete all the code in the file.  Type the following into the file:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.my-app-name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; add
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;a b&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;+&lt;/span&gt; a b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above is just a simple function which we&#39;ve written so we have something
to test with.  The next step is to write our first test.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;my_app_name_test.cljs&lt;/code&gt;.  Delete all the code in the file. Type the following
into the file.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.my-app-name-test
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cljs.test              &lt;span class=&quot;token symbol&quot;&gt;:refer-macros&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;deftest is&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;myusername.my-app-name &lt;span class=&quot;token symbol&quot;&gt;:as&lt;/span&gt; my-app-name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deftest&lt;/span&gt; test-add-function
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;my-app-name/add&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Notice that we did not have to add &lt;code&gt;cljs.test&lt;/code&gt; as a dependency in our project.
This is because &lt;code&gt;cljs.test&lt;/code&gt; &lt;a href=&quot;https://clojurescript.org/tools/testing&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;comes with ClojureScript&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Let&#39;s review the test we just wrote.  &lt;code&gt;cljs.test&lt;/code&gt; is a small library with
everything you need to test ClojureScript code&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#cljs-test&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;cljs-test-ref&quot;&gt;.&lt;/a&gt;  Among other things,
it comes with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Test Decleration Utils&lt;/strong&gt; e.g. &lt;code&gt;deftest&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;deftest&lt;/code&gt; let&#39;s us define a test. In our example, we defined a test called &lt;code&gt;test-add-function&lt;/code&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#test-add-fn&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;test-add-fn-ref&quot;&gt;.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Assertion Library&lt;/strong&gt; e.g. &lt;code&gt;is&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;is&lt;/code&gt; is a convenience wrapper around a &lt;code&gt;try-catch&lt;/code&gt; block&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test Runner&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;we haven&#39;t introduced this to you yet, but it&#39;s called &lt;code&gt;run-tests&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have written a test, the next section will show you how to run
the test.&lt;/p&gt;
&lt;h2 id=&quot;run-tests-with-cljs-main&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#run-tests-with-cljs-main&quot;&gt;Run tests with cljs-main&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To run our tests, we need to create a namespace that will import all of our
tests and then run them.  We can refer to this namespace as our &lt;code&gt;test_runner&lt;/code&gt;,
but you can also think of it as the &lt;code&gt;test entrypoint&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Start by creating a new file in &lt;code&gt;test/myusername&lt;/code&gt;.  Call this file
&lt;code&gt;test_runner.cljs&lt;/code&gt;.  Open &lt;code&gt;test_runner.cljs&lt;/code&gt; and type the following into it:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.test-runner
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cljs.test &lt;span class=&quot;token symbol&quot;&gt;:refer-macros&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;run-tests&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run-tests&lt;/span&gt; &#39;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What the above does is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import our test namespaces e.g. &lt;code&gt;myusername.my-app-name-test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run all of our rests by calling &lt;code&gt;run-tests&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have a file which knows how to run our tests, we need a command in
our app which we call to run the tests.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;deps.edn&lt;/code&gt; file.  Type the following new alias into the file:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;;; ...&lt;/span&gt;

&lt;span class=&quot;token symbol&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--main&quot;&lt;/span&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;cljs.main&quot;&lt;/span&gt;
                   &lt;span class=&quot;token string&quot;&gt;&quot;--compile&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;myusername.test_runner&quot;&lt;/span&gt;
                   &lt;span class=&quot;token string&quot;&gt;&quot;--repl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above is using &lt;code&gt;cljs.main&lt;/code&gt; (ClojureScript tools) to run the tests.  We will
show you later how to run the tests with figwheel.  For now though, I feel it&#39;s
valuable to show you how to start from scratch.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;From here, we just have to run the tests.  To do this, go to your terminal and
run the test alias:&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you haven&#39;t stopped the previous running instance of your app, please do
that before running the following command.&lt;/p&gt;
&lt;/aside&gt;&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;clj -M:test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What the above alias is going to do is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;compile your &lt;code&gt;cljs&lt;/code&gt; to &lt;code&gt;js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;automatically open your app in your default browser&lt;/li&gt;
&lt;li&gt;render the default ClojureScript &lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;run the tests in the browser&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But you will notice that you won&#39;t see the tests anywhere. So, what happened?
Your test &lt;code&gt;report&lt;/code&gt; or &lt;code&gt;output&lt;/code&gt; won&#39;t be found in the browser, rather, you will
find it in your terminal and will look something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-text&quot;&gt;&lt;code class=&quot;bride-code-text&quot;&gt;➜ clj -M:test
ClojureScript 1.11.60
cljs.user=&gt;
Testing myusername.my-app-name-test

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You will see the tests run in the terminal only when the REPL has connected to
browser.  Sometimes this doesn&#39;t happen automatically so you can try to make it
happen by refreshing the browser window.  Or, remove the &lt;code&gt;--repl&lt;/code&gt; in the
alias and just manually open the page http://localhost:9000&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Note that you could also have the &lt;code&gt;test report&lt;/code&gt; displayed in your browser
console by adding &lt;code&gt;(enable-console-print!)&lt;/code&gt; in your &lt;code&gt;test-runner&lt;/code&gt; namespace
before you invoke &lt;code&gt;run-tests&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.test-runner
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cljs.test &lt;span class=&quot;token symbol&quot;&gt;:refer-macros&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;run-tests&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;enable-console-print!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; new&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run-tests&lt;/span&gt; &#39;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cancel out of the &lt;code&gt;clj -M:test&lt;/code&gt; process in your terminal.  Run &lt;code&gt;clj -M:test&lt;/code&gt;
again.  Check the browser console and you should see the tests logged there
as well.&lt;/p&gt;
&lt;p&gt;Note that it&#39;s pretty cumbersome to have to stop and re-run tests all the time.
Instead, we can tell ClojureScript to watch the &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; directory so
that every time you update files in your &lt;code&gt;src&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt; dir they will
automatically be recompiled on save.  To make this happen, update your
&lt;code&gt;:test&lt;/code&gt; alias to look like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-m&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;cljs.main&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-w&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;src:test&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; new&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-c&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;myusername.test_runner&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Notice that we use a colon between &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;.  This is called a
path-separator and it&#39;s how you can tell ClojureScript to watch multiple
directories.  Also note that this path-separator is &lt;code&gt;system-dependent&lt;/code&gt;.  This
means that this will only work on mac and linux.  However, if you want to make
this work on windows try replacing &lt;code&gt;:&lt;/code&gt; with &lt;code&gt;;&lt;/code&gt;.  For example, &lt;code&gt;src;test&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;And that&#39;s everything involved in setting up a ClojureScript only &lt;code&gt;Test Toolchain&lt;/code&gt;.  For those who want to take it a step further, let&#39;s see how we can
configure &lt;code&gt;figwheel&lt;/code&gt; to run these tests.&lt;/p&gt;
&lt;h2 id=&quot;run-tests-with-figwheel&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#run-tests-with-figwheel&quot;&gt;Run tests with figwheel&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Because we are using the &lt;code&gt;templates&lt;/code&gt; reagent template, we have everything we
need to run our tests using &lt;code&gt;figwheel&lt;/code&gt;.  In fact, most everything we needed from
the previous section will be used in this section with a few changes.  As you
will see, one awesome feature of using figwheel for testing is you get more
tooling, with less configuration.&lt;/p&gt;
&lt;p&gt;To recap, we already have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;test runner&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only thing we have to change is a small piece of our test runner.  Open up
&lt;code&gt;test_runner.cljs&lt;/code&gt; and update the following&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.test-runner
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cljs-test-display.core&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; new&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;figwheel.main.testing &lt;span class=&quot;token symbol&quot;&gt;:refer-macros&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;run-tests&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; new&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run-tests&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cljs-test-display.core/init!&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;app-testing&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; updated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Notice that we are using &lt;code&gt;run-tests&lt;/code&gt; from &lt;code&gt;figwheel&lt;/code&gt;.  This is a convenience
function provided by &lt;code&gt;figwheel&lt;/code&gt; and as we will see does more than &lt;code&gt;run-test&lt;/code&gt;
provided by &lt;code&gt;cljs.test&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The next step is to open your &lt;code&gt;dev.cljs.edn&lt;/code&gt; file and add a &lt;code&gt;:extra-main-files&lt;/code&gt; key set like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:auto-bundle&lt;/span&gt;      &lt;span class=&quot;token symbol&quot;&gt;:webpack&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:watch-dirs&lt;/span&gt;       &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; updated&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:css-dirs&lt;/span&gt;         &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:extra-main-files&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:testing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main&lt;/span&gt; myusername.test-runner&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;; new&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main&lt;/span&gt; myusername.my-app-name&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What the above does is build and run your tests, like we did with the &lt;code&gt;:test&lt;/code&gt;
alias in the previous section.&lt;/p&gt;
&lt;p&gt;The difference is that we are going to do this as part of our &lt;code&gt;:dev&lt;/code&gt; alias.
This is great because it means we have a single file watcher and HMR process
runing in the same process as our development build. So now, we can develop
our app and tests at the same time in one simple command.&lt;/p&gt;
&lt;p&gt;To run the above:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-shell&quot;&gt;&lt;code class=&quot;bride-code-shell&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M:dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you can visit your app at &lt;code&gt;http://localhost:9500&lt;/code&gt; and your tests at
&lt;code&gt;http://localhost:9500/figwheel-extra-main/testing&lt;/code&gt;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;When you visit &lt;code&gt;http://localhost:9500&lt;/code&gt; it will be blank.  This is expected
because you only have an &lt;code&gt;add&lt;/code&gt; function in your ClojureScript app.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;When you visit &lt;code&gt;localhost:9500/figwheel-extra-main/testing&lt;/code&gt; you should see
something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/003-figwheel-testing.png&quot; alt=&quot;screenshot of figwheel test runner&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The above is a graphical version of the textual &lt;code&gt;test report&lt;/code&gt; that we got when
we ran the tests using &lt;code&gt;cljs.test&lt;/code&gt;.  From here, you can modify your code and
your &lt;code&gt;figwheel-extra-main/testing&lt;/code&gt; will not only rebuild, but live update
creating a nice developer experience.&lt;/p&gt;
&lt;h2 id=&quot;runtime-environments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#runtime-environments&quot;&gt;Runtime Environments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Up until now, we haven&#39;t discussed &lt;code&gt;Runtime Environments&lt;/code&gt;.  &lt;code&gt;Runtime Environments&lt;/code&gt;
are important because they impact your test results.&lt;/p&gt;
&lt;p&gt;When we ask which &lt;code&gt;runtime environment&lt;/code&gt; our JS code is running in we want to know
if it&#39;s running in a browser or server environment.  Then, we also need to know
which browser (Safari, Chrome, Firefox) or server environment (Node, Dino, Bun)
our code is specifically running in.&lt;/p&gt;
&lt;p&gt;Right now, if you run your code like we did in the &lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#run-tests-with-cljs-main&quot;&gt;run tests with cljs.main&lt;/a&gt;
section, your code will be run in a &lt;code&gt;Browser Environment&lt;/code&gt;.  If you were to set
&lt;code&gt;--repl-env&lt;/code&gt; to &lt;code&gt;node&lt;/code&gt; then your code would be run in a &lt;code&gt;Node Environment&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Making sure we&#39;re testing against the right environments is important because
the behavior and APIs made available to you will change based on the environment
your code&#39;s run in.&lt;/p&gt;
&lt;p&gt;For example, you won&#39;t have the &lt;code&gt;window&lt;/code&gt; object in &lt;code&gt;Node&lt;/code&gt;, so it wouldn&#39;t be a
good idea to test your browser code in a Node server environment.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Yes, you can test some code that&#39;s agnostic of the environment, but in general,
test your code where you expect it to run&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Another consideration is test performance. As it turns out, it&#39;s not always
desirable or possible to test your browser code directly in the browser.  For
example, you may run into a scenario where you want to run your code in your
CI/CD process.  When this is the case, you will want to
setup a &lt;code&gt;Headless Browser Runtime Environment&lt;/code&gt;.  The following section will
show you how to do this.&lt;/p&gt;
&lt;h3 id=&quot;headless-browser-runtime-environment&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#headless-browser-runtime-environment&quot;&gt;Headless Browser Runtime Environment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This section is going to illustrate how to run your ClojureScript tests using headless
chrome.&lt;/p&gt;
&lt;p&gt;This is something we want to configure so we can run our tests as part of our
CI/CD process.&lt;/p&gt;
&lt;p&gt;The reason we do this is because in CI/CD we don&#39;t need a browser GUI.  The GUI
is slow and uses more computer resources.  For this reason, we configure our tests
to run in a headless environment.  Here are some example of headless JS environments&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;headless chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.nightmarejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Nightmare&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChrome/puppeteer&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Puppeteer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jsdom/jsdom&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;jsdom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For our purposes I use &lt;a href=&quot;https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;headless chrome&lt;/a&gt; which is Chrome without the GUI.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;I choose &lt;code&gt;headless chrome&lt;/code&gt; as this causes less issues compared to JSDOM which
I originally used.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The following sub-sections will walk through the steps required to setup this
environment and teach figwheel to execute your tests inside of it.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;housekeeping: ensure you have &lt;a href=&quot;https://yarnpkg.com/en/docs/getting-started&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;yarn&lt;/a&gt; and &lt;a href=&quot;https://nodejs.org/en/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;node&lt;/a&gt; installed before continuing.
You can also swap out &lt;code&gt;yarn&lt;/code&gt; for &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h4&gt;Step 1 Setup A Headless Test Runner&lt;/h4&gt;
&lt;p&gt;Open &lt;code&gt;test_runner.cljs&lt;/code&gt;.  Make it match the following:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; myusername.test-runner
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;figwheel.main.testing &lt;span class=&quot;token symbol&quot;&gt;:refer-macros&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;run-tests-async&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;; tests here&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;myusername.my-app-name-test&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; -main &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&amp;amp; args&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run-tests-async&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Step 2 Add a test config&lt;/h4&gt;
&lt;p&gt;Create a new file in the root of &lt;code&gt;my-app-name&lt;/code&gt; called &lt;code&gt;test.headless.cljs.edn&lt;/code&gt;. Open
&lt;code&gt;test.headless.cljs.edn&lt;/code&gt; and type the following into it:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:auto-bundle&lt;/span&gt;         &lt;span class=&quot;token symbol&quot;&gt;:webpack&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:ring-server-options&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:port&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9504&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main&lt;/span&gt;            myusername.test-runner
 &lt;span class=&quot;token symbol&quot;&gt;:infer-externs&lt;/span&gt;   &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
 &lt;span class=&quot;token symbol&quot;&gt;:output-dir&lt;/span&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;target/public/cljs-out&quot;&lt;/span&gt;
 &lt;span class=&quot;token symbol&quot;&gt;:output-to&lt;/span&gt;       &lt;span class=&quot;token string&quot;&gt;&quot;target/public/cljs-out/main.js&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Step 3 Configure Figwheel&lt;/h4&gt;
&lt;p&gt;Open &lt;code&gt;deps.edn&lt;/code&gt; and add a &lt;code&gt;:test-headless&lt;/code&gt; alias:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;test&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  com.bhauman/figwheel-main  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.18&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  reagent                    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:aliases&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:dev&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-m&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;figwheel.main&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--build&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dev&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--repl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token symbol&quot;&gt;:test-headless&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;; new alias&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;--main&quot;&lt;/span&gt;         &lt;span class=&quot;token string&quot;&gt;&quot;figwheel.main&quot;&lt;/span&gt;
               &lt;span class=&quot;token string&quot;&gt;&quot;--compile-opts&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;test.headless.cljs.edn&quot;&lt;/span&gt;
               &lt;span class=&quot;token string&quot;&gt;&quot;--fw-opts&quot;&lt;/span&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;{:launch-js [&#92;&quot;/Applications/Google Chrome.app/Contents/MacOS/Google Chrome&#92;&quot; &#92;&quot;--headless&#92;&quot; &#92;&quot;--remote-debugging-port=9222&#92;&quot; :open-url]}&quot;&lt;/span&gt;
               &lt;span class=&quot;token string&quot;&gt;&quot;--main&quot;&lt;/span&gt;         &lt;span class=&quot;token string&quot;&gt;&quot;myusername.test-runner&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The &lt;code&gt;launch-js&lt;/code&gt; is going to run a headless chrome.  This path is specific to
macos.  You will have to change it based on your environment e.g. Windows, Linux
etc.  As a result, you will have mulitple &lt;code&gt;test-headless&lt;/code&gt; aliases based on
environment.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;That&#39;s it.  We are ready to run our headless browser testing setup.  Try it out
by running &lt;code&gt;clj -M:test-headless&lt;/code&gt; in your terminal.&lt;/p&gt;
&lt;p&gt;If it all worked you should see something like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;

Testing myusername.my-app-name-test

Ran &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; tests containing &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; assertions.
&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; failures, &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; errors.
:figwheel.main.testing/success
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&#39;re going to notice that you have to re-run this every time you want to run
your headless tests.  This is to be expected. The thing with this approach is
that we have only really configured it to be run by our CI environment and also
as a quick sanity check for newcomers to our project.  Could we make it do
more?  Yup!  You can take this and connect it to &lt;code&gt;figwheel&lt;/code&gt;&#39;s file watching
mechanism and have it behave exactly like the browser testing setup.&lt;/p&gt;
&lt;h2 id=&quot;alternative-tools&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#alternative-tools&quot;&gt;Alternative Tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Up until now, i&#39;ve shown you only &lt;code&gt;cljs.test&lt;/code&gt;.  The reason is because it&#39;s simple,
does what we need and means we don&#39;t have to pull in more deps.&lt;/p&gt;
&lt;p&gt;Having said this, you might want more features.  That&#39;s totally understandable
and possible with this setup. Part of the reason I broke down &lt;code&gt;cljs.test&lt;/code&gt;
into smaller groups of functionality like &lt;code&gt;assertion library&lt;/code&gt;, &lt;code&gt;test definitions&lt;/code&gt;,
&lt;code&gt;test reporting&lt;/code&gt; and &lt;code&gt;test runner&lt;/code&gt; is because it helps you see that you&#39;re not
looking to replace everything, but maybe just a small piece of something.&lt;/p&gt;
&lt;p&gt;Now that we know what some of these pieces are you should be in a position to
replace them if you need to.  With this in mind, here are some alternatives you
can consider if you want to experiment with different tools.&lt;/p&gt;
&lt;p&gt;To replace your assertion libraries and test definitions these are some popular
libraries in Clojure(Script)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/clojure-expectations/expectations&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;expectation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/metosin/testit&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;testit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/marick/Midje&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;midje&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jimpil/fudje&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;fudje&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For now I recommend sticking with &lt;code&gt;cljs.test&lt;/code&gt; and then look into one of the
above when/if the need arises.&lt;/p&gt;
&lt;p&gt;And replacements for &lt;code&gt;test-runners&lt;/code&gt; and &lt;code&gt;test reporters&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/weavejester/eftest&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;eftest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/lambdaisland/kaocha&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;kaocha&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;What about a tool like &lt;a href=&quot;https://github.com/bensu/doo&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;doo&lt;/a&gt;? See the footnote&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#doo-runner&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;doo-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal here was to layout some context.  Point you to tools and explore how
and what to configure in your tooling for testing ClojureScript.  From here,
play with the setup, see how far it takes you and run with it.  Here are some
other resources you might be interested in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hub.packtpub.com/testing-your-application-cljstest/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Testing Your Application - CLJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://figwheel.org/docs/testing.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Figwheel Testing Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/goldbergyoni/javascript-testing-best-practices&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;JavaSCript and Node Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, there is no &amp;quot;right&amp;quot; or &amp;quot;wrong&amp;quot; testing tool.  Start.  Figure out what
works and what doesn&#39;t work and then iterate.&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;cljs-test&quot;&gt;&lt;p&gt;It is also maintained by the ClojureScript core team you can feel confident that it is a healthy tool to use.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#cljs-test-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;test-add-fn&quot;&gt;&lt;p&gt;You can name the test anything you like. There are many idiomatic conventions for this so I recommend you do a little research into naming/structuring tests and find one that aligns with your sensibilities.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#test-add-fn-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;doo-runner&quot;&gt;&lt;p&gt;I have used doo in production apps and have found that this tool is not as useful as I would like it to be.  You may here it recommended, but I believe these are based on what used to be available, which was not nearly as much as of now (2019-2020).&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/clojurescript-test-setup/#doo-runner-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>What the Reagent Component?!</title>
    <link href="https://betweentwoparens.com/blog/what-the-reagent-component/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/what-the-reagent-component/</id>
    <content type="html">&lt;p&gt;Did you know that when you write a &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-1-a-simple-function&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;form-1&lt;/a&gt;, &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-2--a-function-returning-a-function&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;form-2&lt;/a&gt; or &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#form-3-a-class-with-life-cycle-methods&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;form-3&lt;/a&gt; Reagent component they all default&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#reagent-default-class&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;reagent-default-class-ref&quot;&gt;&lt;/a&gt; to becoming React &lt;code&gt;class components&lt;/code&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#reagent-components&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;reagent-components-ref&quot;&gt;?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For example, if you were to write this &lt;code&gt;form-1&lt;/code&gt; Reagent component:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; welcome &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, friend&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By the time Reagent passes it to React it would be the equivalent of you writing this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; friend&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;To be clear, Reagent components do not turn into &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ES6 class syntax&lt;/a&gt;.  This is just an illustrative tool because ES6 classes are rapidly becoming more common than the alternative forms of writing classes that we shall see later in this post.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Okay, so, Reagent components become React &lt;code&gt;Class Components&lt;/code&gt;. Why do we care? This depth of understanding is valuable because it means we can better understand:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript, ES6 classes and the idea behind &amp;quot;syntax sugar&amp;quot;&lt;/li&gt;
&lt;li&gt;React&#39;s strategy for &lt;a href=&quot;https://overreacted.io/how-does-react-tell-a-class-from-a-function/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;distinguishing class and function components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How ClojureScript interacts with JavaScript&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result of all of this &amp;quot;fundamental&amp;quot; learning is we can more effectively harness JavaScript from within ClojureScript.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;I assume readers have a level of familiarity with ClojureScript, JavaScript and React. Please also note that understanding Reagent at this level is not required to be productive in Reagent.  Finally, as of &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/CHANGELOG.md#100-alpha2-2020-05-13&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Reagent 1.0.0&lt;/a&gt; Reagent is capable of allowing developers to choose whether they want their components to be &lt;code&gt;class&lt;/code&gt; or &lt;code&gt;function&lt;/code&gt; components.  When this post was originally written, this was not possible and for many in the community it was an assumption that might have gone unnoticed.  None the less, the learnings here are still important!  So, the rest of this post is assuming that you have NOT enabled Reagent components to render as &lt;code&gt;function&lt;/code&gt; components.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;a-pseudoclassical-pattern&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#a-pseudoclassical-pattern&quot;&gt;A Pseudoclassical Pattern&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The reason all of your Reagent components become &lt;code&gt;class components&lt;/code&gt; is because
all of the code you pass to Reagent is run through an internal Reagent function
called &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/88e9833be9c3135548d760286ffd84d88a0a0489/src/reagent/impl/component.cljs#L289&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;create-class&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;create-class&lt;/code&gt; is interesting because of how it uses JavaScript to
transform a Reagent component into something that is recognized as a React
class component.  Before we look into what &lt;code&gt;create-class&lt;/code&gt; is doing, it&#39;s
helpful to review how &amp;quot;classes&amp;quot; work in JavaScript.&lt;/p&gt;
&lt;p&gt;Prior to ES6, JavaScript did not have classes&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#javascript-es6-classes&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;javascript-es6-classes-ref&quot;&gt;.&lt;/a&gt;
and this made &lt;em&gt;some&lt;/em&gt; JS developers sad because classes are a common pattern used
to structure code and provide support for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;instantiation&lt;/li&gt;
&lt;li&gt;inheritance&lt;/li&gt;
&lt;li&gt;polymorphism&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But as I said, prior to ES6, JavaScript didn&#39;t have a formal syntax for &amp;quot;classes&amp;quot;.
To compensate for the lack of classes, the JavaScript community got creative
and developed a &lt;a href=&quot;http://nick.balestra.ch/2015/classes-and-instantiation-patterns-in-javascript/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;series of instantiation patterns&lt;/a&gt; to help &lt;em&gt;simulate&lt;/em&gt; classes.&lt;/p&gt;
&lt;p&gt;Of all of these patterns, the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; became one of the most popular ways to simulate a class in JavaScript.  This is evidenced by the fact that many of the &amp;quot;first generation&amp;quot; JavaScript libraries and frameworks, like &lt;a href=&quot;https://developers.google.com/closure/library/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;google closure library&lt;/a&gt; and &lt;a href=&quot;https://backbonejs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;backbone&lt;/a&gt;, are written in this style.&lt;/p&gt;
&lt;p&gt;The reason we are going over this history is because the thing about a programming language is there are &amp;quot;patterns&amp;quot; and &amp;quot;syntax&amp;quot;.  The challenge with &amp;quot;patterns&amp;quot; is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They&#39;re disseminated culturally (tribal knowledge)&lt;/li&gt;
&lt;li&gt;They&#39;re difficult to identify&lt;/li&gt;
&lt;li&gt;They&#39;re &lt;em&gt;often&lt;/em&gt; difficult to search&lt;/li&gt;
&lt;li&gt;They &lt;em&gt;often&lt;/em&gt; require a deeper knowledge to understand how and why to use a pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point in praticular is relevant to our conversation because patterns
live in a context and assume prior knowledge. Knowledge like how well we know the
context of a problem, the alternative approaches to addressing a problem,
advancements in a language and so on.&lt;/p&gt;
&lt;p&gt;The end result is that a pattern can just become a thing we do.  We can
forget or never know why it started in the first place or what the world could
look like if we chose a different path.&lt;/p&gt;
&lt;p&gt;For example, the most common way of writing a React class component is to use ES6 class syntax.  But did you know that ES6 class syntax is little more than syntactic sugar around the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;For example, you can write a valid React class component using the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1. define a function (component) called `Welcome`&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 2. connect `Welcome` to the `React.Component` prototype&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 3. re-define the `constructor`&lt;/span&gt;
Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;constructor&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;enumerable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;writable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;configurable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Welcome&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 4. define your React components `render` method&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Reagent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h2&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;While the above is a valid React &lt;code&gt;Class Component&lt;/code&gt;, it&#39;s also verbose and error prone.  For these reasons JavaScript introduced ES6 classes to the language:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Reagent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;h1&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Yup, ES6 class syntax is a sexier &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; and also a good example of what developers mean when they say &lt;code&gt;syntactic sugar&lt;/code&gt;.  I should also mention that there are &lt;em&gt;some&lt;/em&gt; differences between the two approaches listed above which means they are not 100% equivalent, but for most developers the differences are academic.  &lt;strong&gt;Fun time bonus:&lt;/strong&gt; I encourage you checkout &lt;a href=&quot;https://codesandbox.io/s/pseudoclassical-instantiation-pattern-sc0fk&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;this code sandbox&lt;/a&gt; where I have setup live examples of both.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;For those looking for further evidence, we can support our claim that &lt;code&gt;ES6 Classes&lt;/code&gt; result in same thing as what the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; produces by using JavaScript&#39;s built-in introspection tools to compare the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; to the &lt;code&gt;ES6 class&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pseudoclassical instantiation pattern&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// ...repeat steps 2 - 4 from above before completing the rest&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; welcome &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;ES6 class&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ES6 Inheritance&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; welcome &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;

&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What does all of this mean?  As far as JavaScript and React are concerned, both definions of the &lt;code&gt;Welcome&lt;/code&gt; component are valid React &lt;code&gt;Class Components&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this in mind, lets look at Reagent&#39;s &lt;code&gt;create-class&lt;/code&gt; function and see what it does.&lt;/p&gt;
&lt;h2 id=&quot;what-reagent-does&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#what-reagent-does&quot;&gt;What Reagent Does&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The history lesson from the above section is important because &lt;code&gt;create-class&lt;/code&gt; uses a modified version of the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt;.  Let&#39;s take a look at what we mean.&lt;/p&gt;
&lt;p&gt;The following code sample is a simplified version of Reagent&#39;s &lt;code&gt;create-class&lt;/code&gt; function:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; updater&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

goog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; classMethods&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

goog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; staticMethods&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;I ported the CLJS code to JS above because it should make it easier to examine
what the code is actually doing without adding the overhead of transcribing
CLJS to JS&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;What we have above is Reagents take on the &lt;code&gt;pseudoclassical instantiation pattern&lt;/code&gt; with a few minor tweaks:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 1. we copy to properties + methods of React.Component&lt;/span&gt;
goog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; classMethods&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

goog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; staticMethods&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 2. the constructor is not as &quot;thorough&quot;&lt;/span&gt;
cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Exploring point 1 we see that Reagent has opted to copy the &lt;code&gt;properties&lt;/code&gt; and &lt;code&gt;methods&lt;/code&gt; of &lt;code&gt;React.Component&lt;/code&gt; directly to the Reagent compnents we write.  That is what&#39;s happening here:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;goog&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; classMethods&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we were using the the traditional &lt;code&gt;pseudoclassical&lt;/code&gt; approach we would instead do this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thus, the difference is that Reagent&#39;s approach copies all the methods and properties from &lt;code&gt;React.Component&lt;/code&gt; to the &lt;code&gt;cmp&lt;/code&gt; prototype where as the second approach is going to &lt;code&gt;link&lt;/code&gt; the &lt;code&gt;cmp&lt;/code&gt; prototype to &lt;code&gt;React.component&lt;/code&gt; prototype.  The benefit of linking is that each time you instantiate a &lt;code&gt;Welcome&lt;/code&gt; component, the &lt;code&gt;Welcome&lt;/code&gt; component does not need to re-create all of the &lt;code&gt;React.components&lt;/code&gt; methods and properties.&lt;/p&gt;
&lt;p&gt;Exploring the second point, Reagent is doing this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;cmp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constructor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;whereas with the traditional &lt;code&gt;pseudoclassical&lt;/code&gt; approach we would instead do this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;constructor&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;enumerable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;writable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;configurable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Welcome&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The difference in the above approaches is that if we just use &lt;code&gt;=&lt;/code&gt; as we are doing in the Reagent version we create an &lt;code&gt;enumerable&lt;/code&gt; constructor.  This can have an implication depending on who consumes our classes, but in our case we know that only React is going to be consuming our class components, so we can do this with relative confidence.&lt;/p&gt;
&lt;p&gt;What is one of the more interesting results of the above two Reagent modifications?  First, if React depended on JavaScript introspection to tell whether or not a component is a child of &lt;code&gt;React.Component&lt;/code&gt; we would not be happy campers:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-javascript&quot;&gt;&lt;code class=&quot;bride-code-javascript&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; false...Welcome is not a child of React.Component&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; false...React.component is not part of Welcomes prototype chain&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; false...Welcome is not an instance of React.Component&lt;/span&gt;

welcome &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true...welcome is a child of Welcome&lt;/span&gt;

Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype
&lt;span class=&quot;token comment&quot;&gt;// =&gt; true...welcome is linked to Welcome prototype&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// =&gt; false...React.Component not linked to the prototype of React.Component&lt;/span&gt;

console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isPrototypeOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;welcome&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// is Welcome is the ancestory?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What the above shows is that &lt;code&gt;Welcome&lt;/code&gt; is not a child of &lt;code&gt;React.component&lt;/code&gt; even though it has all the properties and methods that &lt;code&gt;React.Component&lt;/code&gt; has.  This is why were lucky that React is smart about detecting &lt;a href=&quot;https://overreacted.io/how-does-react-tell-a-class-from-a-function/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;class vs. function components&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Second, by &lt;code&gt;copying&lt;/code&gt; rather than &lt;code&gt;linking&lt;/code&gt; prototypes we could inccur a
performance cost. How much of a performance hit?  In our case this cost is likely
negligible.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;For those who want to know why the Reagent team chose to modify the
pseudoclassical instantiation pattern the &lt;a href=&quot;https://github.com/reagent-project/reagent/pull/437#issuecomment-520943315&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;official response&lt;/a&gt; from the current
maintainer of the Reagent to this post from the current maintainer of the
Reagent to this post.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my experience, digging into the weeds and going on these detours
has been an important part of my growth as a developer. The weeds have allowed
me to be a better programmer because I&#39;m honing my ability to understand
challenging topics and find answers.  The result is a strange feeling of calm
and comfort.&lt;/p&gt;
&lt;p&gt;This calm and comfort shouldn&#39;t be overlooked.  So much of our day-to-day is
left unquestioned and unanalyzed.  We let knowledge become &amp;quot;cultural&amp;quot; or
&amp;quot;tribal&amp;quot;. This is scary. It&#39;s scary because it leads to bad decisions because no one around us
knows the whys or wherefores.  Ultimately, it&#39;s a bad habit.  A bad habit which is seen
by some as a virtue because it would simply take too much time for to learn
things ourselves.  That&#39;s until you actually start doing this kind of work
and spend time learning and observing and seeing that these &amp;quot;new things&amp;quot;
we&#39;re seeing all the time aren&#39;t really new, but just another example
of that old thing back.&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;reagent-default-class&quot;&gt;&lt;p&gt;I say &amp;quot;default&amp;quot; because prior to &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/CHANGELOG.md#100-2020-12-21&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;reagent 1.0&lt;/a&gt; you did not have a choice between class or function components.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#reagent-default-class-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;reagent-components&quot;&gt;&lt;p&gt;This is &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md#final-note&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;briefly touched on&lt;/a&gt; in Reagents component guide but they do not explicitly use the words &lt;code&gt;React class component&lt;/code&gt; which means that it is easy to miss the implication of this point. Hence this blog post.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#reagent-components-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;javascript-es6-classes&quot;&gt;&lt;p&gt;It is important to note that even with ES6 class syntax JavaScript still does not have classes in the traditional sense.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/what-the-reagent-component/#javascript-es6-classes-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>Start a ClojureScript App from Scratch</title>
    <link href="https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/</id>
    <content type="html">&lt;p&gt;In this post we&#39;ll walk through my approach to setting up a &lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#clojurescript-spelling&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;clojurescript-spelling-ref&quot;&gt;Clojure(Script)&lt;/a&gt; app from scratch.
My ultimate goal is to help alleviate the nagging perectionist feelings we get
when starting new projects.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you happen to get stuck along the way, I have a &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;demo project&lt;/a&gt; which you can
reference.  Furthmore, while we aren&#39;t writing much ClojureScript in this post,
feel free to reference this &lt;a href=&quot;https://github.com/shaunlebron/ClojureScript-Syntax-in-15-minutes&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;15 minute primer to the syntax of Clojure&lt;/a&gt;. And
finally, if you&#39;re more of a visual learner I have a Youtube playlist called
&lt;a href=&quot;https://youtube.com/playlist?list=PLaGDS2KB3-ArG0WqAytE9GsZgrM-USsZA&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Getting Started with Clojure(Script)&lt;/a&gt; which goes over all the topics in this
post and more!&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;If you plan on following along with this post, please be sure to have Clojure
installed and working.  Not sure?  Want to know how?  I recommend taking a look
at my free &lt;a href=&quot;https://youtube.com/playlist?list=PLaGDS2KB3-ArG0WqAytE9GsZgrM-USsZA&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Getting Started with Clojure(Script)&lt;/a&gt; Youtube series which will
take you through the whole process or checkout the official written
&lt;a href=&quot;https://clojurescript.org/guides/quick-start&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ClojureScript Quickstart Guide&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;setup-project-structure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#setup-project-structure&quot;&gt;Setup Project Structure&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section covers the file &amp;amp; folder structure of our application: What goes
where and why.&lt;/p&gt;
&lt;p&gt;To start a new project we need a name.  In Clojure/Script the
convention is to combine your &amp;quot;company&amp;quot; and &amp;quot;project&amp;quot; name.  For example, if we
worked for &lt;em&gt;Nike&lt;/em&gt; and we&#39;re building an app called &lt;em&gt;Fit Queens&lt;/em&gt; then our app
structure would look like &lt;code&gt;src/nike/fit_queens.cljs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For the demo code in this post, we&#39;ll pretend our company name is &lt;code&gt;tallex&lt;/code&gt; and
the app is called &lt;code&gt;time dive&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With this in mind, let&#39;s get to step 1: create your projects files and folders!&lt;/p&gt;
&lt;h3 id=&quot;step-1---add-the-files-and-folders&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-1---add-the-files-and-folders&quot;&gt;Step 1 - Add the Files and Folders&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start by creating each file and folder exactly as seen below&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#project-structure&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;project-structure-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
├── README.md
├── resources
│   ├── index.html
│   └── style.css
├── src
│   └── tallex
│       └── time_dive.cljs
└── tests
    └── tallex
        └── time_dive_tests.cljs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Notice how the files and folders in the &lt;code&gt;src&lt;/code&gt; and &lt;code&gt;tests&lt;/code&gt; dirs have underscores
in their names?  This is a naming convention called &lt;a href=&quot;https://en.wikipedia.org/wiki/Snake_case&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;snake case&lt;/a&gt;. In Clojure and
ClojureScript you&#39;re required to follow this convention when naming files and
folders because Clojure/Script is a JVM hosted language which means we have to
follow &lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Java conventions&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-2---add-html&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-2---add-html&quot;&gt;Step 2 - Add HTML&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add some HTML so when the page renders we see something.  All web apps start
with an HTML file. Think of &lt;code&gt;HTML&lt;/code&gt; as the  &amp;quot;bones&amp;quot; of your web app.&lt;/p&gt;
&lt;p&gt;Open your &lt;code&gt;index.html&lt;/code&gt; file and add the following&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#resources-dir&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;resources-dir-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-html&quot;&gt;&lt;code class=&quot;bride-code-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Time Dive&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site__title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site__title-text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Time Dive&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/out/main.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above will connect our &lt;code&gt;css&lt;/code&gt;, &lt;code&gt;js&lt;/code&gt; and render our app name &lt;em&gt;Time Dive&lt;/em&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-3---add-css&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-3---add-css&quot;&gt;Step 3 - Add CSS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we can write some &lt;code&gt;CSS&lt;/code&gt;. Open the &lt;code&gt;style.css&lt;/code&gt; file and add these
styles&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-css&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-css-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-css&quot;&gt;&lt;code class=&quot;bride-code-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--color-purple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;197&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 18&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 193&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--color-pink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;241&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Arial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.site__title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.site__title-text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;-webkit-linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    34deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-purple&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-pink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-text-fill-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The above is our &lt;code&gt;css&lt;/code&gt;.  It will make our app name &lt;em&gt;Time Dive&lt;/em&gt; look pretty when
it renders on the screen.  All of this is optional, but a valuable sanity check
to make sure that our CSS is working as we expect.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-4---add-clojurescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-4---add-clojurescript&quot;&gt;Step 4 - Add ClojureScript&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now let&#39;s write some ClojureScript. Open &lt;code&gt;time_dive.cljs&lt;/code&gt; and type the following
code&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-cljs&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-cljs-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; tallex.time-dive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;js/console.log&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, Time Dive!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above tells Clojure/Script you&#39;re creating a &lt;code&gt;namespace&lt;/code&gt; called
&lt;code&gt;tallex.time-dive&lt;/code&gt;. This &lt;code&gt;namespace&lt;/code&gt; is going to be the &lt;code&gt;entry point&lt;/code&gt; of our app&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#entry-point-conventions&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;entry-point-conventions-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;There are a few implicit details which I want to highlight when it comes to namespaces.
&lt;strong&gt;Firstly&lt;/strong&gt;, namespaces follow the folder path.  &lt;strong&gt;Secondly&lt;/strong&gt;, if
a folder or file in your namespace has multiple words in it, like &lt;code&gt;time_dive&lt;/code&gt;, when
we&#39;re write our Clojure/Script namespace you must use dashes and not underscores
to separate them.  For example, you have a file labelled &lt;code&gt;time_dive&lt;/code&gt; and when we
write it in Clojure/Script we would write &lt;code&gt;time-dive&lt;/code&gt;. &lt;strong&gt;Lastly&lt;/strong&gt;, best practice
is to multi-segment our namespace name.  A multi-segmented
name is when we have multipe words/phrases separated by dots.  For example,
&lt;code&gt;tallex.time-dive&lt;/code&gt; is multi-segmented.  The first segment is &lt;code&gt;tallex&lt;/code&gt; and the
second is &lt;code&gt;time-dive&lt;/code&gt;.  Best practice is to have two or more segments. If we
only have one segment it can lead to name conflicts. Having said this, it&#39;s not
the end of the world if you only have a single-segment namespace.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-5---add-clojurescript-tests&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-5---add-clojurescript-tests&quot;&gt;Step 5 - Add ClojureScript Tests&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Good tests are the Alfred to a software engineers Batman. Open up that
&lt;code&gt;time_dive_tests.cljs&lt;/code&gt; file and add the following&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-cljs-test&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-cljs-test-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; tallex.time-dive-tests&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;js/console.log&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, Time Dive Tests!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This concludes setting up the project structure and boilerplate code. The next
thing to do is setup some tooling to run our Clojure(Script) app.&lt;/p&gt;
&lt;h2 id=&quot;running-and-developing-clojurescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#running-and-developing-clojurescript&quot;&gt;Running and Developing ClojureScript&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To run our Clojure/Script project we&#39;ll use &lt;a href=&quot;https://clojure.org/guides/deps_and_cli&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;clj&lt;/a&gt; tool&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#clj-tools&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;clj-tools-ref&quot;&gt;:&lt;/a&gt;
which will allow us to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run clojure programs&lt;/li&gt;
&lt;li&gt;resolve transitive dependencies&lt;/li&gt;
&lt;li&gt;build classpaths&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why do we need this?  Because while we&#39;re developing our app we want to be
able to use tools like ClojureScript, Figwheel etc to make our development
experience pleasant.  To do this, we start by adding these tools (deps) to our
project.&lt;/p&gt;
&lt;h3 id=&quot;step-6---add-deps-file&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-6---add-deps-file&quot;&gt;Step 6 - Add deps file&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Start by creating a &lt;code&gt;deps.edn&lt;/code&gt; file in the root of our project and then make
it look like this&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#build-tools-deps&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;build-tools-deps-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tests&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:aliases&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:dev&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-m&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;cljs.main&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-ro&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{:static-dir,[&#92;&quot;.&#92;&quot;,&#92;&quot;out&#92;&quot;,&#92;&quot;resources&#92;&quot;]}&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-w&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-c&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;tallex.time-dive&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;-r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Unlike other files in our Clojure project, we must name our &lt;code&gt;.edn&lt;/code&gt; what
&lt;code&gt;cljs&lt;/code&gt; want: &lt;code&gt;deps.edn&lt;/code&gt;.  This is because the &lt;code&gt;clj&lt;/code&gt; tool is going to look for a file
called &lt;code&gt;deps.edn&lt;/code&gt;. Furthermore, you will notice that the extension of this file
is &lt;code&gt;.edn&lt;/code&gt;. You can think of this as the Clojure(Script) equivalent of &lt;code&gt;json&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Before we continue, let&#39;s review what our &lt;code&gt;deps.edn&lt;/code&gt; file is doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/reference/deps_and_cli#_paths&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:paths&lt;/a&gt; tells &lt;code&gt;clj&lt;/code&gt; where to look for clojure code. Also known as a &lt;code&gt;classpath&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/reference/deps_and_cli#_dependencies&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:deps&lt;/a&gt; tells &lt;code&gt;clj&lt;/code&gt; which dependencies our app needs. Right now our only dependency is ClojureScript.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/reference/deps_and_cli#_aliases&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:aliases&lt;/a&gt; are like shortcuts.  We can store long commands, or alternate dependencies in these.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Right now, we only have one alias called &lt;code&gt;dev&lt;/code&gt;, but we will eventually have
others like &lt;code&gt;prod&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;.  The aliases allow us to run our app in different
ways.  Right now, our &lt;code&gt;dev&lt;/code&gt; alias says: run ClojureScript.  Specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://clojure.org/reference/deps_and_cli#_usage&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;quot;-m&amp;quot;&lt;/a&gt; run &lt;code&gt;cljs.main&lt;/code&gt; (run clojurescript).&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/reference/repl-options&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;quot;-ro&amp;quot;&lt;/a&gt; teach the CLJS repl where to find &lt;code&gt;static files&lt;/code&gt; e.g. html, css etc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/reference/repl-and-main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;quot;-w&amp;quot;&lt;/a&gt; watch all files in &lt;code&gt;src&lt;/code&gt; dir and recompile when they are changed.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/reference/repl-and-main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;quot;-c&amp;quot;&lt;/a&gt; compile our app entry point: &lt;code&gt;tallex.time-dive&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/reference/repl-and-main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&amp;quot;-r&amp;quot;&lt;/a&gt; run a REPL and connect it to the browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we have a rough idea of what is going on we&#39;re ready to take our app
for a test drive.&lt;/p&gt;
&lt;p&gt;Open a terminal, move into the root of the app and run the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M:dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;wait a bit for the above to run. If it worked, you should see that a browser
tab/window automatically opens and you&#39;ll see the HTML and CSS we coded above:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/001-time-dive-app.png&quot; alt=&quot;screenshot of time dive app&quot; /&gt;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Note that when you run the above you will see that two new directories are
auto generated for you in the root of your project: &lt;code&gt;.cpcache/&lt;/code&gt; and &lt;code&gt;out/&lt;/code&gt;. I bring
this up so you know that it&#39;s expected and so that you know it&#39;s Okay
to not include these folders in your projects version control.  If you are
wondering how to version control them see this &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/0cef20e6773ab5d2f93253926dafb4e05e0673f7&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;extra step&lt;/a&gt;&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Before we jump over to the next section I want to draw your attention to the
fact that we have zero dependencies. Think about this: our files are being
watched, code is recompiled on save, we are greeted with a browser repl and
all of this with zero dependencies. Yes, we are still missing a few niceties,
but we are not done yet.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you were testing the watch feature and can&#39;t see the code changes take
affect be sure to try refreshing the browser.&lt;/p&gt;
&lt;/aside&gt;&lt;h2 id=&quot;setup-a-clojurescript-toolchain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#setup-a-clojurescript-toolchain&quot;&gt;Setup a ClojureScript Toolchain&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I noted, we have zero dependencies and already have a powerful toolchain.
However, the developer experience can be better.  This section will take our
toolchain to the next level by introducing &lt;a href=&quot;https://figwheel.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;figwheel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;figwheel&lt;/code&gt; is a popular ClojureScript tool and a must have for my workflow&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#toolchain-tools&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;toolchain-tools-ref&quot;&gt;.&lt;/a&gt;
Figwheel has &lt;a href=&quot;https://figwheel.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;many features&lt;/a&gt;, but we are only going to focus on the main ones.
These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;live ClojureScript and CSS Reloading&lt;/li&gt;
&lt;li&gt;Informative error messages&lt;/li&gt;
&lt;li&gt;Build configurations for prod, dev, test et al.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that we know &lt;em&gt;what&lt;/em&gt; figwheel does, let&#39;s see &lt;em&gt;how&lt;/em&gt; to make it do the things.&lt;/p&gt;
&lt;h3 id=&quot;step-7---add-figwheel&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-7---add-figwheel&quot;&gt;Step 7 - Add Figwheel&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It starts by adding figwheel as a dependency. We do this by opening the
&lt;code&gt;deps.edn&lt;/code&gt; file and add the line you see highlighted below&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-toolchain&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-toolchain-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; highlight-range{7}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tests&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  com.bhauman/figwheel-main &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.18&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token comment&quot;&gt;; ...&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Clojure libraries are generally found in &lt;a href=&quot;https://clojars.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Clojars&lt;/a&gt; which is a popular Clojure package repository.  This is where you can go to find packages and examples of how to use the packages in our projects&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#package-repos&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;package-repos-ref&quot;&gt;.&lt;/a&gt;  Also note that when you add new dependencies to your project you will also have to stop and restart your app.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-8---add-build-configuration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-8---add-build-configuration&quot;&gt;Step 8 - Add build configuration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;build configuration&lt;/code&gt; is we configure both &lt;a href=&quot;https://figwheel.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;figwheel&lt;/a&gt; and the &lt;a href=&quot;https://clojurescript.org/reference/compiler-options&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ClojureScript compiler&lt;/a&gt; &lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#build-config-options&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;build-config-options-ref&quot;&gt;.&lt;/a&gt;
In this section, we&#39;ll show you what a &lt;code&gt;development&lt;/code&gt; build configuration looks like&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-build-config&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-build-config-ref&quot;&gt;.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Create a new file in the root of our ClojureScript app called &lt;code&gt;dev.cljs.edn&lt;/code&gt;
and add the following code to it:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:watch-dirs&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token symbol&quot;&gt;:css-dirs&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main&lt;/span&gt; tallex.time-dive&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What does all of the above mean?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://figwheel.org/config-options#watch-dirs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:watch-dirs&lt;/a&gt; - when any &lt;code&gt;cljs&lt;/code&gt; files change in &lt;code&gt;src&lt;/code&gt; directory figwheel recompiles and re-loads the browser.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://figwheel.org/config-options#css-dirs&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:css-dirs&lt;/a&gt; - when &lt;code&gt;css&lt;/code&gt; files change in the &lt;code&gt;resources&lt;/code&gt; directory figwheel recompiles and re-loads them in the browser&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://clojurescript.org/reference/compiler-options#main&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;:main&lt;/a&gt; - This is an option that figwheel passes to the &lt;code&gt;ClojureScript compiler&lt;/code&gt; which tells the compiler which file is our apps &lt;code&gt;entry point&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the above sounds like it overlaps with how we configured our project in
Step 6, you&#39;re right.  Now that we&#39;re using &lt;code&gt;Fighwheel&lt;/code&gt; we don&#39;t need the
&lt;code&gt;-w&lt;/code&gt;, &lt;code&gt;-r&lt;/code&gt; and &lt;code&gt;-c&lt;/code&gt; flags we originally added to our &lt;code&gt;dev&lt;/code&gt; alias.  We&#39;ll update
this in the next step.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;A few additional notes about the above:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt;  You can name your build configuration anything you like but it needs to
include the &lt;code&gt;.cljs.edn&lt;/code&gt; part.  We called ours &lt;code&gt;dev&lt;/code&gt; because it&#39;s configuring
our code for the development environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; You can and will have multiple &lt;code&gt;build configurations&lt;/code&gt;.  This is not a
bad thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt;  when you look at the above it can seem like there is very little
configuration, especially when compared to a &lt;code&gt;webpack&lt;/code&gt; config file. The
reason for this is because Figwheel makes a lot of sane default choices out
of the box.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-9---update-%3Adev-alias&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-9---update-%3Adev-alias&quot;&gt;Step 9 - Update :dev Alias&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We need to update our &lt;code&gt;dev&lt;/code&gt; alias to call &lt;code&gt;figwheel&lt;/code&gt; instead of calling
&lt;code&gt;ClojureScript&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;deps.edn&lt;/code&gt; and make it look like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tests&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  com.bhauman/figwheel-main &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.18&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:aliases&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:dev&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-m&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;figwheel.main&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--build&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dev&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--repl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Time for sanity check to make sure everything is still working. Run the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M:dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your app should run, but you will notice that you get the following screen:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/001-time-dive-figwheel-landing-page.png&quot; alt=&quot;screenshot of figwheel landing page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This appears because figwheel is looking for our &lt;code&gt;index.html&lt;/code&gt; in
&lt;code&gt;resources/public&lt;/code&gt;. Up until now we put our &lt;code&gt;index.html&lt;/code&gt; file directly under
the &lt;code&gt;resources&lt;/code&gt; dir. So, our next step is to move our &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;h3 id=&quot;step-10---restructure-resources-dir&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-10---restructure-resources-dir&quot;&gt;Step 10 - Restructure resources dir&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Go ahead and add a &lt;code&gt;public&lt;/code&gt; directory to the &lt;code&gt;resources&lt;/code&gt; dir and move your
&lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;style.css&lt;/code&gt; into it.&lt;/p&gt;
&lt;p&gt;Your folder structure should look like this&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-resources-restruct&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-resources-restruct-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
├── README.md
├── deps.edn
├── dev.cljs.edn
├── resources
│   └── public
│       ├── index.html
│       └── style.css
├── src
│   └── tallex
│       └── time_dive.cljs
└── tests
    └── tallex
        └── time_dive_tests.cljs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You will once again also see auto-generated folders like &lt;code&gt;target&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt; and
&lt;code&gt;.cpcache&lt;/code&gt;. They are not see in the above topology because I wanted to focus
on the important folders. If you see them, this is good.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;We also need to update the &lt;code&gt;script&lt;/code&gt; tag in our &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-html&quot;&gt;&lt;code class=&quot;bride-code-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/cljs-out/dev-main.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The reason we update the script tag because &lt;code&gt;figwheel&lt;/code&gt; is going to build your
ClojureScript in a different folder than &lt;code&gt;clj&lt;/code&gt; did.&lt;/p&gt;
&lt;p&gt;time to run the app again:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-M:dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The toolchain is now in place, but we are still missing the great and powerful
Hot Module Reloading.&lt;/p&gt;
&lt;h2 id=&quot;hot-module-reloading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#hot-module-reloading&quot;&gt;Hot Module Reloading&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hot Module Reloading (HMR) is the &amp;quot;killer feature&amp;quot; of React development. So
much so that HMR and React are often spoken in the same breath as if the two
are linked in some way.  The two are separate things entirely though. Truth is,
as long as you write &lt;a href=&quot;https://figwheel.org/docs/reloadable_code.html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;reloadable code&lt;/a&gt;, you can achieve HMR.&lt;/p&gt;
&lt;p&gt;This is the catch though: writing reloadable code can be &lt;a href=&quot;https://betweentwoparens.com/students-of-the-game-reloadable-code&quot;&gt;tricky and time consuming&lt;/a&gt;.
Writing reloadable code is made much easier when you write your code using React.
This is likely part of the reason the two are seen as linked.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;figwheel&lt;/code&gt; offers a framework / library agnostic mechanism to support your
ability to write HMR. Specifically, figwheel gives us &lt;code&gt;hooks&lt;/code&gt; which we specify
in the namespace  where we want to take advantage of HMR.&lt;/p&gt;
&lt;p&gt;The way it works is when we write HMR we have to tell our app how to tear
itself down and setup again when files are re-compiled. We have to write these
functions ourselves. What figwheel helps with is providing &lt;code&gt;hooks&lt;/code&gt; like
&lt;code&gt;:after-load&lt;/code&gt; and &lt;code&gt;:before-load&lt;/code&gt; which will call our setup and teardown
functions.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The hooks I am referring to are figwheel hooks and have nothing to do with React Hooks.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;step-11---refactor-for-figwheel&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-11---refactor-for-figwheel&quot;&gt;Step 11 - Refactor for Figwheel&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This section will illustrate how to use &lt;code&gt;figwheel hooks&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open &lt;code&gt;time_dive.cljs&lt;/code&gt;. Currently, our &lt;code&gt;time-dive&lt;/code&gt; namespace is logging
&amp;quot;Hello, Time Dive&amp;quot; on each reload. We could however only have it log on
re-compile by adding a hook like this&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-reagent&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-reagent-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:figwheel-hooks tallex.time-dive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:after-load re-render &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;js/console.log&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, Time Dive!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now when you try to run the app you will notice that the &lt;code&gt;console.log&lt;/code&gt; will only
log when there has been a reload.
not log the first time but only after each save. Things to take note of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;^:figwheel-hooks&lt;/strong&gt; - &lt;code&gt;meta data&lt;/code&gt; telling figwheel we want to use hooks in our namespace&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;^:after-load&lt;/strong&gt; - &lt;code&gt;meta data&lt;/code&gt; telling figwheel that we want it to run the function, &lt;code&gt;re-render&lt;/code&gt;, after each compile&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The &lt;code&gt;^:&lt;/code&gt; is Clojure syntax for &lt;a href=&quot;https://clojure.org/reference/metadata&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;metadata&lt;/a&gt;.  It&#39;s additional information we
can add to our to our vars, functions etc.  In this case, when &lt;code&gt;figwheel&lt;/code&gt; read
the metadata, it knows it has to do something.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;&lt;code&gt;reloadable code&lt;/code&gt; is a rich topic and my hope is to show you how it works
with CLJS and &lt;code&gt;figwheel&lt;/code&gt; and that it&#39;s a way you write your code just as much
as a helper tool.&lt;/p&gt;
&lt;h2 id=&quot;add-reagent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#add-reagent&quot;&gt;Add Reagent&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You could use a bunch of JS frameworks in ClojureScript, but the ClojureScript
community loves React and the community has made wrappers to make React
easier to use in ClojureScript.&lt;/p&gt;
&lt;p&gt;While there are many wrappers the most popular React wrapper is currently
&lt;a href=&quot;https://reagent-project.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Reagent&lt;/a&gt; so we will show you how to use that.&lt;/p&gt;
&lt;h3 id=&quot;step-12---refactor-for-reagent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#step-12---refactor-for-reagent&quot;&gt;Step 12 - Refactor for Reagent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to adding Reagent we are going to update our &lt;code&gt;deps.edn&lt;/code&gt;, &lt;code&gt;html&lt;/code&gt;,
&lt;code&gt;css&lt;/code&gt; and &lt;code&gt;cljs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Open the &lt;code&gt;deps.edn&lt;/code&gt; file and making it look like this&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-reagent-two&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;sanity-check-reagent-two-ref&quot;&gt;:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;; highlight-range{9}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:paths&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;src&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tests&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

 &lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  com.bhauman/figwheel-main  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.2.18&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  reagent                   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.2.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


 &lt;span class=&quot;token symbol&quot;&gt;:aliases&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:dev&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:main-opts&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-m&quot;&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;figwheel.main&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--build&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dev&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--repl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we can open our &lt;code&gt;index.html&lt;/code&gt; file and modify as follows:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-html&quot;&gt;&lt;code class=&quot;bride-code-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- highlight-range{8,10} --&gt;&lt;/span&gt;
&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Time Dive&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/cljs-out/dev-main.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally open our &lt;code&gt;time-dive&lt;/code&gt; namespace and add a few things:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:figwheel-hooks tallex.time-dive
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:require&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;reagent.dom &lt;span class=&quot;token symbol&quot;&gt;:as&lt;/span&gt; r.dom&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; app &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:h1.site__title&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:span.site__title-text&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Time Dive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; mount &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;r.dom/render&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;js/document.getElementById&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defn&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;^&lt;/span&gt;:after-load re-render &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;defonce&lt;/span&gt; start-up &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A little about the above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app&lt;/code&gt; is our first example of a &lt;a href=&quot;https://github.com/reagent-project/reagent/blob/master/doc/CreatingReagentComponents.md&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Reagent component&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mount&lt;/code&gt; a function. When called, it will display our &lt;code&gt;time-dive&lt;/code&gt; app&lt;/li&gt;
&lt;li&gt;&lt;code&gt;re-render&lt;/code&gt; a function with a hook. When called, it reloads our app. It supports the HMR part&lt;/li&gt;
&lt;li&gt;&lt;code&gt;defonce&lt;/code&gt; is used to control side effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;A little more about &lt;code&gt;defonce&lt;/code&gt;:  When your app re-loads through figwheels HMR
the code in the file will re-run.  So, if instead of &lt;code&gt;start-up&lt;/code&gt; we just called
&lt;code&gt;(mount)&lt;/code&gt;, &lt;code&gt;mount&lt;/code&gt; would rerun every time the file changes.  Instead, we
want to control this process.  We want to say:  when the file runs there are
things I want to do only the first time and things I want to happen every
other time.  This is called writing reloadable code.
See &lt;a href=&quot;https://betweentwoparens.com/blog/students-of-the-game:-reloadable-code/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Students of The Game: Reloadable Code&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Last step: open up &lt;code&gt;style.css&lt;/code&gt; and change the &lt;code&gt;body&lt;/code&gt; tag to &lt;code&gt;#root&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-css&quot;&gt;&lt;code class=&quot;bride-code-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* replace ... */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;/* with ... */&lt;/span&gt;
&lt;span class=&quot;token selector&quot;&gt;#root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The only reason we do this is because with Reagent we had to change our HTML structure a bit.  Likewise we change our css to reflect the HTML structure changes.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Ready to see if it all worked? Run &lt;code&gt;clj -M:dev&lt;/code&gt; and marvel at your ClojureScript SPA.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point we have created a ClojureScript app from scratch and provided a solid foundation which should allow you to take this app in any direction you like. Of course, I did not go into details beyond the initial phase, but if you are interested in possible next steps or sources for inspiration, here are a few that I often recommend.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/robert-stuttaford/bridge&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Example Reagent App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/juxt/edge&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Example Full Featured Clojure(Script) App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/athomasoriginal/clojurescript-30&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ClojureScript 30&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lambdaisland.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Lambda Island - ClojureScript Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://purelyfunctional.tv/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Purely Functional TV - Clojure(Script) Tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pragprog.com/titles/roclojure/getting-clojure/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Getting Clojure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://leanpub.com/elementsofclojure&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Elements of Clojure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These resources are great next steps for learning to work with Clojure(Script).&lt;/p&gt;
&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;clojurescript-spelling&quot;&gt;&lt;p&gt;You will notice I spell ClojureScript in two ways: &lt;code&gt;ClojureScript&lt;/code&gt; or &lt;code&gt;Clojure(Script)&lt;/code&gt;.  The difference: The first is me saying &amp;quot;Just ClojureScript&amp;quot; and the second is me saying &amp;quot;this applies to both Clojure and ClojureScript&amp;quot;.  The purpose is because Clojure and ClojureScript are 95% the same language, same build tools etc.  I have found it helpful to make this clear early on.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#clojurescript-spelling-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;project-structure&quot;&gt;&lt;p&gt;Technically the &lt;code&gt;README&lt;/code&gt;, &lt;code&gt;Resources&lt;/code&gt; and &lt;code&gt;tests&lt;/code&gt; files/dirs are not needed, but I always include them by default because to me, taking the time to setup things well in the beginning saves us time later.  Also keep in mind that you don&#39;t have to follow my structure.  There is no real science here other than this is a sane structure I have evolved and come to trust through use in production.  &lt;strong&gt;Sanity Check&lt;/strong&gt;: your project should look like this: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/96fafa51dfa8cb2e1ea208961c1ff2a3e4eb663a&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 96fafa5&lt;/a&gt;.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#project-structure-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;resources-dir&quot;&gt;&lt;p&gt;You will notice HTML, CSS, Images etc will go in our &lt;code&gt;Resources&lt;/code&gt; dir.  This is not a hard and fast rule, but it is a helpful convention.  Also, &lt;strong&gt;sanity Check&lt;/strong&gt;:  &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/58975cc17d779a6f4c7947c9c21a468a6711671e&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 58975c&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#resources-dir-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-css&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/3aab28449076fb0d80e801d0a1f8cf0c5d8c5e42&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 3aab28&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-css-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-cljs&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/863278997d8dd23e3c56dbb61cab7c5138aa423c&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 863278&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-cljs-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;entry-point-conventions&quot;&gt;&lt;p&gt;The dominant convention is to name your entry point &lt;code&gt;core.cljs&lt;/code&gt;. This is something that comes from the build tool &lt;code&gt;lein&lt;/code&gt; and it&#39;s a silly convention because it provides us with no semantics.  It&#39;s easy to want to do this though because other languages like  JavaScript do this with their &lt;code&gt;index.js&lt;/code&gt; and python with &lt;code&gt;main.py&lt;/code&gt; and so on.  Resist the urge and try to give your &lt;code&gt;entry point&lt;/code&gt; a meaningful name.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#entry-point-conventions-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-cljs-test&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/90a576f927947fcd620c6bcb340d3dc0427d2b06&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 90a576&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-cljs-test-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;clj-tools&quot;&gt;&lt;p&gt;Other tools include &lt;code&gt;lein&lt;/code&gt; and &lt;code&gt;boot&lt;/code&gt;, however the &lt;code&gt;Clojure Tools&lt;/code&gt; are currently
the most popular choice for new projects.  Feel free to learn more by reading
&lt;a href=&quot;https://betweentwoparens.com/blog/what-are-the-clojure-tools/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;What Are The Clojure Tools&lt;/a&gt;:&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#clj-tools-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;build-tools-deps&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/ba182b9a2b7f5b753bb7b16bb5ff4bf8384ab0bd&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit ba182b&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#build-tools-deps-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;what-is-dev-toolchain&quot;&gt;&lt;p&gt;When I say &amp;quot;toolchain&amp;quot; I mean things like build the app for production and dev, HMR, live CSS reloading.  All the things needed to make development life easy and get your app from your local environment to a production ready state.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#what-is-dev-toolchain-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;toolchain-tools&quot;&gt;&lt;p&gt;There is also &lt;a href=&quot;http://shadow-cljs.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;shadow-cljs&lt;/a&gt; which does some great stuff and is the more popular
tool.  Okay, why am I teaching Figwheel then? Figwheel does less and this is
important to me.  It adds testing facilities, a file-watcher and some
conveniences and no more.  Compare this to &lt;code&gt;shadow-cljs&lt;/code&gt; which actually adds
to the CLJS language itself.  For example, it supports a non-standard form of
requiring files.  I find that the conveniences it provides often serves to
confuse users.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#toolchain-tools-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-toolchain&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/7d642c5416413da13c9cbebd31e33a563e917c90&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 7d642c&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-toolchain-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;package-repos&quot;&gt;&lt;p&gt;&lt;code&gt;Clojars&lt;/code&gt; is not the only way to find versions, or even gain access to libraries.  Another place to look is on Github where the source code for your packages live.  In addition, you can even specify a specific hash to download the packages directly from github.  Feel read to read more about that &lt;a href=&quot;https://clojure.org/reference/deps_and_cli#_dependencies&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;CLI and Deps&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#package-repos-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;build-config-options&quot;&gt;&lt;p&gt;I believe the difference between ClojureScript and Figwheel options is a great source of confusion for new ClojureScript developers.  I feel this way because it requires an understanding of where one library ends and the other begins.  Just know that Figwheel is going to be running the &lt;code&gt;ClojureScript Compiler&lt;/code&gt; for you which is why both options can all look like one thing.  If you are ever not sure, visit the links.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#build-config-options-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-build-config&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/46e46990726d61638e9b80f6345e4b6683ac1e70&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 46e469&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-build-config-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-resources-restruct&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/4b6b656323ea5cda9edb9265e61e49de6d9f7cfc&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 4b6b65&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-resources-restruct-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-resources-restruct&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/4c8cbd67dcc24d0365feb25bf511e03cba0fcf36&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 4c8cbd&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-resources-restruct-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;sanity-check-reagent-two&quot;&gt;&lt;p&gt;&lt;strong&gt;Sanity Check&lt;/strong&gt;: &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-app/commit/e1cf66d7ed1973d4fa1ec1091c0cbe16e61cf4b4&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit e1cf66&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/#sanity-check-reagent-two-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
  
  <entry>
    <title>Deploy ClojureScript to Github Pages</title>
    <link href="https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/"/>
    <updated>2024-11-11T22:08:33Z</updated>
    <id>https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/</id>
    <content type="html">&lt;p&gt;Here&#39;s a small example of what it looks like to deploy a static website with
some ClojureScript to Github Pages. I&#39;ll start by introducing some key cocepts
and then move into how we actually do the thing.&lt;/p&gt;
&lt;h3 id=&quot;what-is-clojurescript%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#what-is-clojurescript%3F&quot;&gt;What is ClojureScript?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ClojureScript, like &lt;a href=&quot;https://elm-lang.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Elm&lt;/a&gt; or &lt;a href=&quot;https://reasonml.github.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Reason&lt;/a&gt;, is a compile to js programming language.
ClojureScript is different from JavaScript in a few ways.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&#39;s a functional language&lt;/li&gt;
&lt;li&gt;It&#39;s a &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisp_(programming_language)&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;lisp&lt;/a&gt; (AKA: Not C style syntax)&lt;/li&gt;
&lt;li&gt;It&#39;s development and design is intentional&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of the more pragmatic differences&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The culture of the language avoids breaking changes&lt;/li&gt;
&lt;li&gt;Write your frontend and backend in one language&lt;/li&gt;
&lt;li&gt;Out-of-the-box tools to help you solve problems better&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If nothing else, ClojureScript is guarenteed to make you think different.&lt;/p&gt;
&lt;h3 id=&quot;github-pages-and-static-sites%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#github-pages-and-static-sites%3F&quot;&gt;Github Pages and Static Sites?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Github Pages&lt;/code&gt; is a service provided by Github which allows you to freely host
your static website.&lt;/p&gt;
&lt;p&gt;A static website is when you write your website in html, css and
javascript.  You don&#39;t need to setup servers, databases or additonal server
side code. The benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;A quick development workflow&lt;/li&gt;
&lt;li&gt;Easier website security&lt;/li&gt;
&lt;li&gt;Less expensive to build and host&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The downsides are that static websites will not be able to acheive all the cool
features of a beefy web app.  Often times I will use a static website to prove
a concept for an app, host docs or build marketing websites.  They are cheap,
fast to build and let you prove out concepts.&lt;/p&gt;
&lt;p&gt;With this in mind, let&#39;s start coding.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;The rest of this article assumes that you have a Github account. If you don&#39;t, no worries. Take a moment and &lt;a href=&quot;https://help.github.com/en/articles/signing-up-for-a-new-github-account&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;create one for free&lt;/a&gt; or just sit back and enjoy the read. For those who want to adventure with me, go through Github&#39;s official &lt;a href=&quot;https://pages.github.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;Github Pages Quickstart&lt;/a&gt; for projects and follow it exactly.  Note that throughout this post I will have footnotes referencing &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;my demo project&lt;/a&gt; which has each step mirrored by its corresponding &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/commits/master&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit&lt;/a&gt;. Please lean on them if you feel lost at any point.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Let&#39;s start by getting Clojure setup on your local machine. To do this, visit the &lt;a href=&quot;https://clojurescript.org/guides/quick-start&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;ClojureScript Quickstart&lt;/a&gt; and follow the instructions there.&lt;/p&gt;
&lt;p&gt;Not sure if you have everything setup properly? We can run a quick sanity check in your terminal by executing the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-Stree&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should see a response like this:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;org.clojure/clojure &lt;span class=&quot;token number&quot;&gt;1.11&lt;/span&gt;.1
  &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; org.clojure/spec.alpha &lt;span class=&quot;token number&quot;&gt;0.3&lt;/span&gt;.218
  &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; org.clojure/core.specs.alpha &lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;.62
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Don&#39;t worry if your versions are different from mine.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;setting-up-your-html&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#setting-up-your-html&quot;&gt;Setting up your HTML&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For those that went through the Github Pages quickstart, you should have a repo
with a sad, empty &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-1-commit&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-step-1-commit-ref&quot;&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/a&gt;. Open your &lt;code&gt;index.html&lt;/code&gt;
and type the following:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-html&quot;&gt;&lt;code class=&quot;bride-code-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Github Pages + ClojureScript&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;h1&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site__title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;site__title-text&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Hello ClojureScript&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;h1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/demo-clojurescript-gh-pages/out/main.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You&#39;ll notice that we added a reference to a &lt;code&gt;main.js&lt;/code&gt; and &lt;code&gt;style.css&lt;/code&gt;
file in our HTML. These don&#39;t exist yet, but we will create them later.
Please also note that where it says &lt;code&gt;&amp;quot;demo-clojurescript-gh-pages&amp;quot;&lt;/code&gt;.  This is
named after my Github project repo.  You should name yours after &lt;em&gt;your&lt;/em&gt; Github
project repo.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;setting-up-your-css&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#setting-up-your-css&quot;&gt;Setting up your CSS&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The next thing we want to do is add a &lt;code&gt;style.css&lt;/code&gt; file at the same level as our
&lt;code&gt;index.html&lt;/code&gt;&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-2-commit&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-step-2-commit-ref&quot;&gt;.&lt;/a&gt;  Type the following into it&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-css&quot;&gt;&lt;code class=&quot;bride-code-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--color-purple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;197&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 18&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 193&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--color-pink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;241&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 50&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100vh&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; flex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Arial&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;justify-content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.site__title&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 100px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 50%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;text-align&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.site__title-text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;-webkit-linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    34deg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-purple&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--color-pink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-background-clip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;-webkit-text-fill-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have our HTML and CSS, we need to add ClojureScript.&lt;/p&gt;
&lt;h3 id=&quot;setting-up-your-clojurescript&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#setting-up-your-clojurescript&quot;&gt;Setting up your ClojureScript&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This section will now add the absolute minimum requirements to start working with
ClojureScript.&lt;/p&gt;
&lt;p&gt;Create a file called &lt;code&gt;deps.edn&lt;/code&gt; at the same level as our
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-deps&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-deps-ref&quot; class=&quot;gatsby-code-text&quot;&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;
&lt;p&gt;Open the file you&#39;ve created and type the following code into it.&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:deps&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;org.clojure/clojurescript &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token symbol&quot;&gt;:mvn/version&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;1.11.60&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you&#39;re coming from JavaScript it can be helpful to think of the &lt;code&gt;deps.edn&lt;/code&gt;
as similar to &lt;code&gt;package.json&lt;/code&gt;. &lt;code&gt;deps.edn&lt;/code&gt; tells &lt;code&gt;clojure&lt;/code&gt; which version of
&lt;code&gt;ClojureScript&lt;/code&gt; we want to use.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;Let&#39;s recap a bit. At this point, your directory structure should look like &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-3-commit&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-step-3-commit-ref&quot;&gt;this:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
├── deps.edn
├── style.css
└── index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If yes, we are good to move onto the next step: writing ClojureScript!&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;src/demo&lt;/code&gt; &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-src-dir&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-src-dir-ref&quot;&gt;directory&lt;/a&gt;. Once created, move into &lt;code&gt;src/demo&lt;/code&gt; and create
a ClojureScript file called &lt;code&gt;static_website.cljs&lt;/code&gt;. Now our repo should
look like &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-4-commit&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-step-4-commit-ref&quot;&gt;this:&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;
├── src
│   └──  demo
│       └── static_website.cljs
├── style.css
├── deps.edn
└── index.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Open &lt;code&gt;static_website.cljs&lt;/code&gt; and type the following:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-clojure&quot;&gt;&lt;code class=&quot;bride-code-clojure&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;ns&lt;/span&gt; demo.static-website&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;js/console.log&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, Github Pages!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Open your terminal and run the following command&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; cljs.main &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;demo-clojurescript-gh-pages/out&quot;&lt;/span&gt;  &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; demo.static-website &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;You want to run the above command from the same place as your &lt;code&gt;deps.edn&lt;/code&gt;.
Further, if you&#39;re curious above the above command and what things like &lt;code&gt;-d&lt;/code&gt; or
&lt;code&gt;-c&lt;/code&gt; means you can check these out in your terminal by running  &lt;code&gt;clj -m cljs.main --help&lt;/code&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;p&gt;The above command will compile your CLJS into JS. It can take a moment to run.
When completed, a browser tab will automatically open and serve your HTML, CSS
and ClojureScript. If everything worked you should see a site that looks like
this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://betweentwoparens.com/images/000-image-hello-cljs-dev-example.png&quot; alt=&quot;screenshot of example hello clojurescript site&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Further, if you open your browser console you should see &amp;quot;Hello, Github Pages!&amp;quot;&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;If you&#39;re not seeing your ClojureScript in the browser console, please verify
that your &lt;code&gt;index.html&lt;/code&gt; file is using your Github project name and the string
following the &lt;code&gt;-d&lt;/code&gt; in the above command, &lt;code&gt;demo-clojurescript-gh-pages&lt;/code&gt;, is also
using your Github project &lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-project-name&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-project-name-ref&quot;&gt;name&lt;/a&gt;.&lt;/p&gt;
&lt;/aside&gt;&lt;h3 id=&quot;build-production-bundle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#build-production-bundle&quot;&gt;Build production bundle&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The above is an example of how we test our code locally. After we&#39;re happy with
our code, we can build it for production by running the following command:&lt;/p&gt;
&lt;div class=&quot;bride-highlight&quot;&gt; &lt;pre class=&quot;bride-code-bash&quot;&gt;&lt;code class=&quot;bride-code-bash&quot;&gt;clj &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; cljs.main &lt;span class=&quot;token parameter variable&quot;&gt;-O&lt;/span&gt; advanced &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;demo.static-website&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once the above is done, commit your code with &lt;code&gt;git&lt;/code&gt;, and push the code to your
Github project repo and you should see your ClojureScript app live&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-versioned-dependencies&quot; aria-describedby=&quot;footnote-label&quot; id=&quot;fn-versioned-dependencies-ref&quot;&gt;!&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As I noted in the beginning, this is a very small example of a ClojureScript
project. From here, you can go in many different directions.  However, the idea
is the same: turn your CLJS code into JS code and ship the JS code.&lt;/p&gt;
&lt;aside class=&quot;blog-content__note&quot;&gt;&lt;p&gt;Hopefully you did not run into any issues, but if you did please head over to
&lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;my demo project&lt;/a&gt; where I try to identify and help to resolve some gotchas.
Experience something new?  Please feel free to get in touch and I would be
happy to help work through the issue with you.&lt;/p&gt;
&lt;/aside&gt;&lt;aside class=&quot;footnote-container&quot;&gt;&lt;h3&gt;Footnotes&lt;/h3&gt;&lt;ol&gt;&lt;li id=&quot;fn-step-1-commit&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/commit/90156bf57c1b80bd2e125909e8e7a584a53538c2&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 90156b&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-1-commit-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-step-2-commit&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/commit/db9371431ab3288233cc5ec7ecd32f6c449c8d54&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit db9371&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-2-commit-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-deps&quot;&gt;&lt;p&gt;&lt;code&gt;deps.edn&lt;/code&gt; is a newer, more beginner friendly way of setting up a Clojure(script) project.  Other popular alternatives include using tools like &lt;a href=&quot;https://leiningen.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;leiningen&lt;/a&gt; and &lt;a href=&quot;https://boot-clj.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;boot&lt;/a&gt; Having said this, I recommend using &lt;code&gt;deps.edn&lt;/code&gt;.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-deps-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-step-3-commit&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/commit/575c634dc770da7000787e6feb0ed7757e505309&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 575c63&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-3-commit-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-src-dir&quot;&gt;&lt;p&gt;The reason we are creating a &lt;code&gt;demo&lt;/code&gt; dir nested in a &lt;code&gt;src&lt;/code&gt; dir is because in Clojure(script) it&#39;s preferred to multi-segment our namespaces.  This is both for &lt;a href=&quot;https://github.com/bbatsov/clojure-style-guide#no-single-segment-namespaces&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;stylistic&lt;/a&gt; and &lt;a href=&quot;https://stackoverflow.com/questions/13567078/whats-wrong-with-single-segment-namespaces&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;technical&lt;/a&gt; reasons.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-src-dir-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-step-4-commit&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/commit/347c5580c55a80352179c39f2ce37d164bbc860c&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;commit 347c55&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-step-4-commit-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-project-name&quot;&gt;&lt;p&gt;We are referencing &lt;code&gt;demo-clojurescript-gh-pages&lt;/code&gt; in our &lt;code&gt;index.html&lt;/code&gt; and as the &lt;a href=&quot;https://clojurescript.org/reference/compiler-options#output-dir&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;-d or :output-dir flag&lt;/a&gt; for our development bundle.  This is because when our code is served from Github Pages it&#39;s going to be served from &lt;code&gt;https://username.github.io/project-name/&lt;/code&gt; where &lt;code&gt;project-name&lt;/code&gt; is the name of our &lt;a href=&quot;https://athomasoriginal.github.io/demo-clojurescript-gh-pages/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;gh pages clojurescript repo&lt;/a&gt;. This means that in order to serve our site in development and production, without having two script tags in our &lt;code&gt;index.html&lt;/code&gt; we sync with what its called in production so we only have to set it once.  There are other ways to achieve this, but with a goal of minimalism in mind, I feel this will do.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-project-name-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;li id=&quot;fn-versioned-dependencies&quot;&gt;&lt;p&gt;When you run the development or production build commands they will generate a bunch of code we do not need to version control.  For example, a &lt;code&gt;.cpcache&lt;/code&gt;, &lt;code&gt;demo-clojurescript-gh-pages/out&lt;/code&gt;, and &lt;code&gt;out&lt;/code&gt; dirs.  The only files you need to version control are the ones I have in &lt;a href=&quot;https://athomasoriginal.github.io/demo-clojurescript-gh-pages/&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;gh pages clojurescript repo&lt;/a&gt;.  The other ones can be ignored.  If you&#39;re curious what that that looks like I have created a &lt;a href=&quot;https://github.com/athomasoriginal/demo-clojurescript-gh-pages/tree/level-2-what-to-version-control&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;level 2&lt;/a&gt; branch to show you.&lt;/p&gt;
&lt;a href=&quot;https://betweentwoparens.com/blog/deploy-clojurescript-to-github-pages/#fn-versioned-dependencies-ref&quot; aria-label=&quot;Back to content&quot;&gt;Back&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/aside&gt;</content>
  </entry>
</feed>
