clojure.browser.repl/bootstrap

functionsince v0.0-3115Edit
(bootstrap)

Source docstring:
Reusable browser REPL bootstrapping. Patches the essential functions
in goog.base to support re-loading of namespaces after page load.
Source code @ clojurescript:src/main/cljs/clojure/browser/repl.cljs
(defn bootstrap
  []
  ;; Monkey-patch goog.provide if running under optimizations :none - David
  (when-not js/COMPILED
    (set! (.-require__ js/goog) js/goog.require)
    ;; suppress useless Google Closure error about duplicate provides
    (set! (.-isProvided_ js/goog) (fn [name] false))
    ;; provide cljs.user
    (goog/constructNamespace_ "cljs.user")
    (set! (.-writeScriptTag__ js/goog)
      (fn [src opt_sourceText]
        ;; the page is already loaded, we can no longer leverage document.write
        ;; instead construct script tag elements and append them to the body
        ;; of the page, to avoid parallel script loading enforce sequential
        ;; load with a simple load queue
        (let [loaded (atom false)
              onload (fn []
                       (when (and load-queue (false? @loaded))
                         (swap! loaded not)
                         (if (zero? (alength load-queue))
                           (set! load-queue nil)
                           (.apply js/goog.writeScriptTag__ nil (.shift load-queue)))))]
          (.appendChild js/document.body
            (as-> (.createElement js/document "script") script
              (doto script
                (gobj/set "type" "text/javascript")
                (gobj/set "onload" onload)
                (gobj/set "onreadystatechange" onload)) ;; IE
              (if (nil? opt_sourceText)
                (doto script (gobj/set "src" src))
                (doto script (gdom/setTextContent opt_sourceText))))))))
    ;; queue or load
    (set! (.-writeScriptTag_ js/goog)
      (fn [src opt_sourceText]
        (if load-queue
          (.push load-queue #js [src opt_sourceText])
          (do
            (set! load-queue #js [])
            (js/goog.writeScriptTag__ src opt_sourceText)))))
    ;; In the latest Closure library implementation, there is no goog.writeScriptTag_,
    ;; to monkey-patch. The behavior of interest is instead in goog.Dependency.prototype.load,
    ;; which first checks and uses CLOSURE_IMPORT_SCRIPT if defined. So we hook our desired
    ;; behavior here.
    (when goog/debugLoader_
      (set! js/CLOSURE_IMPORT_SCRIPT (.-writeScriptTag_ js/goog)))
    ;; we must reuse Closure library dev time dependency management, under namespace
    ;; reload scenarios we simply delete entries from the correct private locations
    (set! (.-require js/goog)
      (fn [src reload]
        (when (= reload "reload-all")
          (set! (.-cljsReloadAll_ js/goog) true))
        (let [reload? (or reload (.-cljsReloadAll_ js/goog))]
          (when reload?
            (if (some? goog/debugLoader_)
              (let [path (.getPathFromDeps_ goog/debugLoader_ src)]
                (gobj/remove (.-written_ goog/debugLoader_) path)
                (gobj/remove (.-written_ goog/debugLoader_)
                  (str js/goog.basePath path)))
              (let [path (gobj/get js/goog.dependencies_.nameToPath src)]
                (gobj/remove js/goog.dependencies_.visited path)
                (gobj/remove js/goog.dependencies_.written path)
                (gobj/remove js/goog.dependencies_.written
                  (str js/goog.basePath path)))))
          (let [ret (.require__ js/goog src)]
            (when (= reload "reload-all")
              (set! (.-cljsReloadAll_ js/goog) false))
            ;; handle requires from Closure Library goog.modules
            (if (js/goog.isInModuleLoader_)
              (js/goog.module.getInternal_ src)
              ret)))))))