Light Table 0.7.2 running a "live" browser repl with clojurescript.
I'm just documenting a solution to a problem that was blocking me from using Light Table. I couldn't find any suitable answers, and it took a while for me to find a workaround. Hopefully, this will help anyone else experiencing a similar problem.
When editing a scratch file that is not the core cljs source file for the project (as specified in project.clj:cljsbuild:builds:source-paths), I was getting the following when defining a namespace:
(ns foo)
ReferenceError: goog is not defined
In attempting to use something like dommy, I would get:
(ns foo.bar-2
(:require
[dommy.core :as dc]
[domina.xpath :as dx]))
Error: goog.require could not find: dommy.core
I found similar problems here [Clojurescript libraries - goog.require could not find
and here https://groups.google.com/forum/#!searchin/light-table-discussion/goog$20/light-table-discussion/D4xjfDnA2Co/7iaqewIPzGUJ
However, in the first case, the solution did not work. In the second case I was unable to understand what the user meant by "just not live evaling clojurescript namespaces in LightTable and relying on the browser/DOM behavior for feedback" as a workaround.
The reason for me not using the main file of the project is I want to do some quick one-offs in a separate repl. This is something I am able to do under emacs. Normally, under emacs, I will have the main cljs file, and then the ncider repl. I will put both into the same namespace, so I can update the shared context from either buffer.
Assumptions:
I assume you know already know how to bring up the two servers needed by Light Table: the clojure repl, and the browser.
Basically, this link:
http://grokbase.com/t/gg/clojure/142rsp4rc8/om-trouble-with-goog-reference
tipped me off to the solution.
It appears that any file that is not under the project src dir, is totally dependent on the browser "repl" to find any libraries it needs. So the solution is to add tags to your index.html for any js libraries you want to include in the ns:
<html>
<head>
<script type='text/javascript' id='lt_ws' src='http://localhost:54792/socket.io/lighttable/ws.js'></script>
<script src="out/goog/base.js" type="text/javascript"></script> <!-- add this -->
</head>
<body>
hello from mies-test
<script src="out/mies_test.js" type="text/javascript"></script>
</body>
</html>
You must then do the following:
1) Make sure you have any js libraries (other than 'goog') under your project.clj dependencies:
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2755"]
[domina "1.0.3"]
[prismatic/dommy "1.0.0"]
[enfocus "2.1.1"]
2) run "lein cljsbuild once". You need to make sure you have goog/base.js and cljs/core.js under your output dir:
#HP_LAPTOP_ENVY /c/vtstuff/clojure_stuff/projects/mies2/out
$ ls *
cljs_deps.js mies_test.js
cljs:
core.cljs core.cljs.cache.edn core.js core.js.map
clojure:
browser
goog:
array base.js disposable functions iter log mochikit promise structs uri
asserts debug dom html json math net reflect testing useragent
async deps.js events i18n labs messaging object string timer
mies2:
core.cljs core.cljs.cache.edn core.js core.js.map
If you do a "lein clean" it will delete the "out" dir. Doing a "lein cljsbuild once" will then rebuild it. Do this if you want a clean start.
3) Refresh your browser url e.g
file:///C:/vtstuff/clojure_stuff/projects/mies2/index.html
4) Now when I ran (ns foo) I got:
Error: goog.require could not find: cljs.core
at Error (<anonymous>)
at Object.goog.require (file:///C:/vtstuff/clojure_stuff/projects/mies2/out/goog/base.js:470:13)
-> This seems to be an inconsistent problem. I was able to get another project to work without adding cljs/core.js to index.html. You can basically see here how any scratch buffer is entirely dependent on what the browser repl knows about. The main clojure repl is automatically aware of any dependencies, but here again I seem to need to add it to index.html:
<head>
<script type='text/javascript' id='lt_ws' src='http://localhost:61756/socket.io/lighttable/ws.js'></script>
<script src="out/goog/base.js" type="text/javascript"></script>
<script src="out/cljs/core.js" type="text/javascript"></script> <!-- add this -->
</head>
5) Refresh the browser again, and now evaluations in scratch.cljs work:
(+ 1 1 ) 2
(ns foo) nil
(namespace ::x) "foo"
6) if you want to add dommy to your ns:
(ns foo-2
(:require [dommy.core :as dommy]))
#<Error: goog.require could not find: dommy.core>
Error: goog.require could not find: dommy.core
You're going to have cause dommy/core.js to be created under the "out" dir. You'll have to extract the .cljs files from the dommy jar (in your maven ".m2" repos) and then add them to your src dir. Then do a "cljsbuild once" to generate dommy/core.js, then add a reference to index.html, like we did for 'goog' and 'cljs'. I did this and it worked. However, I now realize it's just best to have your scratch repl pull in the "main" cljs, and then just reference the artifacts from your scratch file (or just do everything in the main cljs, which is what I think the prior person was talking about when he said "avoiding 'live evaling'") :
(ns foo-3
(:require [mies2.core]))
mies2.core/abc 7
7) Unfortunately, you can't put the scratch file into the same ns as the main
cljs:
(ns mies2.core)
#<Error: Namespace "mies2.core" already declared.>
Error: Namespace "mies2.core" already declared.
Anyway, after figuring all this out, I was able to run a three.js cube demo. Maybe this will all seem obvious once I gain more familiarity with live browser "repling", but it certainly cause me a lot of confusion in the beginning.
Happy coding.
Related
I play with this great Gorilla REPL powered project ( https://bitbucket.org/probprog/anglican-examples/ to be specific), and want to use it under certain restricted circumstances.
Is there a way to produce an uberjar that can be started using only a JVM?
Well, I know how to create an uberjar for this project, but can I start a Gorilla REPL from it? If not what do I have to add and how do I start it?
EDITED Note on Juraj's answer:
I added a start file src/gorillaproxy/gorillaproxy.clj with the following content:
(ns gorillaproxy.gorillaproxy
(:use [gorilla-repl.core :only [run-gorilla-server]])
(:gen-class))
(defn -main
[& args]
(run-gorilla-server {:port 8990}))
Then I added [gorilla-repl "0.4.0"] to the dependency list (in project.clj), and the line
:main gorillaproxy.gorillaproxy
In that way the uberjar started the Gorilla REPL, and when I put the worksheets (and data, resources, .. if needed) into the same directory, everything worked fine.
Gorilla is typically run via the lein-gorilla plugin and thus isn't a part of an uberjar.
If you really want to create a bundle containing gorilla repl dependencies, then you need to add it this capability manually to your project.
The question is why would you want to do that.
Do you want to distribute these samples to somebody else? If that's the case, you'll still need to have all those worksheets in the current directory from where your uberjar is run because that's how gorilla repl discovers worksheets.
You can look at lein-gorilla source code to see how gorilla repl can be started.
I'd then at the same code to your project (create new src/core.clj file or whatever) and configure it in your project.clj as :main.
You'll also need to add gorilla-repl as a dependency to your project.clj
Notice however, that you'll need to run that uberjar from a directory where your anglican worksheets are (or a parent directory of such a directory).
I have implemented a hyphenation algorithm (at namespace hyphenator-clj.core), defined it as org.clojars.nikonyrh.hyphenator-clj 0.1.0 at defproject and pushed it to Clojars. Uberjar seems to have files like core__init.class, core.clj and core.class.
However when I try to use it as a dependency on an other project I get this error:
$ lein uberjar
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.pom from clojars
Retrieving org/clojars/nikonyrh/hyphenator-clj/org.clojars.nikonyrh.hyphenator-clj/0.1.0/org.clojars.nikonyrh.hyphenator-clj-0.1.0.jar from clojars
Compiling example.core
java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
Exception in thread "main" java.io.FileNotFoundException: Could not locate org/clojars/nikonyrh/hyphenator_clj__init.class or org/clojars/nikonyrh/hyphenator_clj.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(core.clj:1:1)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile1(Compiler.java:7464)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
...
Must I change my project's folder structure so that it matches the expected org/clojars/nikonyrh/hyphenator_clj__init.class, or can I somehow override the current behavior? If there is a good tutorial about this out there I would be happy to read it.
Basically I would like to get this example project to work. project.clj:
(defproject example "0.0.1-SNAPSHOT"
:description ""
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojars.nikonyrh.hyphenator-clj "0.1.0"]]
:javac-options ["-target" "1.6" "-source" "1.6" "-Xlint:-options"]
:aot [example.core]
:main example.core)
src/example/core.clj:
(ns example.core
(:require [org.clojars.nikonyrh.hyphenator-clj :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
I'm suspecting I also have the english.txt in a wrong directory, as it isn't contained in the uberjar but resource files are an other topic.
You would probably be better off not using a hyphen in the namespace hyphenator-clj. Why not just use hyphenator? But if you do I suspect that the name of the directory should have an underscore in it rather than a hyphen, so be: hyphenator_clj.
If fixing that issue doesn't help then another thing to look out for, which I can't see from your question, is where exactly is core.clj in the directory structure, and does the project.clj reflect that? For instance is the path for the namespace hyphenator-clj.core in a src directory off the root of your project? The root of your project being defined as where the project.clj is located.
Something else that would be good to see in the question is whether you can get the program to work just locally, without having packed it up into an uberjar and shipped it to clojars. My guess would be that it does work locally, but it would help for that to be stated.
Okay taking a look at your links now. You might like to read a working project deployed to clojars, that has hypens in its name, for instance here. The first difference you might notice is the project name you use is rather long: org.clojars.nikonyrh.hyphenator-clj. It should just be hyphenator-clj. Also I would recommend having an identifier ending in "-SNAPSHOT" as that project does.
But taking a look at the bigger picture, a great idea you suggested in the comments is to test without Clojars being in the mix at all. To do this use lein install on the library you want to use from another lein project.
Ahaa at least I understand the process a bit better now, basically my require has to match the structure of the used JAR file, which may be very different from the project's name. For example cc.qbits/spandex is actually required as qbits.spandex.
The english.txt dependency was fixed by moving it to resources folder, deploying the new version to Clojars and importing the dependency as it exists in the JAR:
(ns example.core
(:require [hyphenator-clj.core :as h])
(:gen-class))
(defn -main [& argv] (doseq [arg argv] (println (h/hyphenate arg :hyphen \-))))
How to configure project.clj file to configure it to output html & css files from hiccup & garden on compiling, so that i can deploy to server without any dynamic css/html loading on client side ?
If you don't really need to use Leiningen, using Boot you can do it easily with perun.io, especially if website is the primary objective:
https://perun.io/guides/getting-started/
https://github.com/hashobject/perun.
I rewrote my website that way https://github.com/ArchieT/website-archiet.
If there is a need to use Lein, maybe I'll look at it later as I don't have much time right now.
It should not be hard to do.
You can use the lein-garden leiningen plugin: https://github.com/noprompt/lein-garden.
Here's an example config.
(defproject cash-money "1.1.1"
:plugins [[lein-garden "X.X.X"]]
:garden {:builds [{;; Optional name of the build:
:id "screen"
;; Source paths where the stylesheet source code is
:source-paths ["src/styles"]
;; The var containing your stylesheet:
:stylesheet cash-money.core/screen
;; Compiler flags passed to `garden.core/css`:
:compiler {;; Where to save the file:
:output-to "resources/screen.css"
;; Compress the output?
:pretty-print? false}}]})
Then you can run lein garden auto to watch for changes and automatically recompile.
If you want an example of a codebase using this: https://github.com/Dexterminator/spotify-data-extrapolator/tree/db8d6e16529940272409598c8ac0fdbbaf739646
To help you find stuff like this in the future, I'll describe a process for discovery.
I found this by going to the garden github repository (https://github.com/noprompt/garden) and looking through the code for a bit of text that looked like it would be unique to garden so that I could search all of github and find other repositories that used garden. The bit of text I chose was defpseudoelement. I scanned the projects that were already using garden and found one that mentioned running lein garden auto in the readme. Searching again for lein garden auto took me to the lein-garden leiningen plugin. In hindsight, it would probably make more sense to see what other libraries the author of garden has written. That would have taken us directly to the plugin. C'est la vie.
I'm very interested in using CLJS and Untangled to make a dynamic web app. I have some very basic questions, though. My first question is: I see that like in other frameworks, there is a base index.html that has a .js file reference and the <div id="app"></div> is tied to the javascript file.
So in the Untangled Template project from github, I have my Figwheel server running and I wanted to do some tinkering on the dev-index side.
<body>
<div class="container-fluid" id="app"><div>Now loading super sweet app</div></div>
<script src="js/untangled_template.js" type="text/javascript"></script>
</body>
However, there's no file called untangled_template.js and I'm wondering what would be the bare minimum scaffolding for such a .js file.
Having used Clojure, but not really broken into Clojurescript yet, I'm curious how this .js file comes to be (since presumably it's first written in cljs)
Thanks many
Disclaimer: I've never used Untangled.
This line of the Untangled template's project.clj is probably what you're looking for. Note how in the :cljsbuild section of this file, there are several builds listed - when you run lein figwheel, the dev profile is used, and whenever you make changes to your cljs code, Figwheel compiles your cljs (note the :source-paths part of this build map) and puts the generated JS in resources/public/js/untangled_template.js.
You say you're not seeing an untangled_template.js file - do you mean that you don't see a file with that name in the root directory of your Leiningen project, or do you mean that when you load your index.html in a Web browser it complains that it can't find /js/untangled_template.js?
I need to share a namespace between my Clojure (Garden) and my ClojureScript (Reagent).
Currently the project folder looks like this:
src/
clj/
name/
css.clj
cljs/
name/
core.cljs
cljc/
name/
config.cljc
The config.cljc file has the following namespace: (ns name.config).
I've tried to reference this namespace from inside clj/name/css.clj with a require.
(ns name.css
(:require [name.config :as config]))
However, this results in a compile error from Garden.
Caused by: java.io.FileNotFoundException: Could not locate name/config__init.class or name/config.clj on classpath.
I guess it's not even checking for cljc files.
I added "src/cljc" to the :source-paths vector in project.clj and :garden :builds but I get the same error even after restarting the build processes.
I see this behaviour on Clojure 1.7.0 and 1.8.0.
It might also be worth mentioning that it works without issues in ClojureScript (with Figwheel handling the build). I can require and use the new namespace without problems.
It seems like I must be missing something really simple, because none of the documentation around .cljc files even mentions requiring them.
Check if you’re using Clojure 1.7 or above in your project.clj. This error message:
Caused by: java.io.FileNotFoundException: Could not locate name/config__init.class or name/config.clj on classpath.
indicates that you’re using Clojure 1.6 or below, as those versions of Clojure only know to look for .class or .clj files.
I got this same error when I moved a file from .clj to .cljc in my project. I did lein clean but that had no effect. Eventually I renamed the module namespace and that fixed it.
(My guess is that there was some sort of cache of compiled modules and it was referencing a module which no longer existed, but the cljc wasn't re-compiled because a module of that name was still cached.)
When I renamed the module namespace it worked, with no other changes to the code.