What should go in my project.clj to run Om with Clojurescript? - clojurescript

I looked at the Github Om page but it is not clear which version I should be using?

see https://github.com/swannodette/om#using-it
Your project.clj should include something like the following:
(defproject foo "0.1.0"
...
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2173"]
[om "0.5.3"]]
...)

Related

Evaluate expression and display results in spacemacs

Recently started playing with Clojurescript in Spacemacs(emacs 26.1). I am using figwheel, I usually make a change in the *.cljs file and then test the results in the function in the REPL. I recently watched a video where someone evaluated the function in the file without having to go to the REPL.
I tried to do the same using cider in spacemacs, The problem is it evaluates but does not display the results.
Below snippet is from config in my project.clj
:profiles {:dev {:source-paths ["src" "env/dev/clj"]
:dependencies [[binaryage/devtools "0.9.10"]
[figwheel-sidecar "0.5.16"]
[nrepl "0.4.4"]
[cider/piggieback "0.3.9"]]}})
Snippet from cljs file.
(defn tes []
(inc 1234))
(prn (tes))
(tes)
I tried evaluating (tes) and (prn (tes)), it evaluates but does not print anything in the echo area.
I have cider setup in spacemacs and cider REPL running during the execution. Executing the function in cider REPL by navigating to the namespace works.
Is there anything I am missing here in order to get it working in terms of setup.
You probaly need cider-nrepl.Put the following in your ~/.lein/profiles.clj file.
{:repl {:plugins [[cider/cider-nrepl "0.18.0"]]}}

How can I make figwheel start with a custom initial namespace?

The project.clj of my clojurescript code specifies :repl-options {:init-ns my-project.core} and I start figwheel via start-figwheel!. In the figwheel documentation it says that
;; you can also just call (ra/start-figwheel!)
;; and figwheel will do its best to get your config from the
;; project.clj or a figwheel.edn file`
But when figwheel starts, it puts me into the cljs.user namespace. How can I make figwheel pick up this option?
My figwheel.clj looks as follows:
(require '[figwheel-sidecar.repl :as r]
'[figwheel-sidecar.repl-api :as ra])
(ra/start-figwheel!
{:figwheel-options {}
:build-ids ["dev"]
:all-builds
[{:id "dev"
:figwheel {:devcards true}
:source-paths ["src"]
:compiler {:main 'my-project.core
:asset-path "js"
:output-to "resources/public/js/main.js"
:output-dir "resources/public/js"
:verbose true}}]})
(ra/cljs-repl)
I am basically asking this question from Google groups.
start-figwheel! only starts figwheel logic. Regarding your finding that:
;; you can also just call (ra/start-figwheel!)
;; and figwheel will do its best to get your config from the
;; project.clj or a figwheel.edn file`
It indeed finds its config but it's only :figwheel submap of project.clj.
:repl-options are used by REPL when it starts. It seems that figwheel-sidecar.repl-api/cljs-repl doesn't allow specifying REPL options and it doesn't read them from project.clj.
You might try to play with starting lein repl where project.clj's :repl-options use :init option to provide the code you want to execute instead of a standalone script.

ClojureScript cljsbuild doesn't load dependencies without optimisations

I am trying to use figwheel in my ClojureScript build.
It works with lein cljsbuild auto already, but I have to put :optimisations :whitespace.
Otherwise I get a message in the browser :
Uncaught ReferenceError: goog is not defined
However figwheel require :optimisations :none to run. Here is the part of my leiningen file :
:cljsbuild {
:builds
[{:id "dev"
:source-paths ["src/cljs"]
:figwheel { :websocket-host "localhost"
;;:on-jsload "example.core/fig-reload"
:autoload true
:heads-up-display true
:load-warninged-code true
;;:url-rewriter "example.core/fig-url-rewrite"
}
:compiler {;; :main
:output-to "resources/public/js/gdb/gdb.js"
:output-dir "resources/public/js/gdb/cljsbuild-dev"
;;:asset-path "js/out"
:optimizations :none
:source-map "resources/public/js/gdb/gdb.js.map"
:pretty-print true}}]}
What is missing for me to get the missing dependencies ?
It turns out this is a classic case of RTFM.
The answer was in the ClojureScript quickstart guide.
Specifically, I had to add a :main field, as specified in the Less Boilerplate section :
:main "example.core"
Nothing jumps out as being obviously wrong or missing. However, lein is pretty powerful in the degree it lets you set things to fit your personal taste/workflow, so it is hard to spot things if the approach is signficantly different.
When I run into these types of problems, I find using the standard templates provided by many libraries or projects really useful. My recommendation would be to run
lein new figwheel ft -- --reagent
This will setup a basic project called ft (in this case also with reagent - there is another option for om or you could leave all of this out for a bare bones default. See the figwheel repo on github for more details. This will provide a good working lein figwheel setup which hyou can use as a guide.

Can I use arbitrary node modules from clojurescript?

Is it possible to use arbitrary node.js modules in a clojurescript project? If yes, how do I go about including them? If not, why not?
Yes, you can, there is nothing special about it:
(def fs (js/require "fs"))
(println (.readdirSync fs js/__dirname))
Be careful with the externs if you don't use optimizations none.
Edit: Does leiningen play with the various js package managers?:
Nope. Since the language does not have packages, it cannot know. You have to do js dependency management and lein deps too. There is a lein-npm and a lein-bower to help with integrating these two package managers.
Yes, since late 2017. With shadow-cljs or Lumo now it's not problem to import npm modules in ClojureScript code anymore.
(ns app.main
(:require ["dayjs" :as dayjs]
["shortid" :as shortid]
["lodash" :as lodash]
["lodash" :refer [isString]]))
Read this topic for details: Guide on how to use/import npm modules/packages in ClojureScript?
Since ClojureScript 1.9.854, there's better support to declare npm modules as dependencies and to require them from your namespaces.
In order to declare it as a dependency, you need to use the :npm-deps compiler option (together with the :install-deps one, if you want lein/bootto automatically install it).
:npm-deps is a map from keyword to string, where the keyword is the name of the dependency you would use to install it using npm and the string is the version of the dependency.
An example of what you could add to your project.clj (if you use lein-cljsbuild), in order to use left-pad:
:cljsbuild {:builds [{:id "prod"
:source-paths ["src"]
:compiler {:main left-pad-demo.core
:output-to "package/index.js"
:target :nodejs
:output-dir "target"
:optimizations :simple
:install-deps true
:npm-deps {:left-pad "1.2.0"}
:pretty-print true}}]})
And then, from your namespace, you can require it like so:
(ns left-pad-demo.core
(:require left-pad))
Or so:
(ns left-pad-demo.core
(:require ["left-pad" :as lp]))
A full working namespace could look like:
(ns left-pad-demo.core
(:require left-pad))
(defn -main [s length]
(console.log (left-pad s length)))
(set! *main-cli-fn* -main)
References:
Requiring Node.js modules from ClojureScript namespaces
ClojureScript is not an Island: Integrating Node Modules

Serving data with Ring and Compojure

I am configuring and setting up a web application to serve the JSON data http://www.ericrochester.com/clj-data-analysis/data/census-race.json file statically.
My dependencies:
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2197"]
[ring/ring-core "1.1.7"]
[ring/ring-jetty-adapter "1.1.7"]
[compojure "1.1.3"]
[hiccup "1.0.2"]
[lein-cljsbuild "0.2.10"]]
As the title says I'm using Ring as a development plugin, i.e.
:plugins [[lein-ring "0.8.3"]]
The Leiningen project is
(ns test-app.core
(:require [compojure.route :as route]
[compojure.handler :as handler]
[clojure.string :as str])
(:use compojure.core
ring.adapter.jetty
[ring.middleware.content-type :only
(wrap-content-type)]
[ring.middleware.file :only (wrap-file)]
[ring.middleware.file-info :only
(wrap-file-info)]
[ring.middleware.stacktrace :only
(wrap-stacktrace)]
[ring.util.response :only (redirect)]))
and in the project.clj
:ring {:handler test-app.core/app}
which I am not sure if this will tell Ring where the web application
is.
Moreover, I am not sure how to serve the JSON data file statically. I have read that "Ring serves static files out of the /resources directory of your project. In this case, create the directory /resources/data and put the data file that you downloaded from http://www.ericrochester.com/clj-data-analysis/data/census-race.json into it."
It is mostly this last part about creating the /resources/data directory where I am lost in the implementation. Could someone show how this part is done?
If I can learn to get past this I am looking to build routes and handlers, i.e.
(defroutes site-routes
(GET "/" [] (redirect "/data/census-race.json"))
(route/resources "/")
(route/not-found "Page not found"))
and
(def app
(-> (handler/site site-routes)
(wrap-file "resources")
(wrap-file-info)
(wrap-content-type)))
and in the project.clj
:ring {:handler test-app.core/app}
which I am not sure if this will tell Ring where the web application
is.
When you run $ lein ring server-headless it will look for app in the test-app.core namespace. You should have something like the following in your core.clj file:
(def app
(handler/site app-routes))
It is mostly this last part about creating the /resources/data
directory where I am lost in the implementation. Could someone show
how this part is done?
In the root of your project directory you should have a resources folder. Create a data folder inside the resources folder.
I'm not sure what problem you're having?
If your project looks like this:
project.clj
src/test_app/core.clj
resources/public/data/census-race.json
Then the your site-routes handler will serve up that JSON file when you request the path /data/census-race.json.
You don't need any of the extra middleware like wrap-file, wrap-file-info, or wrap-content-type, since compojure.route/resources already does everything you need.