ClojureScript Warnings as Errors

We recently ran into a problem at Nextjournal when we deployed a bad build to production. It turned out after renaming a var, we overlooked one instance. However, our CI didn't catch that.

Let's see how the ClojureScript compiler behaves with a source file using an undefined namespace.

{:deps
 {org.clojure/clojure {:mvn/version "1.10.1"}
  org.clojure/clojurescript {:mvn/version "1.10.597"}}}
deps.edn
Clojure
(ns foo.bar)
(bam/doesnt-exist)
bar.cljs
ClojureScript

Build it with the default compiler options.

(require 'cljs.build.api
         'cljs.analyzer.api)
(cljs.build.api/build
 "src"
 {:output-to "out/main.js"})
7.1s
Clojure

As we see, it produces warnings, but the build is successful anyway. This is not desirable, we want the build to fail.

To make it fail, we have to build it with a custom warning handler to throw an error in addition to logging them, but clean the previous build first.

rm -rf out
0.2s
Bash in Clojure
(require 'cljs.build.api
         'cljs.analyzer.api)
(cljs.build.api/build
 "src"
 {:output-to "out/main.js"
  :warning-handlers
  [cljs.analyzer.api/default-warning-handler
    (fn [warning-type env extra]
     (when (warning-type cljs.analyzer/*cljs-warnings*)
      (throw
       (cljs.analyzer/error
        env
        (cljs.analyzer/error-message warning-type extra)))))]})
2.2s
Clojure

💥 Much better.

Also interesting: shadow-cljs has a dedicated compiler option for this.

Runtimes (1)