ClojureScript cljsbuild doesn't load dependencies without optimisations - leiningen

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.

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 advanced compilation of pre and post conditions

I have the following piece of code in a ClojureScript project :
(ns project.lib
(:require [cljs.test :refer-macros [is]]))
(defn my-fn [p]
{:pre [(is (#{:allowed-key :another-allowed-key} p))]}
;;...
)
I would like to know if I can control the behaviour of the :pre and :post assertions, and generally what is the way to make sure that some code related to parameter checking is not included.
Note : I am aware of the :closure-define compiler option, but not sure how to apply it to this specific case.
You can set the compiler option :elide-asserts to true to eliminate all assertions, including :pre and :post assertions.
This flag is independent of :advanced and needs to be set even under that mode to eliminate the assertions from production code.
See https://github.com/clojure/clojurescript/wiki/Compiler-Options#elide-asserts
Also note that, generally, the cljs.test namespace would only be used in unit test namespaces, which would be placed in a separate directory (perhaps under "test" as opposed to to "src") and, if using lein, you would use :source-paths so as to not include the tests in your production builds.
Having said that, using :pre and :post is perfectly fine in production code—just use "regular" predicates instead of the cljs.test is macro. For your specific example, is could be eliminated as the precondition simply needs to evaluate to something truthy.

'figwheel' is not a task

I was happily using figwheel all day. I terminated the process by entering :cljs/quit.
When I try to restart figwheel lein figwheel, I'm greeted with this message from leiningen:
'figwheel' is not a task. See 'lein help'
Running lein help lists many tasks I can perform, but figwheel is not among them.
Here's what my project.clj looks like (extra stuff elided):
(defproject myproject
...
:dependencies [...]
:plugins [[lein-environ "1.0.2"]
[lein-cljsbuild "1.1.1"]
[lein-asset-minifier "0.2.4"]]
...
:profiles {:dev {:dependencies [...
[lein-figwheel "0.5.0-6"]
...]
:plugins [[lein-figwheel "0.5.0-6"]
...]
:figwheel {...}}}
...)
Here's what I've tried so far:
Verified I was in the correct directory
Checked out all code changes made since the last successful figwheel start
Added [lein-figwheel "0.5.0-6"] to the base :plugins vector (this sort of worked, but didn't recognize any of my profile-specific settings)
Restarted my computer
You can type lein help profiles to read all about profiles. The problem in this case is caused by:
Remember that if a profile with the same name is specified in multiple
locations, only the profile with the highest "priority" is picked – no
merging is done. The "priority" is – from highest to lowest –
profiles.clj, project.clj, user-wide profiles, and finally system-wide
profiles.
It's using the :dev in profiles.clj which doesn't have figwheel. This is also why adding lein-figwheel to the base :plugins sort of helped, but doesn't use all your settings.
There's a straightforward solution suggested by the docs:
If you need to enable personal overrides of parts of a profile, you can use a composite profile with common and personal parts - something like :dev [:dev-common :dev-overrides]; you would then have just :dev-overrides {} in project.clj and override it in profiles.clj.

Multiple ClojureScript files on same page

I have a project that is using Jasmine to test the JavaScript. I am trying to switch to using ClojureScript for the front end. My project.clj is like
(defproject myproject "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript"0.0-1889"]
[org.clojure/google-closure-library-third-party "0.0-2029"]
[domina "1.0.0"]
[hiccups "0.2.0"]]
:plugins [[lein-cljsbuild "0.3.3"]]
:cljsbuild {
:builds [{
:source-paths ["src/clojurescript"]
:compiler {
:output-to "public/javascripts/main.js"
:optimizations :whitespace
:pretty-print true}}
{
:source-paths ["spec/clojurescript"]
:compiler {
:output-to "spec/javascripts/mainSpec.js"
:optimizations :whitespace
:pretty-print true}}]})
So all the .cljs files in src/clojurescript get compiled to main.js and all the .cljs in spec/clojurescript get compiled to mainSpec.js.
When I load the Jasmine page, both the .js files are loaded but the tests aren't run.
In the console I get an Error: Namespace "goog.debug.Error" already declared.
Both the .js files have the same ~30k lines of google closure code at the top which is causing the error. If I delete this code from mainSpec.js it runs fine.
Is there any way to tell cljsbuild to leave this code off the spec file?
As Jared314 and Zubair pointed out, the problem you're encountering is caused by trying to include two clojurescript compilation outputs in the same page. Clojurescript/Google Closure expect to do a 'whole-world' compile, that is, the compiler expects that all of the code for the entire page is passed to the compiler so that it can optimise it, rename functions, and ultimately spit out a single javascript file. It's not designed to produce multiple output files that work together.
The 'correct' way to solve your problem is to produce two outputs that are used in isolation: a main.js file for running your application, and a spec.js file that include all the code in main plus the code in spec for testing. You can do this by setting up your project something like this:
:cljsbuild {
:builds [{
:source-paths ["src/clojurescript"]
:compiler {:output-to "public/javascripts/main.js"}}
{
:source-paths ["src/clojurescript" "spec/clojurescript"]
:compiler {:output-to "spec/javascripts/spec.js"}}]})
Your jasmine page should refer to spec.js but not main.js - referring to both is the cause of your error.
The issue is both builds are compiled with the Google Closure library included, hence the "already declared" error. You can try using :optimizations :advanced, in the :compiler options, to reduce, or eliminate, the duplicate code.
But, if you still run into the same issue, you might want to compile the src and spec together for the mainSpec.js build.