     (catch Throwable ex (println (.getMessage ex)))))
 
 (defn rhino-setup [repl-env opts]
-  (let [env   (ana/empty-env)
-        scope (:scope repl-env)]
+  (let [opts    (merge {:output-dir ".cljs_rhino_repl"} opts)
+        scope   (:scope repl-env)
+        env     (ana/empty-env)
+        core    (io/resource "cljs/core.cljs")
+        base-js (slurp (io/resource "goog/base.js"))
+        core-js (closure/compile core
+                  (assoc opts
+                    :output-file
+                    (closure/src-file->target-file core)))
+        deps    (closure/add-dependencies opts core-js)
+        output-dir (util/output-directory opts)
+        repl-deps (io/file output-dir "rhino_repl_deps.js")]
+    ;; emit core and deps
+    (apply closure/output-unoptimized
+      (assoc opts :output-to (.getPath repl-deps)) deps)
+
+    ;; setup back references & output stream
+    (ScriptableObject/putProperty scope
+      "___repl_env" (Context/javaToJS repl-env scope))
     (ScriptableObject/putProperty scope "__repl_opts"
       (Context/javaToJS opts scope))
-    (repl/load-file repl-env "cljs/core.cljs" opts)
     (ScriptableObject/putProperty scope
       "out" (Context/javaToJS *out* scope))
-    (binding [ana/*cljs-ns* 'cljs.core]
-      (repl/evaluate-form repl-env env "<cljs repl>"
-        '(do
-           (set! (.-isProvided_ js/goog) (fn [_] false))
-           (set! *print-fn* (fn [x] (.write js/out x))))))))
+
+    ;; define file loading, load goog.base, load repl deps
+    (rhino-eval repl-env "bootjs" 1 bootjs)
+    (rhino-eval repl-env "goog/base.js" 1 base-js)
+    (rhino-eval repl-env "rhino_repl_deps.js" 1 (slurp repl-deps))
+
+    ;; === Bootstrap ===
+    ;; load cljs.core, setup printing
+    (repl/evaluate-form repl-env env "<cljs repl>"
+      '(do
+         (.require js/goog "cljs.core")
+         (set! *print-fn* (fn [x] (.write js/out x)))))
+
+    ;; allow namespace reloading
+    (repl/evaluate-form repl-env env "<cljs repl>"
+      '(set! js/goog.isProvided_ (fn [x] false)))
+
+    ;; monkey-patch goog.require
+    (repl/evaluate-form repl-env env "<cljs repl>"
+      '(do
+         (set! *loaded-libs* #{"cljs.core"})
+         (set! (.-require js/goog)
+           (fn [name reload]
+             (when (or (not (contains? *loaded-libs* name)) reload)
+               (set! *loaded-libs* (conj (or *loaded-libs* #{}) name))
+               (js/CLOSURE_IMPORT_SCRIPT
+                 (aget (.. js/goog -dependencies_ -nameToPath) name)))))))))
 
 (defrecord RhinoEnv []
   repl/IReplEnvOptions

  (time (reduce + [1 2 3 4 5]))
  (even? :a)
  (throw (js/Error. "There was an error"))
  (load-file "clojure/string.cljs")
  (clojure.string/triml "   hello")
  (clojure.string/reverse "   hello")


                                   RhinoException Undefined]))

(def ^String bootjs
  (str "var global = this;\n"
       "CLOSURE_IMPORT_SCRIPT = function(src) {\n"
       "    var ns = \"cljs.repl.rhino\","
       "        name = \"load-file\","
       "        loadFile = Packages.clojure.lang.RT[\"var\"](ns,name);\n"
       "    if(src) loadFile.invoke(___repl_env, __repl_opts, src);\n"
       "};\n"))

;; =============================================================================
;; Protocols
