Skip to content

Commit 96b38e2

Browse files
author
Luke VanderHart
committed
Added support for google closure compilation of foreign libraries
1 parent b216d0d commit 96b38e2

File tree

1 file changed

+64
-13
lines changed

1 file changed

+64
-13
lines changed

src/clj/cljs/closure.clj

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@
161161
(defmethod to-url String [s] (to-url (io/file s)))
162162

163163
(defprotocol IJavaScript
164+
(-foreign? [this] "Whether the Javascript represents a foreign
165+
library (a js file that not have any goog.provide statement")
164166
(-url [this] "The URL where this JavaScript is located. Returns nil
165167
when JavaScript exists in memory only.")
166168
(-provides [this] "A list of namespaces that this JavaScript provides.")
@@ -170,12 +172,14 @@
170172
(extend-protocol IJavaScript
171173

172174
String
175+
(-foreign? [this] false)
173176
(-url [this] nil)
174177
(-provides [this] (:provides (parse-js-ns (string/split-lines this))))
175178
(-requires [this] (:requires (parse-js-ns (string/split-lines this))))
176179
(-source [this] this)
177180

178181
clojure.lang.IPersistentMap
182+
(-foreign? [this] (:foreign this))
179183
(-url [this] (or (:url this)
180184
(to-url (:file this))))
181185
(-provides [this] (map name (:provides this)))
@@ -184,18 +188,20 @@
184188
s
185189
(slurp (io/reader (-url this))))))
186190

187-
(defrecord JavaScriptFile [^URL url provides requires]
191+
(defrecord JavaScriptFile [foreign ^URL url provides requires]
188192
IJavaScript
193+
(-foreign? [this] foreign)
189194
(-url [this] url)
190195
(-provides [this] provides)
191196
(-requires [this] requires)
192197
(-source [this] (slurp (io/reader url))))
193198

194-
(defn javascript-file [^URL url provides requires]
195-
(JavaScriptFile. url (map name provides) (map name requires)))
199+
(defn javascript-file [foreign ^URL url provides requires]
200+
(JavaScriptFile. foreign url (map name provides) (map name requires)))
196201

197202
(defn map->javascript-file [m]
198-
(javascript-file (to-url (:file m))
203+
(javascript-file (:foreign m)
204+
(to-url (:file m))
199205
(:provides m)
200206
(:requires m)))
201207

@@ -371,6 +377,27 @@
371377
;; need for closurebuilder. cljs dependencies will be compiled as
372378
;; needed.
373379

380+
(defn find-url
381+
"Given a string, returns a URL. Attempts to resolve as a classpath-relative
382+
path, then as a path relative to the working directory or a URL string"
383+
[path-or-url]
384+
(or (io/resource path-or-url)
385+
(try (io/as-url path-or-url)
386+
(catch java.net.MalformedURLException e
387+
false))
388+
(io/as-url (io/as-file path-or-url))))
389+
390+
(defn load-foreign-library*
391+
"Given a library spec (a map containing the keys :file
392+
and :provides), returns a map containing :provides, :requires, :file
393+
and :url"
394+
[lib-spec]
395+
(merge lib-spec {:foreign true
396+
:requires nil
397+
:url (find-url (:file lib-spec))}))
398+
399+
(def load-foreign-library (memoize load-foreign-library*))
400+
374401
(defn load-library*
375402
"Given a path to a JavaScript library, which is a directory
376403
containing Javascript files, return a list of maps
@@ -386,15 +413,22 @@
386413

387414
(def load-library (memoize load-library*))
388415

389-
(defn library-dependencies [{:keys [libs]}]
390-
(mapcat load-library libs))
416+
(defn library-dependencies [{:keys [libs foreign-libs]}]
417+
(concat
418+
(mapcat load-library libs)
419+
(map load-foreign-library foreign-libs)))
391420

392421
(comment
393422
;; load one library
394423
(load-library* "closure/library/third_party/closure")
395424
;; load all library dependencies
396425
(library-dependencies {:libs ["closure/library/third_party/closure"]})
397-
)
426+
(library-dependencies {:foreign-libs [{:file "http://example.com/remote.js"
427+
:provides ["my.example"]}]})
428+
(library-dependencies {:foreign-libs [{:file "local/file.js"
429+
:provides ["my.example"]}]})
430+
(library-dependencies {:foreign-libs [{:file "cljs/nodejs_externs.js"
431+
:provides ["my.example"]}]}))
398432

399433
(defn goog-dependencies*
400434
"Create an index of Google dependencies by namespace and file name."
@@ -414,6 +448,7 @@
414448

415449
(def goog-dependencies (memoize goog-dependencies*))
416450

451+
417452
(defn js-dependency-index
418453
"Returns the index for all JavaScript dependencies. Lookup by
419454
namespace or file name."
@@ -501,7 +536,8 @@
501536
(let [requires (mapcat -requires inputs)
502537
required-cljs (cljs-dependencies opts requires)
503538
required-js (js-dependencies opts (set (concat (mapcat -requires required-cljs) requires)))]
504-
(concat (map #(-> (javascript-file (or (:url %) (io/resource (:file %)))
539+
(concat (map #(-> (javascript-file (:foreign %)
540+
(or (:url %) (io/resource (:file %)))
505541
(:provides %)
506542
(:requires %))
507543
(assoc :group (:group %))) required-js)
@@ -520,10 +556,16 @@
520556
(str "goog.provide('test.app');\n"
521557
"goog.require('goog.array');\n"
522558
"goog.require('goog.dom.query');"))
559+
;; add dependencies with foreign lib
560+
(add-dependencies {:foreign-libs [{:file "samples/hello/src/hello/core.cljs"
561+
:provides ["example.lib"]}]}
562+
(str "goog.provide('test.app');\n"
563+
"goog.require('example.lib');\n"))
523564
;; add dependencies to a JavaScriptFile record
524-
(add-dependencies {} (javascript-file (to-url "samples/hello/src/hello/core.cljs")
525-
["hello.core"]
526-
["goog.array"]))
565+
(add-dependencies {} (javascript-file false
566+
(to-url "samples/hello/src/hello/core.cljs")
567+
["hello.core"]
568+
["goog.array"]))
527569
)
528570

529571
;; Optimize
@@ -539,9 +581,18 @@
539581

540582
(defmethod javascript-name JavaScriptFile [js] (javascript-name (-url js)))
541583

584+
(defn build-provides
585+
"Given a vector of provides, builds required goog.provide statements"
586+
[provides]
587+
(apply str (map #(str "goog.provide('" % "');\n") provides)))
588+
589+
542590
(defmethod js-source-file JavaScriptFile [_ js]
543-
(when-let [url (-url js)]
544-
(js-source-file (javascript-name url) (io/input-stream url))))
591+
(when-let [url (-url js)]
592+
(js-source-file (javascript-name url)
593+
(if (-foreign? js)
594+
(str (build-provides (-provides js)) (slurp url))
595+
(io/input-stream url)))))
545596

546597
(defn optimize
547598
"Use the Closure Compiler to optimize one or more JavaScript files."

0 commit comments

Comments
 (0)