       :dot-call
       (comp/emits f ".call(" (comma-sep (cons "null" args)) ")"))))
 
+;; fixes an issue where the cljs.core variant assumes that `resolve-var` will only return
+;; a js/foo symbol if x is also js/something which isn't true in many cases for shadow-cljs
+;; where npm deps especially resolve some/foo to js/module$something.foo
+
+;; https://github.com/clojure/clojurescript/blob/f884af0aef03147f3eef7a680579f704a7b6b81c/src/main/clojure/cljs/core.cljc#L991
+;; this introduces the new "resolved" and uses that in the following cond-> as opposed to testing the js namespace on x only
+(defn shadow-exists?
+  "Return true if argument exists, analogous to usage of typeof operator
+   in JavaScript."
+  [&form &env x]
+  (if (symbol? x)
+    (let [resolved (:name (ana/resolve-var &env x))
+          y (cond-> resolved
+              (= "js" (namespace resolved)) name)
+          segs (str/split (str (str/replace (str y) "/" ".")) #"\.")
+          n (count segs)
+          syms (map
+                 #(vary-meta (symbol "js" (str/join "." %))
+                    assoc :cljs.analyzer/no-resolve true)
+                 (reverse (take n (iterate butlast segs))))
+          js (str/join " && " (repeat n "(typeof ~{} !== 'undefined')"))]
+      (-> (concat (list 'js* js) syms)
+          ;; cljs.core/bool-expr is private ...
+          (vary-meta assoc :tag 'boolean)))
+    `(some? ~x)))
+
 (defn install-hacks! []
   ;; cljs.analyzer tweaks
   (replace-fn! #'ana/load-core shadow-load-core)


  (replace-fn! #'cljs.core/goog-define goog-define)
  (replace-fn! #'cljs.core/defonce shadow-defonce)

  ;; remove these for now, not worth the trouble
  ;; (replace-fn! #'test/deftest @#'shadow-deftest)

                    (.concat (array ~this-sym) (cljs.core/aclone ~argsym)))))
             (meta form)))]
      (ifn-invoke-methods type type-sym form))))
