Skip to content

Commit 2d08f2e

Browse files
anmonteiroswannodette
authored andcommitted
CLJS-2232: Self-host: Add support for string-based requires
1 parent 424e264 commit 2d08f2e

3 files changed

Lines changed: 107 additions & 10 deletions

File tree

src/main/cljs/cljs/js.cljs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,15 @@
575575
(check-uses-and-load-macros {:value nil} ast)))
576576
(cb {:value ast}))))
577577

578+
(defn- node-side-effects
579+
[bound-vars sb deps ns-name]
580+
(doseq [dep deps]
581+
(.append sb
582+
(with-out-str
583+
(comp/emitln (munge ns-name) "."
584+
(ana/munge-node-lib dep)
585+
" = require('" dep "');")))))
586+
578587
(defn- analyze-str* [bound-vars source name opts cb]
579588
(let [rdr (rt/indexing-push-back-reader source 1 name)
580589
eof (js-obj)
@@ -716,14 +725,22 @@
716725
(str "Could not eval " form) cause))))]
717726
(if (:error res)
718727
(cb res)
719-
(let [ast (:value res)]
728+
(let [ast (:value res)
729+
[node-deps ast] (if (keyword-identical? (:target opts) :nodejs)
730+
(let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? (:deps ast))]
731+
[node-libs (assoc ast :deps libs-to-load)])
732+
[nil ast])]
720733
(if (#{:ns :ns*} (:op ast))
721734
(ns-side-effects true bound-vars aenv ast opts
722735
(fn [res]
723736
(if (:error res)
724737
(cb res)
725-
(let [src (str "goog.provide(\"" (comp/munge (:name ast)) "\")")]
726-
(cb {:value (*eval-fn* {:source src})})))))
738+
(let [sb (StringBuffer.)]
739+
(.append sb
740+
(with-out-str (comp/emitln (str "goog.provide(\"" (comp/munge (:name ast)) "\");"))))
741+
(when-not (nil? node-deps)
742+
(node-side-effects bound-vars sb node-deps (:name ast)))
743+
(cb {:value (*eval-fn* {:source (.toString sb)})})))))
727744
(let [src (with-out-str (comp/emit ast))]
728745
(cb {:value (*eval-fn* {:source src})})))))))))
729746

@@ -822,14 +839,21 @@
822839
(str "Could not compile " name) cause))))]
823840
(if (:error res)
824841
(cb res)
825-
(let [ast (:value res)]
842+
(let [ast (:value res)
843+
[node-deps ast] (if (keyword-identical? (:target opts) :nodejs)
844+
(let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? (:deps ast))]
845+
[node-libs (assoc ast :deps libs-to-load)])
846+
[nil ast])]
826847
(.append sb (with-out-str (comp/emit ast)))
827848
(if (#{:ns :ns*} (:op ast))
828849
(ns-side-effects bound-vars aenv ast opts
829850
(fn [res]
830851
(if (:error res)
831852
(cb res)
832-
(compile-loop (:name ast)))))
853+
(do
854+
(when-not (nil? node-deps)
855+
(node-side-effects bound-vars sb node-deps (:name ast)))
856+
(compile-loop (:name ast))))))
833857
(recur ns)))))
834858
(do
835859
(when (:source-map opts)
@@ -944,7 +968,11 @@
944968
(if (:error res)
945969
(cb res)
946970
(let [ast (:value res)
947-
ns' ana/*cljs-ns*]
971+
ns' ana/*cljs-ns*
972+
[node-deps ast] (if (keyword-identical? (:target opts) :nodejs)
973+
(let [{node-libs true libs-to-load false} (group-by ana/node-module-dep? (:deps ast))]
974+
[node-libs (assoc ast :deps libs-to-load)])
975+
[nil ast])]
948976
(if (#{:ns :ns*} (:op ast))
949977
(do
950978
(.append sb
@@ -953,7 +981,10 @@
953981
(fn [res]
954982
(if (:error res)
955983
(cb res)
956-
(compile-loop ns')))))
984+
(do
985+
(when-not (nil? node-deps)
986+
(node-side-effects bound-vars sb node-deps (:name ast)))
987+
(compile-loop ns'))))))
957988
(do
958989
(.append sb (with-out-str (comp/emit ast)))
959990
(recur ns'))))))

src/main/clojure/cljs/analyzer.cljc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -744,10 +744,16 @@
744744
(str module)))
745745

746746
(defn node-module-dep?
747+
#?(:cljs {:tag boolean})
747748
[module]
748-
(contains?
749-
(get-in @env/*compiler* [:node-module-index])
750-
(str module)))
749+
#?(:clj (contains?
750+
(get-in @env/*compiler* [:node-module-index])
751+
(str module))
752+
:cljs (try
753+
(and (= *target* "nodejs")
754+
(boolean (js/require.resolve (str module))))
755+
(catch :default _
756+
false))))
751757

752758
(defn dep-has-global-exports?
753759
[module]

src/test/self/self_host/test.cljs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,66 @@
916916
(is (every? symbol? (keys (get-in @st [:cljs.analyzer/namespaces]))))
917917
(inc! l))))))
918918

919+
(deftest test-string-requires-cljs-2232
920+
(async done
921+
(let [st (cljs/empty-state)
922+
l (latch 4 done)]
923+
(cljs/compile-str
924+
(atom @st)
925+
"(ns foo.core (:require [path]))"
926+
nil
927+
{:context :expr
928+
:target :nodejs
929+
:eval node-eval}
930+
(fn [{:keys [error value] :as m}]
931+
(is (nil? error))
932+
(is (some? (re-find #"foo\.core\.node\$module\$path = require\('path'\);" value)))
933+
(inc! l)))
934+
(cljs/eval-str
935+
(atom @st)
936+
"(ns foo.core (:require [path])) (path/basename \"/foo/bar\")"
937+
nil
938+
{:context :expr
939+
:target :nodejs
940+
:eval node-eval}
941+
(fn [{:keys [error value] :as m}]
942+
(is (nil? error))
943+
(is (= value "bar"))
944+
(inc! l)))
945+
(cljs/analyze-str
946+
(atom @st)
947+
"(ns foo.core (:require [path]))"
948+
nil
949+
{:context :expr
950+
:target :nodejs
951+
:load (fn [_ cb]
952+
(cb {:lang :js
953+
:source ""}))}
954+
(fn [{:keys [error value] :as m}]
955+
(is (nil? error))
956+
(is (= (:deps value) '[path]))
957+
(inc! l)))
958+
(let [st (cljs/empty-state)]
959+
(cljs/eval
960+
st
961+
'(ns foo.core (:require [path]))
962+
{:context :expr
963+
:target :nodejs
964+
:eval node-eval}
965+
(fn [{:keys [error value] :as m}]
966+
(is (nil? error))
967+
(cljs/eval
968+
st
969+
'(path/basename "/foo/bar")
970+
{:context :expr
971+
:ns 'foo.core
972+
:target :nodejs
973+
:eval node-eval}
974+
(fn [{:keys [error value]}]
975+
(is (nil? error))
976+
(is (= value "bar"))
977+
(inc! l)))))))))
978+
919979
(defn -main [& args]
920980
(run-tests))
921981

0 commit comments

Comments
 (0)