Search code examples
clojureboot-clj

Using a resources/public directory in a boot-clj project


I'm trying to setup a boot project, which uses a resource directory holding a subdirectory public. The later should contain for instance all the web related content, the compiled clojurescript etc.

This makes sense for the case you want to hold resources which are not meant to be exposed publicly.

It works perfectly when doing so without the extra public directory. When trying to use the additional subdir, I'm getting errors. Here are the relevant configurations:

In the build.boot:

(set-env! :resource-paths #{"resources"} ...)

...

(deftask dev
  []
  (comp
   (serve
    :handler 'myapp.server/handler
    :reload true
    :port 3000)
   (watch)
   (reload)
   (cljs-repl)
   (cljs)
   (target :dir #{"resources/public"})))

From inside the resources directory:

bash-4.3$ tree
└── public
    ├── index.html
    └── js
        └── main.cljs.edn

Whereas main.cljs.edn looks like:

{:require [{{name}}.core]
 :compiler-options {:asset-path "js/main.out"}}

When invoking boot dev the following occurs: ClojureScript keeps on compiling with errors, until the process is killed manually. It looks like a recursive error related to some relative paths.

Compiling ClojureScript...
• public/js/main.js
Writing target dir(s)...
java.util.concurrent.ExecutionException: java.nio.file.NoSuchFileException: resources/public/public/public/js/main.out/goog/deps.js

whereas the longer it keeps running the public/public/public/.. expands.

Anybody suggestions where this could be fixed?


Update

Here is an updated version of the question:

Consider this structure of a resources folder:

bash-4.3$ tree
└── private_file.txt
└── public
    ├── index.html
    └── js
        └── main.cljs.edn

And the following parts from build.boot:

   (set-env! :resource-paths #{"resources"} ...)

   (deftask dev
      []
      (comp
       (serve
        :handler 'myapp.server/handler
        :reload true
        :port 3000)
       (watch)
       (reload)
       (cljs-repl)
       (cljs)
       (target)))

'myapp.server/handler knows to just serve files from resources/public (implemented by wrap-resource or the compojure equivalent resources. The later even defaults to "private".

But the problem occurs even earlier: when running boot dev the whole resources directory gets reproduced in the target directory, including private_file.txt of course. (is this intended behavior?, I mean the file could be quite big and then it would consume double of the disc space)

At this point I'm not sure how the :asset-path from inside main affects this. In the example here I kept it to "js/main.out", which might be incorrect.


Solution

  • I think the issue is that your are putting your generated code into your source directory and it might cause your build tasks to get confused as they will start consuming files they are generating. The culprit is:

    (target :dir #{"resources/public"})
    

    I would leave it as the default:

    (target :dir #{"target"})
    

    which is equivalent to just

    (target)
    

    As you are using serve task with providing your own ring handler ('myapp.server/handler) you also need to make sure that your handler will serve the resources from your classpath by specifying the correct root directory on your classpath ("public"). Probably you are already using ring.middleware.resource/wrap-resource like that:

    (wrap-resource handler "public")
    

    The last thing is your main.cljs.edn file. Its :asset-path should be set to js as it should be the relative path to JS files served by your server/handler (files from target/public/js will be served http://localhost:xxxx/js).

    With this setup your source files (html, css and other files from resources/public) as well as files generated by tasks like cljs in target/public should be available in your browser.