Auto building Clojurescript files for Compojure app - clojure

I have a web application where i'm using Compojure on the server and Clojurescript on the client. I'm using the leing-cljsbuild plugin to automatically compile cljs files to js.
I'm able to generate the required client side files and load them in the browser when I set the optimizations to :whitespace or :simple, but when I set optimizations to none, the js files reference their dependencies using the local file-system path, which leads to the files not loading at all in the browser.
So, my question is how do I make the generated files use server urls instead of local file paths when they are generated by the clojurescript compiler.
Here's my project.clj file
(defproject my-proj-clj "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:dependencies [[org.clojure/clojure "1.5.1"]
[compojure "1.1.6"]
[org.clojure/tools.nrepl "0.2.3"]
[hiccup "1.0.3"]
[com.novemberain/monger "1.5.0"]
[org.clojure/clojurescript "0.0-2127"]
[jayq "2.5.0"]
]
:plugins [[lein-ring "0.8.8"]
[lein-cljsbuild "1.0.1"]
]
:ring {:handler my-proj-clj.handler/app
}
:cljsbuild { :builds
[{
:source-paths ["src/my-proj-clj"]
:compiler {
:output-dir "./resources/public/js"
:output-to "./resources/public/js/cljs-file.js"
:pretty-print true
:source-map "./resources/public/js/cljs-file.js.map"
:optimizations :none
}}]}
:profiles {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]]}}

I believe the only valid optimization values are :whitespace, :simple, or :advanced. See line 96 at https://github.com/emezeske/lein-cljsbuild/blob/1.0.1/sample.project.clj.
Thus I would use :whitespace as the optimization level (at least to get something working).
Per your post, an optimization level of :whitespace works? Thus, perhaps you can elaborate.
What results are you expecting from an optimization level of ":none". How does your expected result differ from what an optimization level of :whitespace produces?
An optimization level of :none means cljsbuild is not generating js from your cljs source (it will generate a few goog.include statements but nothing else). Try using an interactive repl to help you prototype. Try running the following : lein trampoline cljsbuild repl-rhino
Hope that helps.

I have roughly same setup, optimizations set to :none, generated files use local paths. However, browser does load the scripts.
What I have is this in index.html:
<script src="js/development/goog/base.js" type="text/javascript"></script>
<script src="js/development/main.js" type="text/javascript" ></script>
<script type="text/javascript">goog.require("ixtlan.core");</script>
this in project.clj:
:cljsbuild {
:builds [{:id "dev"
:source-paths ["src/cljs"]
:compiler {
:output-to "resources/public/js/development/main.js"
:output-dir "resources/public/js/development"
:optimizations :none
:source-map true}}
...
and routes contain:
(defroutes routes
(GET "/" [] (index))
(route/files "/" {:root "resources/public"}))
Hope, this helps.

Related

Auto-refresh/ Auto-reload assets

I'm new to clojure and i'm having a hard time figuring out how to reload/ refresh the browser when changes have been made to either html/ js/ css etc.
this is my current setup project.clj
(defproject app2 "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://exampl.com/FIXME"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.89"]
[ring/ring-core "1.5.0"]
[ring/ring-jetty-adapter "1.5.0"]
[enfocus "2.0.0-SNAPSHOT"]]
:plugins [[lein-cljsbuild "1.1.3"]
[lein-ring "0.9.7"]]
:cljsbuild {:builds [{:source-paths ["src/cljs"],
:compiler {
:main "scripts.client"
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:asset-path "js/out"
;;:pretty-print true
;;:optimizations :none
}}]}
:main app2.server/app
:ring {:handler app2.server/app :auto-reload? true :auto-refresh? true :reload-paths ["src" "resources"]}
:profiles {
:dev {
:ring {
:nrepl {
:start? true
:port 9000
}
}
}
}
)
This is my server.clj
(ns app2.server
(:use [ring.middleware.resource :only [wrap-resource]]
[ring.middleware.file-info :only [wrap-file-info]]
[ring.middleware.reload :refer [wrap-reload]])
;;(:require app2.repl)
)
(defn handler
[request]
{:status 200}
)
;handling routing "/" -> "/index.html"
(defn wrap-index [handler]
(fn [req]
(println (pr-str req))
(if (= (:uri req) "/")
(handler (assoc req :uri "/index.html"))
(handler req))))
;setting up a simple resource handler for ring
(def app (-> handler
(wrap-resource "public")
(wrap-file-info)
(wrap-index)
(wrap-reload app {:dirs ["src" "resources"]})
))
How can this be accomplished?
I'm used to developing in node and you have tools like browser sync, weinre and supervisor. What are the equivalents in clojure?
I suggest you have a look at figwheel, which lets you do hot reloading of your ClojureScript and CSS in the browser.
There is of course not one good way of setting up your build, but my way to go for languages like SASS etc. is to watch and compile them as a separate process, and have Figwheel watch the generated CSS.
For example, on one of my ClojureScript projects, I had a script file for LESS compilation which used the LESS compiler and the wr utility directly:
#!/usr/bin/env bash
lessc src/styles/main.main.less resources/public/css/main.css --source-map && cp src/styles/*.less resources/public/css
wr "lessc src/styles/main.main.less resources/public/css/main.css --source-map && cp src/styles/*.less resources/public/css" src/**/*.less
Of course you can also use things like Gulp, Webpack - or any tool you're used to.
The alternative is to use Leiningen plugins, see the list here.

Slow loading of cljsbuild in Clojure

I'm new to Clojure and I'm trying to setup a development environment where I can dynamically load my web project files using ring-server and cljsbuild
i have the following snippet in my project file
:ring {
:handler cjohansen-no.web/app
;;:auto-refresh true
;;:auto-reload? true
;;:reload-paths ["resources","src"]
;;:refresh-paths ["resources","src"]
}
:aliases {
"start-server" ["ring" "server-headless"]
"build-site" ["run" "-m" "cjohansen-no.web/export"]
"build-html" ["run" "-m" "cjohansen-no.web/export-pages"]
"build-js" ["cljsbuild" "auto" "dev"]
"build-web" ["do" ["build-site"] ["build-js"]]
"build-dev" ["pdo" ["build-web"] ["start-server"] ["auto" "build-html"]]
}
:source-paths ["src"]
:test-paths ["test/cjohansen_no" "test/cljs" "spec"]
:clean-targets [:target-path "./build/js/out"
:compile-path "classes"
:output-paths "./build/js/output"
"build/js/main.js.map"
]
:main cjohansen-no.web
:clean-non-project-classes true
:figwheel {
;;:server-port 3000
:css-dirs ["resources/public/css"]
:reload-clj-files {:clj true :cljc false}
:ring-handler cjohansen-no.web/app
:repl false
}
:cljsbuild {
:builds [
{
;; :notify-command ["growlnotify" "-m"]
:id "dev"
:source-paths ["src/cljs"]
:figwheel {
:websocket-host :js-client-host
:autoload false
:reload-dependents true
:debug true
}
:compiler {
:main scripts.core
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js/out"
:optimizations :none
:source-map true
:source-map-timestamp true
:recompile-dependents false
:pretty-print true
:asset-path "js/out"
;;:notify-command ["bin/phantomjs" "bin/speclj.js" "resources/public/js/main.js"]
}
},
....
}
:profiles {
:dev {
:dependencies [
;;[figwheel "0.5.4-7"]
]
:plugins [
[lein-pdo "0.1.1"]
[lein-ring "0.9.7"]
[lein-cljsbuild "1.1.3"]
[lein-figwheel "0.5.4-7"]
]
}
I use this snippet to run my server
(def app (->
(stasis/serve-pages get-pages)
(optimus/wrap get-assets optimizations/all serve-live-assets)
;;(wrap-cljsbuild "/js/" cljsbuild)
wrap-content-type
;; wrap-reload
wrap-utf-8))
I'm loading my assets using Optimus
(defn get-assets []
(concat (assets/load-bundle "public" "styles.css" [#"css/.+\.css$"])
(assets/load-assets "public" [#"img/.*" "/questions.json"])
(assets/load-bundle "public" "main.js" [#"js/.+\.js"])
))
when I run lein with-profile dev pdf start-server, cljsbuild auto and bring up my website the js files and its dependants as compiled by the "dev" build takes FOREVER to complete loading. Why is the ring server so slow?
Should I be referencing the build files in this manner? should i bundle it into one file?
The profile used is for development purposes.
That is a pretty complex project.clj file if your just starting up and are new to clojure/clojurescript. It is possible that starting with just the bare lein figwheel template might be a good way to get a basic environment and then just add to it once you know you need additional bits. It could be that simply parsing your project file is slowing things down.
The basic figwheel template will set things up so that it all reloads when necessary - there really isn't much extra you need to worry about.

Compiling ClojureScript from cljc files with lein

Does cljc / lein / clojurescript work yet?
I was previously using cljx, and was able to compile the same project with the cljx plugin for lein firing off a cljsbuild task.
Now I'm switching to cljc, I want to compile my cljc files into both compiled Java and into javascript for use in the browser.
Here's my current project.clj file
(defproject com.mysite/myproj "0.3.2-SNAPSHOT"
:description ""
:url ""
:license {:name "Gnu Lesser Public License"
:url "https://www.gnu.org/licenses/lgpl.html"}
:dependencies [[org.clojure/clojure "1.7.0"]]
:plugins [[lein-cljsbuild "1.0.3"]
[lein-localrepo "0.4.0"] ]
:source-paths ["cljc" "src" ]
:cljsbuild {:builds [{
:source-paths ["cljc" ]
:compiler {
:output-to "browser-based/js/main.js"
:optimizations :whitespace
:pretty-print true }
} ]}
:hooks [leiningen.cljsbuild]
:aot [myproj.core]
:main myproj.core)
I don't remember exactly where I copied some of this from, but I assume that the leiningen.cljsbuild hook was what automatically fired off the cljs build process. However after removing the cljx plugin, and moving to cljc, this is successfully compiling the Java version of my program but doesn't seem to be producing any javascript.
Yes, it works.
Try with:
(defproject com.mysite/myproj "0.3.2-SNAPSHOT"
:description ""
:url ""
:license {:name "Gnu Lesser Public License"
:url "https://www.gnu.org/licenses/lgpl.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.28"]
:plugins [[lein-cljsbuild "1.0.6"]
[lein-localrepo "0.4.0"]]
:source-paths ["cljc" "src"]
:cljsbuild {:builds [{
:source-paths ["cljc" "src"]
:compiler {:output-to "browser-based/js/main.js"
:optimizations :whitespace
:pretty-print true}}]}
:hooks [leiningen.cljsbuild])
Then run: lein compile or lein cljsbuild once
Please note that I changed the :source-paths under :cljsbuild to include "src": :source-paths ["cljc" "src"]. Apart from that I added an explicit dependency on clojurescript and bumped cljsbuild version to 1.0.6
By the way, why do you have a separate cljc directory? You can have your cljc, clj & cljs files sharing the same directory structure.

Clojure: refresh running web app when html files change

I've set up my project with lein-ring to allow hot code reload. It does work when I change any .clj file while the app is running...
How can I make it the same for change in any html, css and js files. (located in resources/public...)
Here is my project.clj set-up:
(defproject ...
:plugins [[lein-cljsbuild "1.0.4"]
[lein-ring "0.9.2"]]
:ring {:handler votepourca.server/handler
:auto-reload? true
:auto-refresh? true}
:resource-paths ["resources" "markup"]
:source-paths ["src/clj"]
...)
EDIT:
I am using Enlive, and apparently, it needs an extra ring wrapper to allow static file reloading: [com.akolov.enlive-reload "0.1.0"]
So in my server.clj/core.clj/handler.clj, I now have this and it works perfectly!
(:require
[ring.middleware.reload :refer [wrap-reload]]
[com.akolov.enlive-reload :refer [wrap-enlive-reload]])
...
(defn app [routes]
(-> routes
(wrap-params)
(wrap-reload)
(wrap-enlive-reload))))
Thank you to "Kolov" the author of this lib https://github.com/kolov/enlive-reload
Add :reload-paths in addition to :auto-reload?/:auto-refresh?. https://github.com/weavejester/lein-ring/blob/master/src/leiningen/ring/server.clj#L25

Leiningen 2-steps build: how to combine lein-less and lein-asset-minifier

I'm making a Clojure/ClojureScript website that I deploy on Heroku. I'm using Leiningen for project management.
I want to write my stylesheets in LESS. I need the build process to compile the LESS files into CSS, then minify these CSS files; obviously, I do not want the generated CSS files to be under version control.
LESS files --lein-less--> CSS files --lein-asset-minifier--> minified CSS files
I have tried to implement this with the lein-less and lein-asset-minifier Leiningen plugins. My attempt consisted of declaring leiningen.less and minify-assets.plugin/hooks as hooks of the :uberjar task, in proper order (see code below). But running lein uberjar fails with the following error:
Uberjar aborting because jar failed: resources/public/css/site.css (No such file or directory)
So it appears the order of build steps is not enforced.
Is it possible to implement this multi-step build with these Leiningen plugins? If not, how are people doing it?
Code
Here is the relevant part of my project.clj :
(defproject sncf-cljs "0.1.0-SNAPSHOT"
;; ...
:min-lein-version "2.5.0"
:source-paths ["src/clj" "src/cljs"]
:dependencies [
;; ...
]
:plugins [
[lein-cljsbuild "1.0.4"]
[lein-environ "1.0.0"]
[lein-ring "0.9.1"]
[lein-asset-minifier "0.2.2"]
[lein-less "1.7.2"]]
:less {:source-paths ["src/less"]
:target-path "resources/public/css"}
:uberjar-name "sncf-cljs.jar"
:minify-assets {:assets
{"resources/public/css/site.min.css" "resources/public/css/site.css"}}
:cljsbuild {
;; ...
}
:profiles {
;; ...
:uberjar {:hooks [leiningen.less
leiningen.cljsbuild
minify-assets.plugin/hooks]
:env {:production true}
:aot :all
:omit-source true
:cljsbuild {:jar true
:builds {:app
{:source-paths ["env/prod/cljs"]
:compiler
{:optimizations :advanced
:pretty-print false}}}}}
:production {:ring {:open-browser? false
:stacktraces? false
:auto-reload? false}
:cljsbuild {:builds {:app {:compiler {:main "sncf-cljs.prod"}}}}
}})
I did some research because it is an interesting question. So I looked around, and could not find informations how to configure this. So I continued to search and I found a plugin for this task.
https://github.com/kumarshantanu/lein-cascade
The readme on the github page should be sufficient to solve this task.