     (filter #(not (immutable-ns? %)))
     set))
 
-(defn create-path->name []
-  (let [lookup (into {}
-                     (map (fn [[k v]] [v k])
-                          (js->clj (gobj/filter js/goog.dependencies_.nameToPath
-                                                (fn [v k o]
-                                                  (gstring/startsWith v "../"))))))]
-    (fn [path] (get lookup path))))
-
-;; inverting this early may adversly affect perf
-;; inverting on demand would probably provide better perf
-
-;; should really create an addDependency hook to create this
-;; data structure on the fly
-(defn create-ns->dependents []
-  (let [lookup (reduce
-                (fn [a [k v]]
-                  (reduce (fn [a' [k' v']]
-                            (update-in a' [k'] conj k)) a v))
-                {}
-                (js->clj
-                 (gobj/filter js/goog.dependencies_.requires 
-                              (fn [v k o]
-                                (gstring/startsWith k "../")))))]
-    (fn [ns]
-      (set (map *path->name* (reverse (get lookup ns)))))))
-
-(declare topo-sort-helper)
-
-(defn elim-dups [[x & xs]]
-  (if (nil? x)
-    (list)
-    (cons x (elim-dups (map #(difference % x) xs)))))
-
-(defn topo-sort
-  ([deps]
-   (topo-sort deps 0 (atom (sorted-map))))
-  ([deps depth state]
-   (swap! state update-in [depth] (fnil into #{}) deps)
-   (doseq [dep deps]
-     (topo-sort-helper dep (inc depth) state))
-   (when (= depth 0)
-     (elim-dups (reverse (vals @state))))))
-
-;; from cljs.util; will use that one in when it hits mainstream
-(defn topo-sort-helper [x depth state]
-  (let [deps (*get-deps* x)]
-    (when-not (empty? deps) (topo-sort deps depth state))))
-
-;; overkill because we dont need these in order
-;; but the chance that we will soon is pretty high
+(defonce dependency-data (atom {:pathToName {} :dependents {}}))
+
+(defn path-to-name! [path name]
+  (swap! dependency-data update-in [:pathToName path] (fnil clojure.set/union #{}) #{name}))
+
+(defn setup-path->name!
+  "Setup a path to name dependencies map.
+   That goes from path -> #{ ns-names }"
+  []
+  ;; we only need this for dependents
+  (let [nameToPath (gobj/filter js/goog.dependencies_.nameToPath
+                                (fn [v k o] (gstring/startsWith v "../")))]
+    (gobj/forEach nameToPath (fn [v k o] (path-to-name! v k)))))
+
+(defn path->name
+  "returns a set of namespaces defined by a path"
+  [path]
+  (get-in @dependency-data [:pathToName path]))
+
+(defn name-to-parent! [ns parent-ns]
+  (swap! dependency-data update-in [:dependents ns] (fnil clojure.set/union #{}) #{parent-ns}))
+
+(defn setup-ns->dependents!
+  "This reverses the goog.dependencies_.requires for looking up ns-dependents."
+  []
+  (let [requires (gobj/filter js/goog.dependencies_.requires 
+                              (fn [v k o] (gstring/startsWith k "../")))]
+    (gobj/forEach
+     requires
+     (fn [v k _]
+       (gobj/forEach
+        v
+        (fn [v' k' _]
+          (doseq [n (path->name k)]
+            (name-to-parent! k' n))))))))
+
+(defn ns->dependents [ns]
+  (get-in @dependency-data [:dependents ns]))
+
+(defn build-topo-sort [get-deps]
+  (let [get-deps (memoize get-deps)]
+    (letfn [(topo-sort-helper* [x depth state]
+              (let [deps (get-deps x)]
+                (when-not (empty? deps) (topo-sort* deps depth state))))
+            (topo-sort*
+              ([deps]
+               (topo-sort* deps 0 (atom (sorted-map))))
+              ([deps depth state]
+               (swap! state update-in [depth] (fnil into #{}) deps)
+               (doseq [dep deps]
+                 (topo-sort-helper* dep (inc depth) state))
+               (when (= depth 0)
+                 (elim-dups* (reverse (vals @state))))))
+            (elim-dups* [[x & xs]]
+              (if (nil? x)
+                (list)
+                (cons x (elim-dups* (map #(difference % x) xs)))))]
+      topo-sort*)))
+
 (defn get-all-dependencies [ns]
-  (binding [*get-deps* (memoize get-requires)]
-    (apply concat (topo-sort [ns]))))
+  (let [topo-sort' (build-topo-sort get-requires)]
+    (apply concat (topo-sort' (set [ns])))))
 
 (defn get-all-dependents [nss]
-  (binding [*path->name* (create-path->name)
-            *get-deps* (memoize (create-ns->dependents))]
-    (reverse (apply concat (topo-sort nss)))))
-
-#_(prn "dependents" (get-all-dependents [ "example.core" "figwheel.client.file_reloading"]))
+  (let [topo-sort' (build-topo-sort ns->dependents)]
+    (reverse (apply concat (topo-sort' (set nss))))))
+
+#_(prn "dependents" (get-all-dependents [ "example.core" "figwheel.client.file_reloading" "cljs.core"]))
 
 #_(prn "dependencies" (get-all-dependencies "figwheel.client.file_reloading"))
 
-#_(time (get-all-dependents [ "example.core" "figwheel.client.file_reloading"]))
+#_(time (get-all-dependents [ "example.core" "figwheel.client.file_reloading" "cljs.core"]))
 
 (defn unprovide! [ns]
   (let [path (name->path ns)]

(defn before-jsload-custom-event [files]
  (utils/dispatch-custom-event "figwheel.before-js-reload" files))

(defn all? [pred coll]
  (reduce #(and %1 %2) true (map pred coll)))


(defn namespace-file-map? [m]
  (or

                 file-msg
                 {:type :namespace :namespace n}))
             deps))))


(defn sort-files [files]
  (let [keep-files (set (keep :namespace files))]
