Clojure Ring: How to determine if development server is running? - clojure

I have a project containing both Clojure & ClojureScript code. I would like to include unoptimized ClojureScript when I run my server via lein ring server and optimized ClojureScript otherwise. What is the idiomatic way to do this?
I am using:
[[bidi "1.19.0"]
[hiccup "1.0.5"]
[org.clojure/clojure "1.7.0-beta3"]
[org.clojure/clojurescript "0.0-3269"]]
[[lein-cljsbuild "1.0.4"]
[lein-ring "0.9.4"]]
My handler is just a simple one:
(def app (-> ["/" {:get {"" index-view}}]
(compile-route)
(make-handler)))
and this is my server directive:
:ring {:handler webapp.core/app}
I am looking for a way to be able to do this in my views:
(dev-server? request) ;; => true if it's a development server, otherwise false.

The idiomatic way to do this is to use leiningen profiles, using the :dev profile. You can then ensure inside the dev profile that your ClojureScript build is happening without optimization, cf. the leiningen cljsbuild compilation profiles.
If you want to be able to identify the devserver running, you can use environ -- include :env {:dev true} in your :dev profile and then in your code you can just call (env :dev). You might want to take a look at the reagent-template for inspiration.

Related

How to handle the new HTTP configuration for shadow-cljs?

I have been using Clojure, ClojureScript, lein, shadow-cljs, Emacs,
and CIDER to work on a Clojure/ClojureScript dynamic web app project.
Usually, I build the project by executing the command
cider-jack-in-cljs in Emacs, choosing shadow-cljs, then shadow
for REPL type, and, finally, app for the building option.
Things were working fine. I was used to watching changes on the UI on
localhost:3005.
But, an answer from a previous question indicated that the
project was using an old (and deprecated) HTTP configuration for
shadow-cljs.
On shadow-cljs.edn we had:
{:source-paths ["src" "dev"]
:dependencies ...omitted..
:nrepl {:port 8230
:nrepl-middleware [dirac.nrepl/middleware]}
:builds {:app {
:devtools {:after-load app.core/main
:http-root "public"
:http-port 3005
:preloads [shadow.cljs.devtools.client.hud
day8.re-frame-10x.preload
dirac.runtime.preload
devtools.preload]}
}}}}}
After the build was complete, I would see the live application on
localhost:3005. The mini-buffer would direct me to see the
rendered page on the browser.
On shadow-cljs.edn, now, we have:
{:source-paths ["src" "dev"]
:dependencies ...omitted..
:nrepl {:port 8230
:nrepl-middleware [dirac.nrepl/middleware]}
:builds {:app {
:devtools {:after-load app.core/main
:preloads [shadow.cljs.devtools.client.hud
day8.re-frame-10x.preload
dirac.runtime.preload
devtools.preload]}
:dev-http {3005 "public"}
}}}}}
However, the workflow for development is different.
Emacs mini-buffer redirects me on the browser to a different address:
http://localhost:9630/dashboard
Also, old localhost:3005 does not work, even though it is mentioned
on :dev-http {3005 "public"}.
1 - What is the new workflow to change the code and see the changes?
2 - Why is port localhost:3005 not working anymore even though it is mentioned in the source code?
3 - What is the purpose of the dashboard?
:dev-http is a top-level config. It is not part of a build config. It needs to sit at the same level as :nrepl and :builds.
{:source-paths ["src" "dev"]
:dependencies ...omitted..
:nrepl {:port 8230
:nrepl-middleware [dirac.nrepl/middleware]}
:dev-http {3005 "public"}
:builds
{:app
{...
:devtools
{:after-load app.core/main
:preloads
[day8.re-frame-10x.preload
dirac.runtime.preload
devtools.preload]}}}}}}

How to create a multi-page application with Figwheel and Leiningen?

I have a simple Figwheel application which is built with Leiningen.
I want to have multiple pages in it:
index.html should use the code from hello-figwheel.core.
page2.html should use the code from hello-figwheel.page2
I assume I have to somehow modify the project.clj file:
:compiler {:main hello-figwheel.core
:asset-path "js/compiled/out"
:output-to "resources/public/js/compiled/hello_figwheel.js"
:output-dir "resources/public/js/compiled/out"
:source-map-timestamp true
;; To console.log CLJS data-structures make sure you enable devtools in Chrome
;; https://github.com/binaryage/cljs-devtools
:preloads [devtools.preload]}}
How can I tell Leiningen to compile
hello-figwheel.core to resources/public/js/compiled/hello_figwheel.js and
hello-figwheel.page2 to resources/public/js/compiled/page2.js?
There is a similar question. The difference to this one is that Leiningen is used to run Figwheel.
Update 1: I added the following to the project.clj file:
{
:id "page2"
:source-paths ["src"]
:compiler {
:output-dir "resources/public/js/compiled/page2"
:output-to "resources/public/js/compiled/page2/main.js"
:main hello-figwheel.page2
:asset-path "js/compiled/out"
:source-map-timestamp true
;; To console.log CLJS data-structures make sure you enable devtools in Chrome
;; https://github.com/binaryage/cljs-devtools
:preloads [devtools.preload]}
:figwheel {:on-jsload "hello-figwheel.page2/on-js-reload"
;; :open-urls will pop open your application
;; in the default browser once Figwheel has
;; started and compiled your application.
;; Comment this out once it no longer serves you.
:open-urls ["http://localhost:3449/page2.html"]}
}
When I run lein figwheel, the REPL is unable to connect to my web application:
It says Prompt will show when Figwheel connects to your application, but it never happens.
Also, if I open http://localhost:3449/page2.html in the browser, update page2.cljs, and refresh the page in the browser, the changes are not visible there.

Clojure: Cannot launch cider repl with boot

I have the following build.boot file,
(set-env!
:resource-paths #{"src"}
:dependencies '[[me.raynes/conch "0.8.0"]
[boot.core :as boot]])
(task-options!
pom {:project 'myapp
:version "0.1.0"}
jar {:manifest {"Foo" "bar"}})
(boot/deftask cider "CIDER profile"
[]
(require 'boot.repl)
(swap! #(resolve 'boot.repl/default-dependencies)
concat '[[org.clojure/tools.nrepl "0.2.12"]
[cider/cider-nrepl "0.15.0"]
[refactor-nrepl "2.3.1"]])
(swap! #(resolve 'boot.repl/default-middleware)
concat '[cider.nrepl/cider-middleware
refactor-nrepl.middleware/wrap-refactor])
identity)
following this documentation: https://github.com/boot-clj/boot/wiki/Cider-REPL
However, upon doing cider-jack-in I get the error "refusing to run as root. set BOOT_AS_ROOT=yes to force.", and yet after doing export BOOT_AS_ROOT=yes, I get the same error. What's wrong?
This wiki page is super outdated, so I don't recommend following it. I'd be best to read CIDER's documentation instead.
Just make sure you're using Boot 2.8.3. You don't really need any special CIDER profile. Just create a Boot project, open a file from it in CIDER and do M-x cider-jack-in-clj.

How to change Lein's Clojure default version outside of a project directory?

This is asking for help regarding the same question as How to change Clojure or Lein's Clojure default version?
but is not an answer to that question. Should I have nevertheless have written it as an answer under that thread?
Specifying a Clojure version to be used when the "(lein repl)" command is issued outside of a project directory seems to be a natural thing to want. Of course there may be good design reasons for not allowing it, but do you think an error message like the following,
to be displayed when Leiningen detects that the ~/.lein/profiles.clj (or other relevant profile files) specify a different Clojure version from the one hard coded into Leiningen,
would be a good idea?
"specifying the Clojure version to be used with certain software, such as tools.nrepl and clojure-complete, is only allowed when this command is issued within a project directory"
A lot of people apparently have spent a lot of time on Stack Overflow trying to find out how to do this.
References:
"Updating ~/.lein/profiles.clj to {:repl {:dependencies [^:displace [org.clojure/clojure "1.9.0"]]}} does not seem to work. – Petrus Theron Jan 10 2018 at 9:05" How do you change Clojure version in Leiningen and LightTable?
"I asked technomancy on IRC just now. He said: "REPL's outside projects are hard coded to lein's version of clojure". – David J. Feb 24 '14 at 19:52" How to change Clojure or Lein's Clojure default version?
"this ^:displace trick will not work with tools.nrepl or clojure-complete." https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md
How to upgrade nrepl version of leiningen?
I think you may try to declare different profiles in your project.clj where each of them has its own Clojure version. For example:
:profiles
{;; :default [:base :system :user :provided :dev]
:server-jvm {:jvm-opts ^:replace ["-server"]}
:1.5 {:dependencies [[org.clojure/clojure "1.5.1"]]}
:1.6 {:dependencies [[org.clojure/clojure "1.6.0"]]}
:1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
:1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}
:1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}}
Now that, when running any Lein command, specify a profile as follows:
lein with-profile 1.7 repl
The REPL session of Clojure 1.7 should start.
I grabbed that fragment from carmine sources. The official Lein profiles manual also has the same example.

What Is The Reason For The Lein Cyclic Dependency Error When I build uberwar?

Building ring server-headless works -- lein ring server-headless -- but when I try to build the war or uberwar I get the following error, and cannot figure out why this is happening.
No namespaces to :aot compile listed in project.clj.
Exception in thread "main" java.lang.ExceptionInInitializerError, compiling:(ring/util/servlet.clj:62)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6416)
at clojure.lang.Compiler.analyze(Compiler.java:6216)
...
Caused by: java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at clojure.lang.RT.classForName(RT.java:2013)
at clojure.lang.Compiler$HostExpr.maybeClass(Compiler.java:938)
at clojure.lang.Compiler$HostExpr.access$400(Compiler.java:710)
at clojure.lang.Compiler.macroexpand1(Compiler.java:6342)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6395)
... 69 more
Caused by: java.lang.Exception: Cyclic load dependency: [ /servlet ]->/ring/util/servlet->[ /servlet ]
at clojure.core$check_cyclic_dependency.invoke(core.clj:5288)
at clojure.core$load.doInvoke(core.clj:5383)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:401)
at servlet.<clinit>(Unknown Source)
... 76 more
My project.clj file is:
(defproject myproj "0.1"
:description "the sample"
:dependencies [
[org.clojure/clojure "1.3.0"]
[compojure "1.0.4"]
[hiccup "1.0.0"]
[clj-json "0.5.0"]
[ring/ring "1.1.0"]
[clj-http "0.1.1"]
]
:plugins [
[lein-ring "0.7.0"]
]
:ring {:handler routes/start})
If I remove the :ring {:handler routes/start} then I get a NPE somewhere else.
I don't know if I'm missing something in my project.clj, or if the particular version of lein is broken for this use case. Can someone clarify this for me?
I had the same issue, in my case the solution was as simple as doing a
lein clean
before the
lein ring uberwar
I think actual issue is that at some point, my handler was pointing to an incorrect/inexistent handler and that left a servlet.clj in the target/classes directory. Doing a clean will remove this file.
I solved the issue, which was a bit of a mistake on my part. Posting the answer here in case anyone makes the same mistake.
I had something like the following in src/routes.clj:
(defroutes main-routes
(GET "/some/path" [& params] (some-code params))
(route/resources "/")
(route/not-found "not found"))
(def start (run-jetty (handler/site main-routes) {:port 8080}))
This is all standard code to setup routes and provide a hook to start the jetty webapp from the command line via lein ring server-headless. Except that I declared start as a global instead of a function. That means when I run lein ring server-headless things still work, but when I run lein ring uberwar I end up with a weird configuration--a full jetty server will try to start up with it's servlet, AND uberwar has generated a servlet and is trying to package it into a jar.
When I was comparing my code against the compojure examples I kept missing this difference I guess because def and defn optically look so similar. But anyway I just made this change to get it working:
(defn start [] (run-jetty (handler/site main-routes) {:port 8080}))
The error says it all, the :aot param is missing from the project config. Check out this link for using :aot.