Clojurescript libraries - goog.require could not find - leiningen

New to clojurescript, and working through the "Modern CLJS" tutorial here.
It instructs to pull in domina by adding it to the project.clj:
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.5"]
[domina "1.0.0"]]
And then use it in your script by referencing it in the ns form
(ns cljstut.login
(:use [domina :only [by-id value]]))
However, when I actually run this in a browser, I see the following in the console log.
goog.require could not find: domina
Seems like I'm missing some declaration somewhere? But as a newb, this whole build process is rather opaque. Any troubleshooting tips are greatly appreciated.

Dependencies in your project.clj file and your namespace declarations look fine.
If you are building your clojurescript code using lein cljsbuild auto, you will need to restart that process. I believe it should automatically pull in new dependencies after a restart.
If that doesn't work, or you aren't using lein cljsbuild auto, try running the lein deps command inside your project's folder manually - it will fetch all missing dependencies from remote repositories.

Also, make sure you have saved your project.clj file and try running lein clean and lein cljsbuild clean.

I'm in the process of updating modern-cljs to the latest versions of the used libs and lein plugins. At the moment I updated the series up to the 7th tutorial of the series. You should now be safe by updating to domina 1.0.2-SNAPSHOT into project.cljs :dependencies and to lein-cljsbuild 0.3.0 into project.cljs :plugins.
Mimmo

Just want to add that a typo in the namespace would trigger the same error message:
goog.require could not find: domina
Example (note the missing "j" in modern-cljs):
(ns modern-cls.login
(:use [domina :only [by-id value]]))
I was using a different project name thus a different namespace just to be brave.
It bit me in the ass when I copy-pasted from the guide and the error had me puzzled for a while :)

I ran into this same issue while working through the "Modern CLJS" tutorial. My problem was inadvertently adding the "domina" dependency to the :plugins section of project.clj rather than the :dependencies section.

I got past this error message by putting lines in the right order in the index.html file.
Correct order:
<script src="js/expanding_gases.js" type="text/javascript"></script>
<script type="text/javascript">goog.require("expanding_gases.flow_gases");</script>
Incorrect order:
<script type="text/javascript">goog.require("expanding_gases.flow_gases");</script>
<script src="js/expanding_gases.js" type="text/javascript"></script>
By the way a good read for understanding 'goog' messages is here:
https://github.com/clojure/clojurescript/wiki/Quick-Start

Related

How to add shadow cljs watcher on js directory in a re-frame app?

I have created a basic re-frame app using the template lein new re-frame my-proj. This particular project is interfacing with a framework (ecsy) that requires some ES6 modules and ES6 classes e.g code that is generated by the user, not simply called from cljs. Since Clojurescript does not currently generate ES6 code, I have created some wrapper ES6 modules in my project from which I plan to call into cljs code.
After much futzing, I have discovered that it's not necessary to turn these js wrapper modules into full-blown npm modules under 'node_modules', but rather I can simply put them in a sub-directory of my project e.g resources/libs and then add this directory to :js-options in shadow-cljs.edn:
{:lein true
:nrepl {:port 8777}
:builds {:app {:target :browser
:output-dir "resources/public/js/compiled"
:asset-path "/js/compiled"
:modules {:app {:init-fn re-pure-ecs-simple.core/init
:preloads [devtools.preload]}}
:devtools {:http-root "resources/public"
:http-port 8280}
;;add this
:js-options {:js-package-dirs ["node_modules" "resources/libs"]}}}}
So everything works fine now, but the only problem is if I edit any of the js files in 'resources/public' the lein.bat dev compiler doesn't detect the changes. I can go in and make a mock change to a '.cljs' file, which does cause the compiler to re-compile, but it still doesn't pick up on the changes made to the '.js' file (or '.mjs' file). I have to kill, via ctrl-c, the compiler and re-start it to get the change propagated. Unfortunately, this takes about 15 seconds to compile since it's a full compile.
I tried adding 'resources/libs' to my 'project.clj':
:source-paths ["src/clj" "src/cljs" "resources/libs"]
to no avail.
I also tried deleting the compiled js files from <my_proj-dir>/resources/public/js/compiled/cljs-runtime:
rm 'module$node_modules$systems.js' 'module$node_modules$systems.js.map'
In this case, the compiler does re-generate the files (upon doing a mock .cljs change), but it still uses the prior version e.g. it must be using a cached version.
Is there a way I can add a watcher to this js directory so I can do incremental builds? There's obviously a watcher on the 'src/cljs' directory already. I have consulted the shadow-cljs user gd. but honestly, it's a little overwhelming.
You can follow the directions for requiring local .js in the User's Guide.
Basically you put the .js files into the same folder as your .cljs file and then just require it via (:require ["./foo.js" :as foo]). No additional config required.

Using the Boot-clj REPL to load Clojurescript functions in a Castra/Hoplon project

I am having quiet a bit of trouble with the boot-clj nREPL. I connect using cider-jack-in in EMACS and then at the top it displays the correct port and on the bottom it shows 'boot.user=>' but I am having trouble loading cljs functions from the '../rpc.cljs' page. In short I don't have any idea how to navigate to that place. I tired using '(load "...")' but I can't even figure out the current working directory. I couldn't find a tutorial on using the Boot REPL anywhere. I have tried it from the command line with 'boot repl' then loading with '(def p (future (boot (dev))))' but still am completely lost.
So in short, could someone help point me in the right direction? I am looking for how to change the current directory, finding the current working directory, and loading functions from a .cljs file.
:::EDIT:::
I found the boot-cljs-repl and tried to hook that up. In a Hoplon/Castra template it is already included in the 'build.boot' file but, after following the directions on their GitHub it still doesn't work. To connect it to the project add the below in the 'build.boot' file, the second part is for the Boot Task 'Dev'
(require
'[adzerk.boot-cljs-repl :refer [cljs-repl cljs-repl-env start-repl]]"
...
...
(reload)
(cljs-repl-env)
(cljs)))
...
And then, you should be able to use cider-jack-in to load the CLJS repl with the commands '(def r (future (boot (dev))))' followed by (start-repl) but whenever I run that I have an error. I have tried cider-jack-in-clojurescript and the one before but it seems to have an error connecting to the CLJS repl.
boot.user> << started Weasel server on ws://127.0.0.1:38456 >>
<< waiting for client to connect ...
java.lang.NullPointerException
at clojure.java.io$make_parents.invokeStatic(io.clj:443)
at clojure.java.io$make_parents.doInvoke(io.clj:438)
I will keep trying different approaches but so far seem stuck.
:::EDIT:::
I figured out the problem some more, if you use '(cljs-repl)' instead of '(cljs-repl-env)' than you can connect with 'cider-connect' after you start 'boot dev' in bash, and then you type '(start-repl)' into the cider repl and it starts a CLJS repl. The problem I am now having is if I try and use the REPL like a Clojure REPL it doesn't quite work. If you press C-c C-c cider just says, if in a .cljs file, that it needs a Clojurescript REPL even though it is.
Cheers,

atom packages, clojurescript, google closure and dependency management

I'm writing some atom (the editor) package with ClojureScript. And i faced dependency load issue.
When compiled ClojureScript produces file like this (main.js):
goog.addDependency("base.js", ['goog'], []);
goog.addDependency("../cljs/core.js", ['cljs.core'], ...)
goog.addDependency("../clojure/browser/event.js", ...)
Obviously, ClojureScript heavily depends on Google Closure dependency management.
But, to be able to use Google Closure i need to include goog/base.js file.
The only way that i found is to add to goog/base.js:
module.exports = goog
and add to main.js:
require('./goog/base.js')
This is very bad approach, because these files are generated - so they can be overridden.
Also, release compilation will not include these lines.
The question is how can i use both these dependency systems?
Or is it possible to use ClojureScript w/o Google Closure?
Please advice, thanks!
If you set your ClojureScript :optimizations to something other than :none (e.g., :whitespace) then the resulting .js file will include the Google Closure code inlined and you won't have to reference it separately.
(Note that this means you might not be able to use a main function in your ClojureScript code, but you can just put a call to your main function somewhere at the toplevel.)

ClojureScript compiler can't find namespace/file in same directory

lein cljsbuild is having trouble finding a namespace/file that's defined right alongside another namespace/file unless I make sure they're compiled in a certain order.
My directory layout looks like this:
project/
project.clj
src/
cljs/
contempo/
common/
defs.cljs
view/
core.cljs
navigation.cljs
navigation.cljs has some stuff to build Om components for navigating around the page, and core.cljs is the main entry point for this particular page. navigation.cljs starts with:
(ns contempo.view.navigation (:require ...))
core.cljs starts with:
(ns contempo.view.core (:require [contempo.view.navigation :as navigation]))
When I run lein cljsbuild, I get:
solace:Groov jfischer$ lein cljsbuild auto
Compiling ClojureScript.
Compiling "war/view/js/app.js" from ["src/cljs/contempo/common" "src/cljs/contempo/view"]...
Compiling "war/view/js/app.js" failed.
clojure.lang.ExceptionInfo: failed compiling file:src/cljs/contempo/view/core.cljs
... snipped stacktrace ...
Caused by: clojure.lang.ExceptionInfo: No such namespace: contempo.view.navigation at line 1 src/cljs/contempo/view/core.cljs
I can get it to work by removing all references to contempo.view.navigation from core.cljs, running lein cljsbuild auto and letting the compile finish, then putting them back and saving (so cljsbuild picks up the changes), but that's silly and shouldn't be necessary.
My project.clj looks like:
(defproject contempo "0.0.0-SNAPSHOT"
:description "Experimenting with ClojureScript and Om"
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2740"]
[org.clojure/core.async "0.1.346.0-17112a-alpha"]
[org.omcljs/om "0.8.7"]]
:plugins [[lein-cljsbuild "1.0.4"]]
:clean-targets ^{:protect false} ["war/view/js/app.js"
"war/view/js/out"]
:cljsbuild {:builds [{:id "view-dev"
:source-paths ["src/cljs/contempo/common"
"src/cljs/contempo/view"]
:compiler {:output-to "war/view/js/app.js"
:output-dir "war/view/js/out"
:optimizations :none
:cache-analysis true
:source-map true}}]})
Is there anything obvious I'm doing wrong? This looks pretty similar to every ClojureScript project I've looked at.
Update: Tiny skeleton project that shows the error is up here: namespace-error-demo.zip
The issue ended up being: I wasn't obeying the rules for how namespaces are resolved.
With source paths of src/cljs/contempo/common and src/cljs/contempo/view, if I required the contempo.view.whatever namespace, the compiler would look for it at src/cljs/contempo/common/contempo/view/whatever.cljs and src/cljs/contempo/view/contempo/view/whatever.cljs.
I had to use src/cljs as the source directory. What I wanted to pull off (leaving out code for a given page that didn't need it) was kind of silly (since it'd be pulling in all of ClojureScript anyway) and is now properly addressed thanks to proper Google Closure Module support in ClojureScript.
I was having this same problem all of today. In my case, the root cause was having .cljs files with "-" in the name. I only discovered this was the problem after switching to 0.0-3030, which provides better error messages for the strict file path to namespace conventions that more recent versions of the cljs compiler have.
You might want to try changing :source-paths to ["src/cljs"]

Compiling external JS files with Cljsbuild in ClojureScript

I'm trying to compile some JS libraries that we have with lein-cljsbuild to integrate them in our ClojureScript code base. First I added some goog.provide in top of each file, and the files are hierarchically organised in a directory tree according to their namespace (like in Java). That is namespace a.b.c is in src-js/libs/a/b/c.js
I have put the JS files in the root directory of the projects in src-js/libs, and I have the following :compiler options for lein-cljsbuild:
{:id "prod",
:source-paths ["src-cljs" "src-js"]
:compiler
{:pretty-print false,
:libs ["libs/"]
:output-to "resources/public/js/compiled-app.js",
:optimizations :simple}}
None of the JS files get compiled into the compiled-app file. What's wrong?
I also tried to put them in resources/closure-js/libs without success.
I'm using lein-cljsbuild 0.3.0.
First, unlike what is suggested in some texts, you do not need to include your private closure library locations in any classpath configuration statement in your project.clj. So unless the "src/js" directory included in your "source-paths:" statement is for some other purpose, you can remove it.
Second, the only thing to add to your project.clj, for the sake of bringing in your private closure code, is the "libs:" reference you have made; BUT unlike what you have entered, that reference must be to a specific *.js file (or files) and not merely a directory. So if the library you want to used is in a file named test.js and that resides in the /src/js directory, your libs: entry would be: "src/js/test.js". See the cljs-build release notes if you want to use that plugin's default :libs directory option.
Third, (and it looks like you know this already, but this is what tripped me up) if you are using a browser-backed REPL (repl-listen option of cljsbuild), you still will not be able to load/reference/use your private library assets from that REPL until you include a :require statement somewhere in the source for your compiled-app.js (e.g. "(ns testing (:require [myprivatelib]))" ), THEN you must re-compile (lein cljsbuild once) and reload your browser page with a link to compiled-app.js. This brings in that code base. Otherwise, your browser REPL will just keep insisting that the namespace provided in your closure library is not defined.
I hope this helps.