Problems with code splitting


I’m trying to use code splitting in my CLJS codebase to separate app code from trackers (think Google Analytics), so that trackers code are not part of the base module and are lazy loaded on-demand only. Good idea, right ?

Our strategy so far (without code splitting) is to write the small javascript tracker code in Javascript files with Google Closure in mind (goog.provide(), goog.require() etc.) to seamlessly package them an call them from CLJS. So far so good. Works perfectly, already in production for a long time.

Problems appear when I decided to code split them. Basically the split tracker module code is in the main app code split (cljs_base.js), and the tracker module split (google_analytics.js) is empty…

Below the details:


  • Linux
  • Boot 2.7.1 with boot-cljs 2.1.4
  • Clojure 1.9
  • ClojureScript 1.9.946
  • Java 8

Compiler options

{:main           "yoda.core"
 :libs           ["trackers/google_analytics.js"] ;; lots of trackers here in Javascript
 :modules        {:google-analytics {:entries   '#{} ;; CLJS wrapper around the tracker above so that we can call `loader/set-loaded! :google-analytics)`
                                     :output-to "js/google-analytics.js"}}
 :asset-path     "/yd/js/main.out"
 :optimizations  :simple
 :source-map     true
 :parallel-build true
 :verbose        true}

CLJS wrapper code

  (:require [cljs.loader :as loader]
            [ :as ga]))

(defn start [ga-tracking-id entity]
  (ga/start ga-tracking-id entity))

(loader/set-loaded! :google-analytics)

Lazy loading

(loader/load :google-analytics
             (fn []
               ((resolve ' ga-tracking-id entity)))

With the :verbose true option, the CLJS compiler seems to behave well:

Building module :google-analytics
# lot of entries...
  adding entry []
  adding entry (
  module :google-analytics depends on :cljs-base

The browser console shows it’s working :

log:Module loaded: cljs_base
log:Module loaded: google_analytics

The problem

  • There’s no network request to load google_analytics.js
  • google_analytics.js is an empty file (contains only the source-map comment //#
  • cljs_base.js contains everything, including the namespace

It seems to be related to cross module code motion, but I don’t understand why it produces this result. I think I’ve followed the official guide on Code Splitting to the letter.

Do you see where I’m wrong ?

Thanks in advance !

PS: I first posted in the official CLJS mailing list, but it seems that posts require approval first, so I posted here too in the meantime (had to rewrite it! no draft! arghh!). Sorry for the cross posting.

Here I’ve made a minimal project that works as expected and follows your setup, take a look


Thanks a lot, gonna look at it

I studied and ran your minimal project carefully and successfully, but still don’t understand why the tracker module code is included in cljs_base.js…

I noticed some differences though with the official docs :

  1. The Compiler options page describes a set of strings for modules entries (#{"my.ns"}), the official guide uses quoted sets ('#{my.ns}), your example uses a set of quoted namespaces (#{'my.ns}). All seems to work though

  2. Your example says that the base module should include a call to (loader/set-loaded! :cljs-base), but the official guide doesn’t say this at all. Anyway it works for you.

Note that I tested everything in my case, and nothing works… Maybe a boot-cljs problem ? I should try to port your example to boot to see if there’s a problem there.

I managed to create a minimal reproduction repository. It’s definitely a problem of Boot-cljs, not of the CLJS compiler itself.

The repo (with problem statement and instructions):

And the corresponding issue in boot-cljs repo