Browse files

Recognize @import in CSS as a reference

  • Loading branch information...
1 parent 69b0808 commit 7ad6422303b215d6e30bacac147ad7a4e349214d @magnars committed Jan 8, 2014
Showing with 53 additions and 34 deletions.
  1. +18 −14 src/optimus/assets/load_css.clj
  2. +35 −20 test/optimus/assets_test.clj
View
32 src/optimus/assets/load_css.clj
@@ -19,36 +19,40 @@
(pathetic/resolve (remove-url-appendages relative-url))
(pathetic/normalize)))
-(def css-url-re #"url\(['\"]?([^\)]+?)['\"]?\)")
-
-(defn- css-url-str [url]
- (str "url('" url "')"))
+(def css-url-re #"(?:url\(['\"]?([^\)]+?)['\"]?\)|@import ['\"](.+?)['\"])")
(defn- data-url? [#^String url]
(.startsWith url "data:"))
(defn- external-url? [#^String url]
(re-matches #"^(?://|http://|https://).*" url))
-(defn- replace-css-urls [file replacement-fn]
- (assoc-in file [:contents]
- (str/replace (:contents file) css-url-re
- (fn [[match url]] (if (or (data-url? url) (external-url? url))
- match
- (css-url-str (replacement-fn file url)))))))
+(defn- url-match [[match & urls]]
+ (first (remove nil? urls)))
+
+(defn- match-url-to-absolute [original-path [match :as matches]]
+ (let [url (url-match matches)]
+ (if (or (data-url? url)
+ (external-url? url))
+ match ;; leave alone
+ (str/replace match url (combine-paths original-path url)))))
+
+(defn- make-css-urls-absolute [file]
+ (->> (partial match-url-to-absolute (original-path file))
+ (str/replace (:contents file) css-url-re)
+ (assoc-in file [:contents])))
(defn- paths-in-css [file]
(->> file :contents
(re-seq css-url-re)
- (map second)
+ (map url-match)
(remove data-url?)
- (remove external-url?)
- (map #(combine-paths (original-path file) %))))
+ (remove external-url?)))
(defn create-css-asset [path contents last-modified]
(let [asset (-> (create-asset path contents
:last-modified last-modified)
- (replace-css-urls #(combine-paths (original-path %1) %2)))]
+ (make-css-urls-absolute))]
(assoc asset :references (set (paths-in-css asset)))))
(defn load-css-asset [public-dir path]
View
55 test/optimus/assets_test.clj
@@ -75,23 +75,39 @@
(->> (load-assets public-dir [#"/app/*"])
(map :path)) => ["/app/code.js"]))
-(with-files [["/main.css" "#id { background: url('/bg.png'); }"]
- ["/bg.png" "binary"]]
- (fact
- "Loading a single asset is not supported, since loading an asset
- might result in more than one in the list - when the loaded asset
- in turn references more assets.
+(fact
+ "Loading a single asset is not supported, since loading an asset
+ might result in more than one in the list - when the loaded asset in
+ turn references more assets.
- We need to load every referenced asset at this time, since this is
- when we know where the files are located. In other words, we take
- it for granted that any files referenced in a file loaded off the
- class path are present in the same folder structure."
+ We need to load every referenced asset at this time, since this is
+ when we know where the files are located. In other words, we take it
+ for granted that any files referenced in a file loaded off the class
+ path are present in the same folder structure."
+ (with-files [["/main.css" "#id { background: url('/bg.png'); }"]
+ ["/bg.png" "binary"]]
(->> (load-assets public-dir ["/main.css"])
- (map #(select-keys % #{:path :references}))) => [{:path "/main.css"
- :references #{"/bg.png"}}
+ (map #(select-keys % #{:path :references}))) => [{:path "/main.css" :references #{"/bg.png"}}
{:path "/bg.png"}]))
+(fact
+ "Imports are supported, in that they are recognized as references."
+
+ (with-files [["/main.css" "@import url('other.css');"]
+ ["/other.css" "#id { background: url('bg.png'); }"]
+ ["/bg.png" "binary"]]
+ (->> (load-assets public-dir ["/main.css"])
+ (map #(select-keys % #{:path :references}))) => [{:path "/main.css" :references #{"/other.css"}}
+ {:path "/other.css" :references #{"/bg.png"}}
+ {:path "/bg.png"}])
+
+ (with-files [["/main.css" "@import 'other.css';"]
+ ["/other.css" "#id {}"]]
+ (->> (load-assets public-dir ["/main.css"])
+ (map #(select-keys % #{:path :references}))) => [{:path "/main.css" :references #{"/other.css"}}
+ {:path "/other.css" :references #{}}]))
+
(with-files [["/main.css" "#id { background: url(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)}"]]
(fact
"Data URLs are left alone."
@@ -127,16 +143,15 @@
(-> (load-assets public-dir ["/theme/styles/main.css"])
first :contents) => "#id { background: url('/theme/images/bg.png'); }"))
-(with-files [["/query.css" "#id { background: url(\"/bg.png?query\"); }"]
- ["/ref.css" "#id { background: url(/bg.png#ref); }"]
- ["/bg.png" "binary"]]
-
- (fact
- "URLs can have querys and refs, but file paths can't. To find the
+(fact
+ "URLs can have querys and refs, but file paths can't. To find the
files so we can serve them, these appendages have to be sliced off."
- (-> (load-assets public-dir ["/query.css"]) first :contents) => "#id { background: url('/bg.png'); }"
- (-> (load-assets public-dir ["/ref.css"]) first :contents) => "#id { background: url('/bg.png'); }"))
+ (with-files [["/query.css" "#id { background: url(\"/bg.png?query\"); }"]
+ ["/ref.css" "#id { background: url(/bg.png#ref); }"]
+ ["/bg.png" "binary"]]
+ (-> (load-assets public-dir ["/query.css"]) first :contents) => "#id { background: url(\"/bg.png\"); }"
+ (-> (load-assets public-dir ["/ref.css"]) first :contents) => "#id { background: url(/bg.png); }"))
(with-files [["/code.js" "1 + 2"]
["/more.js" "3 + 5"]]

0 comments on commit 7ad6422

Please sign in to comment.