Skip to content

Instantly share code, notes, and snippets.



Last active Nov 12, 2018
What would you like to do?
Notes about fixing analysis issues with ClojureScript 1.10.439

How to analyze-file with foreign-lib dependencies?

  • I'm trying to figure out how to analyze a file that depends on react (via CLJSJS)
  • Previously would analyze with *analyze-deps* set to false
  • With 1.10.439 this no longer works. (Dynamic vars can't be resolved, see old description below)
  • With *analyze-deps* set to true I need to properly supply the foreign lib information but I can't figure out how.


When calling cljs.analyzer.api/analyze-file with the state-as-first-arg arity it calls cljs.env/with-compiler-env which shadowed my own binding described in Current Approach section. I was unaware that analyzer.api/empty-state is actually just a compiler env as well so creating the right compiler env and passing it to analyze-file solved all issues:

(defn- analyze-file [file]
  (let [opts  (cljs.closure/add-implicit-options {})
        state (cljs.env/default-compiler-env opts)]
     (cljs.closure/validate-opts opts)
     (ana/analyze-file state file opts))

Current Approach

Supplying :js-dependency-index via cljs.env/default-compiler-env like this:

(binding [cljs.env/*compiler* (cljs.env/default-compiler-env
                                (cljs.closure/add-implicit-options {}))]

I think it's not possible to pass this via analyze-file's third opts arg since that is only the :options part of the compiler env. Unfortunately analyze-deps still throws when doing the check below. The check succeeds right after the binding form (see repro.clj):

(println "REACT FOUND?" (contains? (:js-dependency-index @cljs.env/*compiler*) "react"))

??? Is something modifying the compiler env after the binding? I grepped for swap! calls but couldn't find anything that seemed relevant.


  • cljs.closure/add-implicit-options is called in the compiler itself and properly discovers the foreign lib information on the classpath (via cljs.closure/get-upstream-deps). Tried passing the return value as opts to analyze-file. Wasn't enough but helpful to better understand stuff.

Old Description (ignore this)

This seems to be a regression between 1.10.339 and 1.10.439.

The error typically looks like this, but also occurs with other dynamic vars:

Unable to resolve var: *instrument-enabled* in this context

Working with 1.10.339:

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.339"}}}' repro.clj spec.cljc

Failing with 1.10.439:

clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.439"}}}' repro.clj spec.cljc
  • It seems to be irrelevant whether the file is a .cljc or .cljs file.
  • In most (maybe all) cases the exception was thrown from inside a macro
{:deps {cljsjs/react {:mvn/version "16.6.0-0"}
org.clojure/clojurescript {:mvn/version "1.10.439"}
org.clojure/test.check {:mvn/version "0.9.0"}}}
(require '[ :as io]
'[cljs.analyzer :as an]
'[cljs.analyzer.api :as ana])
(defn- analyze-file [file]
(let [opts (cljs.closure/add-implicit-options {})
state (cljs.env/default-compiler-env opts)]
(cljs.closure/validate-opts opts)
(ana/analyze-file state file opts))
(analyze-file (io/file "spec.cljc"))
(doseq [f *command-line-args*]
(analyze-file (io/file f))
(printf "Successfully analyzed %s\n" f)
(catch Exception e
(println "Failed!" (.getMessage e))
(.printStackTrace e))))
(ns codox-test.spec
(:require [clojure.spec.test.alpha :as st]
(defn test [foo bar]
(+ foo bar))
(defn macro-calling [a b]
(st/with-instrument-disabled (test a b)))
(ns codox-test.spec-two
(:require [clojure.spec.test.alpha :as st]))
(st/with-instrument-disabled (+ 1 2 3))

This comment has been minimized.

Copy link
Owner Author

@martinklepsch martinklepsch commented Nov 9, 2018

ℹ️ the issue was that [an/*analyze-deps* false] — with that flag set to true everything works as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment