 
 (defonce
   ^{:doc "Each runtime environment provides various ways to eval JavaScript
-  source. Whatever function *eval-fn* is bound to will be passed source to eval
-  (a string). The result of eval will be passed back immediately to the caller."
+  source. Whatever function *eval-fn* is bound to will be passed a map
+  containing the following keys:
+
+  :lang   - the language, :clj or :js
+  :source - the source of the library (a string)
+  :name   - optional, used to unique identify the script
+  :path   - optional, relative URL style path representing location
+
+  The result of evaluation should be the return value."
     :dynamic true}
   *eval-fn*
   (fn [js-source]
     (throw (js/Error. "No *eval-fn* set"))))
+
+(defn js-eval [{:keys [source] :as resource}]
+  (js/eval source))
 
 (defn empty-state []
   (env/default-compiler-env))

             (let [js-source (.toString sb)]
               (when (:verbose opts)
                 (debug-prn js-source))
               (cb (*eval-fn* js-source))))))))))

(defn eval-str
  ([state source cb]
   (eval-str state source nil cb))
  ([state source opts cb]
   (eval-str*
     {:*compiler*     state
      :*cljs-ns*      'cljs.user

           (-> (:*cljs-dep-set* bound-vars) meta :dep-path)))
       (if (seq deps)
         (let [dep (first deps)]
           ((:*load-fn* bound-vars) {:name dep :path (ns->relpath dep)}
             (fn [resource]
               (assert (or (map? resource) (nil? resource))
                 "*load-fn* may only return a map or nil")
               (if resource
                 (let [{:keys [lang source]} resource]
                   (condp = lang
                     :clj (analyze* bound-vars source opts
                            (fn []
