Surfacing lazy module errors

Shadow-CLJS has a nifty lazy/loadable tool that helps with loading modules lazily in ClojureScript apps. I find it useful.

But one thing caught me off guard: errors thrown while loading modules via goog.module.ModuleManager are swallowed silently, so if you happen to write a bug in a lazy-loaded module, goog’s module loader will retry a number of times in the background, and then, much later, print a message to the console that’s unrelated to the cause.

We can bring these errors to the surface by listening for a special “REQUEST_ERROR” type (which must be looked up at runtime) on the current ModuleLoader instance:

(ns example.listen 
  (:require [applied-science.js-interop :as j])
  (:import [goog.module ModuleManager ModuleLoader]))

(let [Loader (.. ModuleManager (getInstance) (getLoader))
      event-type (.. ModuleLoader -EventType -REQUEST_ERROR)]
     (.addEventListener Loader event-type
                        (fn [event]
                          (let [{:keys [error moduleIds]} (j/lookup event)]
                            (js/console.error (str moduleIds) error)))))

Alternatively, we can use Google Closure’s built-in logging facilities. This adds 1.5kb to a production build but presumably logs other useful things from other goog namespaces.

(ns my-app.glog
  (:require [goog.debug.Logger.Level :as Level]
            [goog.log :as glog])
  (:import [goog.debug Console]))

(.setCapturing (Console.) true)
(.setLevel (glog/getLogger "") Level/WARNING)

Arne Brasseur (@plexus) has written more about using goog.log: https://lambdaisland.com/blog/2019-06-10-goog-log

Matt Huebert, July 8th, 2019

Applied Science logo
Gist Press is an Applied Science experiment, built with Tufte CSS.