diff --git a/src/clj_pebble/core.clj b/src/clj_pebble/core.clj
index 944d783..48edddb 100644
--- a/src/clj_pebble/core.clj
+++ b/src/clj_pebble/core.clj
@@ -8,6 +8,7 @@
(:require [clojure.walk :refer [stringify-keys]]
[clj-pebble.extensions :as ext]
[clj-pebble.standard-extensions :as std]
+ [clj-pebble.web.extensions :as web]
[clj-pebble.options :refer [options]]))
(defonce classpath-loader (ClasspathLoader.))
@@ -29,7 +30,8 @@
(defn- make-pebble-engine []
(let [engine (-> (PebbleEngine. classpath-loader)
- (ext/add-extensions-library! std/extensions))]
+ (ext/add-extensions-library! std/extensions)
+ (ext/add-extensions-library! web/extensions))]
(apply-options! engine)
engine))
diff --git a/src/clj_pebble/utils.clj b/src/clj_pebble/utils.clj
new file mode 100644
index 0000000..6d983ad
--- /dev/null
+++ b/src/clj_pebble/utils.clj
@@ -0,0 +1,27 @@
+(ns clj-pebble.utils
+ (:import (java.net URL)
+ (java.io File)))
+
+(defn inside-jar? [^File file]
+ (-> file
+ (.getPath)
+ ; the path of a file inside a jar looks something like "jar:file:/path/to/file.jar!/path/inside/jar/to/file"
+ (.contains "jar!")))
+
+(defn get-file-last-modified [^File file]
+ (if (inside-jar? file)
+ 0
+ (.lastModified file)))
+
+(defn get-resource-path
+ (^URL [^String filename]
+ (-> (Thread/currentThread)
+ (.getContextClassLoader)
+ (.getResource filename))))
+
+(defn get-resource-modification-date [^String filename]
+ (when-let [resource-filename (get-resource-path filename)]
+ (->> resource-filename
+ (.getPath)
+ (new File)
+ (get-file-last-modified))))
\ No newline at end of file
diff --git a/src/clj_pebble/web/extensions.clj b/src/clj_pebble/web/extensions.clj
new file mode 100644
index 0000000..3975002
--- /dev/null
+++ b/src/clj_pebble/web/extensions.clj
@@ -0,0 +1,80 @@
+(ns clj-pebble.web.extensions
+ (:import (java.net URI))
+ (:require [clojure.string :as str]
+ [clj-pebble.web.middleware :refer [*servlet-context-path*]]
+ [clj-pebble.options :refer [options]])
+ (:use [clj-pebble.utils]))
+
+;; TODO: while 'public' is the default with Compojure, applications can override with something else ...
+;; should make this customizable (some option added to clj-pebble.options likely ...)
+(def root-resource-path "public")
+
+(defn- get-context-url [url]
+ (str *servlet-context-path* url))
+
+(defn- relative-url? [url]
+ (if-not (str/blank? url)
+ (let [uri (new URI url)]
+ (str/blank? (.getScheme uri)))))
+
+(defn- get-resource-modification-timestamp [^String resource-url]
+ (if (relative-url? resource-url)
+ (->> (str root-resource-path resource-url)
+ (get-context-url)
+ (get-resource-modification-date))))
+
+(defn- get-url-string [url]
+ (if-let [modification-timestamp (get-resource-modification-timestamp url)]
+ ; because it looks kind of dumb to have '?0' at the end of URLs when running from a jar ...
+ (if (= modification-timestamp 0)
+ url
+ (str url "?" modification-timestamp))
+ url))
+
+(defn- minified-url? [url]
+ (re-matches #"^(.+\.)min\.(css|js)$" url))
+
+(defn- make-minified-url [^String url]
+ (let [pos (.lastIndexOf url (int \.))]
+ (if (> pos -1)
+ (let [name (subs url 0 pos)
+ extension (subs url (inc pos))]
+ (str name ".min." extension))
+ url)))
+
+(defn- get-minified-resource-url [url]
+ (if (or (not (:check-for-minified-web-resources @options))
+ (minified-url? url))
+ url
+ (let [minified-url (make-minified-url url)]
+ (if (get-resource-path (str root-resource-path minified-url))
+ minified-url
+ url))))
+
+; defined using the same type of map structure as in clj-pebble.standard-extensions
+
+(defonce extensions
+ {:functions
+ {"path"
+ {:fn (fn [url]
+ (get-context-url url))}
+
+ "stylesheet"
+ {:fn (fn [url & [media]]
+ (let [fmt (if media
+ ""
+ "")
+ resource-path (get-minified-resource-url url)]
+ (format fmt (get-url-string resource-path) media)))}
+
+ "javascript"
+ {:fn (fn [url]
+ (let [fmt ""
+ resource-path (get-minified-resource-url url)]
+ (format fmt (get-url-string resource-path))))}}
+
+ :filters
+ {}
+
+ :tests
+ {}})
\ No newline at end of file
diff --git a/src/clj_pebble/web/middleware.clj b/src/clj_pebble/web/middleware.clj
new file mode 100644
index 0000000..5b6f733
--- /dev/null
+++ b/src/clj_pebble/web/middleware.clj
@@ -0,0 +1,8 @@
+(ns clj-pebble.web.middleware)
+
+(declare ^:dynamic *servlet-context-path*)
+
+(defn wrap-servlet-context-path [handler]
+ (fn [req]
+ (binding [*servlet-context-path* (:context req)]
+ (handler req))))
\ No newline at end of file