refactor: move TodoMVC example into example/ directory
- example/todomvc/pocketbook/todomvc.cljs — app source - example/todomvc/todomvc.html — page - example/todomvc/js/ — compiled output (gitignored) Server static file serving is now filesystem-based via --static-dir flag instead of classpath resources. No static dir by default (API only); bb server passes --static-dir example/todomvc. Removed resources/public/ — library has no bundled static assets.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@
|
|||||||
target/
|
target/
|
||||||
out/
|
out/
|
||||||
resources/public/js/
|
resources/public/js/
|
||||||
|
example/todomvc/js/
|
||||||
*.db
|
*.db
|
||||||
*.db-shm
|
*.db-shm
|
||||||
*.db-wal
|
*.db-wal
|
||||||
|
|||||||
4
bb.edn
4
bb.edn
@@ -1,6 +1,6 @@
|
|||||||
{:tasks
|
{:tasks
|
||||||
{server {:doc "Start the Pocketbook sync server"
|
{server {:doc "Start the Pocketbook sync server (serves example app)"
|
||||||
:task (shell "clj" "-M:server")}
|
:task (shell "clj" "-M:server" "--static-dir" "example/todomvc")}
|
||||||
|
|
||||||
cljs {:doc "Compile ClojureScript (one-shot)"
|
cljs {:doc "Compile ClojureScript (one-shot)"
|
||||||
:task (shell "clj" "-M:cljs")}
|
:task (shell "clj" "-M:cljs")}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{:main pocketbook.todomvc
|
{:main pocketbook.todomvc
|
||||||
:output-to "resources/public/js/main.js"
|
:output-to "example/todomvc/js/main.js"
|
||||||
:output-dir "resources/public/js/out"
|
:output-dir "example/todomvc/js/out"
|
||||||
:asset-path "js/out"
|
:asset-path "js/out"
|
||||||
:optimizations :none}
|
:optimizations :none}
|
||||||
|
|||||||
8
deps.edn
8
deps.edn
@@ -1,4 +1,4 @@
|
|||||||
{:paths ["src" "resources"]
|
{:paths ["src"]
|
||||||
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
|
||||||
http-kit/http-kit {:mvn/version "2.8.0"}
|
http-kit/http-kit {:mvn/version "2.8.0"}
|
||||||
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
com.cognitect/transit-clj {:mvn/version "1.0.333"}
|
||||||
@@ -15,12 +15,14 @@
|
|||||||
:server {:main-opts ["-m" "pocketbook.server"]}
|
:server {:main-opts ["-m" "pocketbook.server"]}
|
||||||
|
|
||||||
;; ClojureScript client build
|
;; ClojureScript client build
|
||||||
:cljs {:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.132"}
|
:cljs {:extra-paths ["example/todomvc"]
|
||||||
|
:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.132"}
|
||||||
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
||||||
org.clojure/core.async {:mvn/version "1.7.701"}}
|
org.clojure/core.async {:mvn/version "1.7.701"}}
|
||||||
:main-opts ["-m" "cljs.main" "-co" "build.edn" "-c"]}
|
:main-opts ["-m" "cljs.main" "-co" "build.edn" "-c"]}
|
||||||
|
|
||||||
:cljs-dev {:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.132"}
|
:cljs-dev {:extra-paths ["example/todomvc"]
|
||||||
|
:extra-deps {org.clojure/clojurescript {:mvn/version "1.11.132"}
|
||||||
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
com.cognitect/transit-cljs {:mvn/version "0.8.280"}
|
||||||
org.clojure/core.async {:mvn/version "1.7.701"}}
|
org.clojure/core.async {:mvn/version "1.7.701"}}
|
||||||
:main-opts ["-m" "cljs.main" "-co" "build.edn" "-w" "src" "-c"]}}}
|
:main-opts ["-m" "cljs.main" "-co" "build.edn" "-w" "src" "-c"]}}}
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
(def default-config
|
(def default-config
|
||||||
{:port 8090
|
{:port 8090
|
||||||
:db-path "pocketbook.db"
|
:db-path "pocketbook.db"
|
||||||
:users nil ;; nil = no auth, or {"alice" {:token "abc" :groups #{"todo"}}}
|
:static-dir nil ;; nil = no static serving, or path like "example/todomvc"
|
||||||
:cors true})
|
:users nil ;; nil = no auth, or {"alice" {:token "abc" :groups #{"todo"}}}
|
||||||
|
:cors true})
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Auth
|
;; Auth
|
||||||
@@ -135,15 +136,19 @@
|
|||||||
(subs path (inc i)))))
|
(subs path (inc i)))))
|
||||||
|
|
||||||
(defn- serve-static
|
(defn- serve-static
|
||||||
"Attempt to serve a static file from resources/public. Returns response or nil."
|
"Attempt to serve a static file from a directory. Returns response or nil."
|
||||||
[uri]
|
[static-dir uri]
|
||||||
(let [path (str "public" (if (= "/" uri) "/todomvc.html" uri))
|
(when static-dir
|
||||||
resource (io/resource path)]
|
(let [rel (if (= "/" uri) "/todomvc.html" uri)
|
||||||
(when resource
|
file (io/file static-dir (subs rel 1))]
|
||||||
{:status 200
|
(when (and (.isFile file) (.canRead file)
|
||||||
:headers {"Content-Type" (get content-types (ext path) "application/octet-stream")
|
;; Prevent path traversal
|
||||||
"Cache-Control" "no-cache"}
|
(.startsWith (.toPath file) (.toPath (io/file static-dir))))
|
||||||
:body (io/input-stream resource)})))
|
{:status 200
|
||||||
|
:headers {"Content-Type" (get content-types (ext (.getName file))
|
||||||
|
"application/octet-stream")
|
||||||
|
"Cache-Control" "no-cache"}
|
||||||
|
:body (io/input-stream file)}))))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Ring handler
|
;; Ring handler
|
||||||
@@ -171,7 +176,7 @@
|
|||||||
|
|
||||||
;; Static files (including / → todomvc.html)
|
;; Static files (including / → todomvc.html)
|
||||||
:else
|
:else
|
||||||
(or (serve-static (:uri req))
|
(or (serve-static (:static-dir config) (:uri req))
|
||||||
{:status 404
|
{:status 404
|
||||||
:headers {"Content-Type" "text/plain"}
|
:headers {"Content-Type" "text/plain"}
|
||||||
:body "Not found"}))]
|
:body "Not found"}))]
|
||||||
@@ -195,7 +200,9 @@
|
|||||||
(println (str "🔶 Pocketbook server running on http://localhost:" (:port config)))
|
(println (str "🔶 Pocketbook server running on http://localhost:" (:port config)))
|
||||||
(println (str " Database: " (:db-path config)))
|
(println (str " Database: " (:db-path config)))
|
||||||
(println (str " Auth: " (if (:users config) "enabled" "disabled")))
|
(println (str " Auth: " (if (:users config) "enabled" "disabled")))
|
||||||
(println (str " TodoMVC: http://localhost:" (:port config) "/todomvc.html"))
|
(when (:static-dir config)
|
||||||
|
(println (str " Static: " (:static-dir config)))
|
||||||
|
(println (str " App: http://localhost:" (:port config) "/")))
|
||||||
{:stop server
|
{:stop server
|
||||||
:ds ds
|
:ds ds
|
||||||
:config config})))
|
:config config})))
|
||||||
@@ -210,11 +217,13 @@
|
|||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
(defn -main [& args]
|
(defn -main [& args]
|
||||||
(let [port (some-> (first args) parse-long)
|
(let [opts (apply hash-map (map #(if (str/starts-with? % "--")
|
||||||
db-path (second args)
|
(keyword (subs % 2))
|
||||||
config (cond-> {}
|
%)
|
||||||
port (assoc :port port)
|
args))
|
||||||
db-path (assoc :db-path db-path))]
|
config (cond-> {}
|
||||||
|
(:port opts) (assoc :port (parse-long (:port opts)))
|
||||||
|
(:db-path opts) (assoc :db-path (:db-path opts))
|
||||||
|
(:static-dir opts) (assoc :static-dir (:static-dir opts)))]
|
||||||
(start! config)
|
(start! config)
|
||||||
;; Keep the server running
|
|
||||||
@(promise)))
|
@(promise)))
|
||||||
|
|||||||
@@ -61,14 +61,13 @@
|
|||||||
;; Tests
|
;; Tests
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
(deftest serves-static-root
|
(deftest root-returns-404-without-static-dir
|
||||||
(let [req (-> (HttpRequest/newBuilder)
|
(let [req (-> (HttpRequest/newBuilder)
|
||||||
(.uri (URI. (url "/")))
|
(.uri (URI. (url "/")))
|
||||||
(.GET)
|
(.GET)
|
||||||
(.build))
|
(.build))
|
||||||
resp (.send client req (HttpResponse$BodyHandlers/ofString))]
|
resp (.send client req (HttpResponse$BodyHandlers/ofString))]
|
||||||
(is (= 200 (.statusCode resp)))
|
(is (= 404 (.statusCode resp)))))
|
||||||
(is (.contains (.body resp) "TodoMVC"))))
|
|
||||||
|
|
||||||
(deftest push-and-pull
|
(deftest push-and-pull
|
||||||
(testing "Push new documents"
|
(testing "Push new documents"
|
||||||
|
|||||||
Reference in New Issue
Block a user