Nostalgia City I've recently started maintaining a Clojure codebase that hasn't been touched for over a decade - all Clojure devs that built and maintained it are long gone. It's using java8, Clojure 1.6 and libs like korma and noir - remember those? Contrary to the prevailing Clojure lore, upgrading Clojure will not be just a matter of changing version numbers in the lein project.clj. I find one…
In this post I am going to look at using the importmap feature (supported by all modern browsers), as an alternative way for Clojurescript apps to access npm dependencies. The Problem When a Clojurescript app depends on a regular JS library, such as React for example, then it is typical to: have the code from the npm library 'processed' in some fashion (e.g. to target a specific JS version) bundle…
In this post I am going to look at applying my regular dev setup to a project with a lot of code and tests that take a very long time to run. Firstly, here are my Clojurescript dev setup requirements: run a single test from the IDE - ie the one under the cursor run all tests in namespace similar to above run any subset of tests based on ns-pattern see nicely formatted test output - for example…
This post looks at the meaning of the #inst reader literal from Extensible Data Notation (hereafter referred to as 'edn'), how it behaves by default in Clojure(script) and when it might not be sufficient for representing date/time information. The majority of the content of this post comes from the Rationale section of time-literals , a Clojure(Script) library which provides tagged literals for…
A recent release of the popular Java logging abstraction SLF4J has a new API enabling structured logging . New Clojure logging macros using this, e.g. (log/info "request-for-help" {"priority" "high"}) are available as slf4clj . Why Log data? A couple of years ago I made a survey of all the logging libraries one might use from Clojure. The majority of contenders ( clojure.tools.logging foremost…
Update: As of mid-2022, Clojurescript has fixed the problems described in this post. Why having clojurescript in the classpath may lead to unexpected behaviour The clojurescript maven artifact lists compile dependencies which include: data.json, tools.reader and transit-clj and transit-java. However the clojurescript jar itself is something like an uberjar: It includes compiled data.json,…
Combining Java's promises with Clojure's laziness yields some interesting behaviour Consider: (doseq [x (range 1000000)]) Since range returns a lazy sequence and doseq does not retain the head of the sequence, there will only be one element of the sequence realized at every step of the doseq . Now let's split the creation and consumption of the lazy sequence over chained promises. I am using the…
Tick provides a powerful, cross-platform date-time API way beyond what java.time offers. It is implemented on top of cljc.java-time which again is cross-platform as has exactly the same API as java.time. For years now, the API has been alpha , by which we mean "Ready to use with the caveat that the API might still undergo minor changes". With the current release, the API of tick has been split…
In this post I am going to compare the performance of two Clojurescript date-time libraries, in the context of a typical single-page web application. The Libraries Cljc.java-time cljc.java-time (disclaimer: authored by myself) has the same API as java.time, but targets both Clojure and Clojurescript. It is implemented on top of a pure Javascript implementation of java.time called JS-Joda. It is…
There are choices as to how you do Clojurescript interop ( accessing a Javascript object's methods and properties) and that's what I'm going to look into here. IMHO Clojurescript is somewhat lacking when it comes to official documentation, hence this blog post, and the need to quote from twitter: In concrete terms, sounds like ✓ (.-length "abc") X (.-length #js {:length 3}) ✓ (goog.object/get #js…
I recently made my first crud-style hobby app with Firebase and I wanted to write it in Clojurescript.... of course ;-) Looking around the internet for pointers, I found some Clojurescript-Firebase wrapper libraries I am not too keen on, and no great demo apps either... so I created my own demo 'todo-list' app The README there contains a small list of instructions that should get you up and…
Using interop syntax with the java.time API is not wrong, but there is an alternative that is superior in every respect - and it just got much better. Some in the Clojure community would say that if a Java or JS API is good, then it needn't be 'wrapped' in a library, because plain interop code is idiomatic and any wrapping library might: Miss out something of the underlying API (so you likely need…
UPDATE 2024-03: Since this blog was published the Temporal API has evolved and addressed many of the issues raised here. Notably, the Absolute entity is now Instant, the same as java.time there is a ZonedDateTime entity 'Plain' is the prefix equivalent to java.time's 'Local' there are now facilities for truncation/rounding in the API there is a new library Tempo that targets both java.time and…
Time libs on npm/Shadow tick is a Clojure(Script) library for working with time. cljc.java-time is used by tick and provides a cross-platform version of the java.time api. In the latest releases, these 'just work' on Shadow-cljs, for example: echo '{:deps { tick {:mvn/version "0.4.25-alpha"} thheller/shadow-cljs {:mvn/version "2.9.8"} }}' > deps.edn echo '{:deps {}}' > shadow-cljs.edn echo '{}' >…
Update (2021-07-18) The Reagent project, one of the better known cljs projects that depends on a javascript lib, has abandoned Clojurescript's dependency mechanisms (foreign-libs or deps.cljs) entirely, making users bring their own React, see this issue for details. Original content from here on : If you are authoring a Clojurescript library that doesn't depend on any regular Javascript (JS) code,…
In April 2019 I gave a talk at Clojure/North providing my motivation for working on new date-time libraries: cljc.java-time , time-literals and tick . Yes, you heard right, yet more date-time libraries! In the talk I argue that they provide novelty with respect to cross-platform development and improve the overall situation for Clojurescript date-time work. This post gives some updates on what has…
I can mostly avoid async tests for my re-frame cljs apps. Even integration-style tests that use enzyme or react-testing-library can be made synchronous (if using Re-frame), by using day8.re-frame.test/run-test-sync and faking server responses with synchronous promises. This is nice because they're easier to understand and debug. Sometimes though, async is necessary. The Clojurescript site…
with-redefs is a handy clojure.core function to use when you want to redefine one or more vars temporarily (within a block) and you want these redefinitions to apply across thread boundaries An alternative for doing something similar is with-bindings , and that is slightly different in that the new bindings are only seen within the context of the current thread. If for example, you use…
A brief explanation of how to leverage your business logic code as much as possible by Simplifying it, with some specific tips for Clojure developers, including using the cross-platform tick date/time library. Separate Decisions from Dependencies The idea to 'Separate Decisions from Dependencies' is to only use pure functions for writing code that 'makes decisions' and wire those functions…