javascriptclojurepedestalclojurescript-javascript-interop

Pedestal Doesn't serve static resource


I am trying to build on the Pedestal tutorial app available here.

I am trying to add cljs functionality and trying to setup a unified clojurescript and clojure environment.

My deps.edn file looks as follows:

{:paths ["src"]
 :deps {io.pedestal/pedestal.service {:mvn/version "0.5.7"}
    io.pedestal/pedestal.route   {:mvn/version "0.5.7"}
    io.pedestal/pedestal.jetty   {:mvn/version "0.5.7"}
    org.slf4j/slf4j-simple       {:mvn/version "1.7.28"}
    org.clojure/core.async       {:mvn/version "1.3.610"}
    org.clojure/tools.namespace  {:mvn/version "1.1.0"}
    org.clojure/tools.logging    {:mvn/version "1.1.0"}
    org.clojure/data.json        {:mvn/version "1.1.0"}
    org.clojure/clojurescript    {:mvn/version "1.10.758"}
    thheller/shadow-cljs         {:mvn/version "2.11.23"}
    selmer/selmer                {:mvn/version "1.12.33"}
    hiccup/hiccup                {:mvn/version "1.0.5"}}
 :mvn/repos {"central"  {:url "https://repo.maven.apache.org/maven2/"}
         "clojars"  {:url "https://clojars.org/repo/"}}}

My Shadow-cljs.edn file is as follows

{:source-paths ["src/cljs"]
 :nrepl {:port 9000}
 :dependencies [[cider/cider-nrepl "0.21.0"]]
 :builds {:app {:target :browser
            :output-dir "resources/public/js"
            :modules {:main {:init-fn frontend.core/init-fn}}}}}

My Folder structure looks as follows:

enter image description here

The website doesn't do anything different from the pedestal tutorial, aside from using selmer to render an HTML template to create a H1 tag with "Hello, World!" or "Hello, name!". Inside the html I've included the main.js generated from clojurescript by shadow-cljs.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>Hello, {{name}}</h1>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>

My core.clj has the following route definition

(def routes
(route/expand-routes
  #{["/hello" :get [coerce-body content-neg-intc respond-hello] :route-name :greet]
    ["/echo" :get echo]}))

(defn create-server
     []
   (http/create-server
       {::http/routes routes
        ::http/type   :jetty
        ::http/port   8800
        ::http/join?  false
        ::http/resource-path  ["resources/public" "resources/public/js" "resources/public/js/cljs-runtime"]
        ::http/secure-headers {:content-security-policy-settings {:object-src "none"}}}))

As you can see I have added the resources folder in the resource-path.

I am able to run the shadow-cljs and clj in parallel terminals and host the server as follows: enter image description here

When I look at chrome for the hosted page I get the following. enter image description here

No matter what I do I can't add the public folder in resources to the html path on the client. Such that I can not load the main.js with the page. Why is that? I am a newbie with both clojure and pedestal so maybe I am missing something obvious. Please can someone help me with this problem? I am not sure how to proceed. The Pedestal documentation is not very detailed in this regard.


Solution

  • There are two problems with your setup:

    1. The key ::http/resource-path takes a single element and not a vector.
    2. As the name of the key indicates, the path must be a resource in the Java sense: the files are actually loaded by a ClassLoader (the resource could be inside a jar file).

    In your case, you can do the following:

    1. add "resources" to the :src in your deps.edn file (the maven repo config is not necessary as maven central and clojars are always included);

    2. use "public" as value for the key ::http/resource-path.

    Your edn file becomes:

    {:paths ["src" "resources"]
     :deps {io.pedestal/pedestal.service {:mvn/version "0.5.7"}
        io.pedestal/pedestal.route   {:mvn/version "0.5.7"}
        io.pedestal/pedestal.jetty   {:mvn/version "0.5.7"}
        org.slf4j/slf4j-simple       {:mvn/version "1.7.28"}
        org.clojure/core.async       {:mvn/version "1.3.610"}
        org.clojure/tools.namespace  {:mvn/version "1.1.0"}
        org.clojure/tools.logging    {:mvn/version "1.1.0"}
        org.clojure/data.json        {:mvn/version "1.1.0"}
        org.clojure/clojurescript    {:mvn/version "1.10.758"}
        thheller/shadow-cljs         {:mvn/version "2.11.23"}
        selmer/selmer                {:mvn/version "1.12.33"}
        hiccup/hiccup                {:mvn/version "1.0.5"}}}
    

    Your server config becomes:

    (defn create-server
         []
       (http/create-server
           {::http/routes routes
            ::http/type   :jetty
            ::http/port   8800
            ::http/join?  false
            ::http/resource-path  "public"
            ::http/secure-headers {:content-security-policy-settings {:object-src "none"}}}))