Skip to content

Commit 40caf64

Browse files
committed
:require-global
Support :require syntax for libraries external to the build - add external-dep? helper for new :external? property for :foreign libs - Need to implicitly create :external? :foreign libs from :require-global specs - elide these libs from the js inputs, they have no files - these libs don't need `goog.require` - add basic unit tests
1 parent 389adac commit 40caf64

File tree

4 files changed

+66
-39
lines changed

4 files changed

+66
-39
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,17 @@
27812781
(if (and (.exists cljcf) (.isFile cljcf))
27822782
cljcf))))))
27832783

2784+
(defn external-dep?
2785+
"Returns true if the library is an :external? foreign dep. This means no source is provided
2786+
for the library, i.e. it will be provided by some script tag on the page, or loaded by some
2787+
other means into the JS execution environment."
2788+
#?(:cljs {:tag boolean})
2789+
[dep]
2790+
(let [js-index (:js-dependency-index @env/*compiler*)]
2791+
(if-some [[_ {:keys [foreign external?]}] (find js-index (name (-> dep lib&sublib first)))]
2792+
(and foreign external?)
2793+
false)))
2794+
27842795
(defn foreign-dep?
27852796
#?(:cljs {:tag boolean})
27862797
[dep]
@@ -3083,13 +3094,10 @@
30833094
[new-name (symbol "js" (str orig))]))
30843095
rename)}))))
30853096

3086-
(defn global-lib [lib]
3087-
(symbol "js" (str lib)))
3088-
30893097
(defn parse-global-require-spec
3090-
[env aliases spec]
3098+
[env cenv deps aliases spec]
30913099
(if (or (symbol? spec) (string? spec))
3092-
(recur env aliases [spec])
3100+
(recur env cenv deps aliases [spec])
30933101
(do
30943102
(basic-validate-ns-spec env false spec)
30953103
(let [[lib & opts] spec
@@ -3120,18 +3128,25 @@
31203128
(error env
31213129
(parse-ns-error-msg spec
31223130
":refer must be followed by a sequence of symbols in :require / :require-macros"))))
3123-
(merge
3124-
(when (some? alias)
3125-
{rk (merge {alias (global-lib lib)} {lib (global-lib lib)})})
3126-
(when (some? referred-without-renamed)
3127-
{uk (apply hash-map (interleave referred-without-renamed (repeat (global-lib lib))))})
3128-
(when (some? renamed)
3129-
{renk (reduce (fn [m [original renamed]]
3130-
(when-not (some #{original} referred)
3131-
(throw (error env
3132-
(str "Renamed symbol " original " not referred"))))
3133-
(assoc m renamed (symbol "js" (str (str lib) "." (str original)))))
3134-
{} renamed)}))))))
3131+
(swap! deps conj lib)
3132+
(let [ret (merge
3133+
(when (some? alias)
3134+
{rk (merge {alias lib} {lib lib})})
3135+
(when (some? referred-without-renamed)
3136+
{uk (apply hash-map (interleave referred-without-renamed (repeat lib)))})
3137+
(when (some? renamed)
3138+
{renk (reduce (fn [m [original renamed]]
3139+
(when-not (some #{original} referred)
3140+
(throw (error env
3141+
(str "Renamed symbol " original " not referred"))))
3142+
(assoc m renamed (symbol (str lib) (str original))))
3143+
{} renamed)}))]
3144+
(swap! cenv assoc-in [:js-dependency-index (str lib)]
3145+
{:external? true
3146+
:foreign true
3147+
:provides [(str lib)]
3148+
:global-exports {lib lib}})
3149+
ret)))))
31353150

31363151
(defn parse-require-spec [env macros? deps aliases spec]
31373152
(if (or (symbol? spec) (string? spec))
@@ -3435,7 +3450,7 @@
34353450
:use-macros (comp (partial parse-require-spec env true deps aliases)
34363451
(partial use->require env))
34373452
:import (partial parse-import-spec env deps)
3438-
:require-global #(parse-global-require-spec env aliases %)}
3453+
:require-global #(parse-global-require-spec env env/*compiler* deps aliases %)}
34393454
valid-forms (atom #{:use :use-macros :require :require-macros :require-global :import})
34403455
reload (atom {:use nil :require nil :use-macros nil :require-macros nil})
34413456
reloads (atom {})

src/main/clojure/cljs/closure.clj

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,13 +1127,17 @@
11271127
(let [requires (set (mapcat deps/-requires inputs))
11281128
required-js (js-dependencies opts requires)]
11291129
(concat
1130-
(map
1131-
(fn [{:keys [foreign url file provides requires] :as js-map}]
1132-
(let [url (or url (io/resource file))]
1133-
(merge
1134-
(javascript-file foreign url provides requires)
1135-
js-map)))
1136-
required-js)
1130+
(->> required-js
1131+
;; :foreign-libs which declare :external? have no sources (they are included
1132+
;; on the page via some script tag we'll never see). :require-global libs are
1133+
;; implicit :foreign-libs where :external? is true
1134+
(remove :external?)
1135+
(map
1136+
(fn [{:keys [foreign url file provides requires] :as js-map}]
1137+
(let [url (or url (io/resource file))]
1138+
(merge
1139+
(javascript-file foreign url provides requires)
1140+
js-map)))))
11371141
(when (-> @env/*compiler* :options :emit-constants)
11381142
[(constants-javascript-file opts)])
11391143
inputs)))

src/main/clojure/cljs/compiler.cljc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,10 @@
13671367
escape-string
13681368
wrap-in-double-quotes)
13691369
");"))
1370-
(emitln "goog.require('" (munge lib) "');"))))]
1370+
(if-not (ana/external-dep? lib)
1371+
(emitln "goog.require('" (munge lib) "');")
1372+
;; TODO: validate the lib exists
1373+
))))]
13711374
:cljs
13721375
[(and (ana/foreign-dep? lib)
13731376
(not (keyword-identical? optimizations :none)))

src/test/clojure/cljs/analyzer_tests.clj

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -395,18 +395,23 @@
395395
:rename {JSSymbol js/Symbol}}))))
396396

397397
(deftest test-parse-require-global
398-
(let [parsed (ana/parse-global-require-spec {} (atom {:fns {}})
399-
'[React :refer [createElement] :as react])]
398+
(let [cenv (atom {})
399+
deps (atom [])
400+
parsed (ana/parse-global-require-spec {} cenv deps (atom {:fns {}})
401+
'[React :refer [createElement] :as react])]
402+
(println (pr-str @cenv) (pr-str @deps))
400403
(is (= parsed
401-
'{:require {react js/React
402-
React js/React}
403-
:use {createElement js/React}})))
404-
(let [parsed (ana/parse-global-require-spec {} (atom {:fns {}})
405-
'[React :refer [createElement] :rename {createElement create} :as react])]
404+
'{:require {react React
405+
React React}
406+
:use {createElement React}})))
407+
(let [cenv (atom {})
408+
deps (atom [])
409+
parsed (ana/parse-global-require-spec {} cenv deps (atom {:fns {}})
410+
'[React :refer [createElement] :rename {createElement create} :as react])]
406411
(is (= parsed
407-
'{:require {react js/React
408-
React js/React}
409-
:rename {create js/React.createElement}}))))
412+
'{:require {react React
413+
React React}
414+
:rename {create React/createElement}}))))
410415

411416
(deftest test-cljs-1785-js-shadowed-by-local
412417
(let [ws (atom [])]
@@ -1582,7 +1587,7 @@
15821587
'(ns foo.core
15831588
(:require-global [React :as react :refer [createElement]]))))]
15841589
(is (= (:requires parsed-ns)
1585-
'{React js/React
1586-
react js/React}))
1590+
'{React React
1591+
react React}))
15871592
(is (= (:uses parsed-ns)
1588-
'{createElement js/React})))))
1593+
'{createElement React})))))

0 commit comments

Comments
 (0)