I'm trying to use ClojureScript for a project. To be a happy developer, I need a quick feedback-loop: write some code and see it as soon as it's possible. I'd also love to use REPL in the context of the current page.
I'm using lein-cljsbuild and from the issues I'm having I think I failed to set it up properly.
First of all, compilation time for a small file is too big, even after "JWM warm-up" with :optimizations :simple:
Compiling "resources/public/js/cljs.js" from ["src-cljs"]...
Successfully compiled "resources/public/js/cljs.js" in 8.233018 seconds.
Compiling "resources/public/js/cljs.js" from ["src-cljs"]...
Successfully compiled "resources/public/js/cljs.js" in 5.522989 seconds.
Compiling "resources/public/js/cljs.js" from ["src-cljs"]...
Successfully compiled "resources/public/js/cljs.js" in 8.144354 seconds.
Second, from time to time I get stuff like this:
Compiling "resources/public/js/cljs.js" from ["src-cljs"]...
Compiling "resources/public/js/cljs.js" failed.
Exception in thread "main" java.lang.NullPointerException
at java.util.regex.Matcher.getTextLength(Matcher.java:1140)
at java.util.regex.Matcher.reset(Matcher.java:291)
at java.util.regex.Matcher.<init>(Matcher.java:211)
at java.util.regex.Pattern.matcher(Pattern.java:888)
at clj_stacktrace.utils$re_gsub.invoke(utils.clj:6)
# ... many similar useless lines
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
These stacktraces (most of the time related to syntax errors, as I understood from experimenting), are worse than not helpful: not only they provide zero clues about the error, they also stop automatic recompilation. After every such stacktrace I should do these things:
Figure out what's the problem, using a technique I call "pretend you're a parser". Thank God it's Lisp and the only thing I should do is to carefully count matching parentheses.
Press Cmd-C in the shell where the lein cljsbuild auto runs
Run lein cljsbuild auto again
Make some useless change, like inserting a newline, in the file, to trigger a new build
Wait for ~30 seconds until the file is compiled again, since the JVM has to "warm-up" again
In many cases at this point I get another stacktrace, after getting which I have to lather, rinse and repeat all the damned procedure
Third thing which I failed to understand is REPL. From the interwebs I've learned how to connect rlwrap lein trampoline cljsbuild repl-listen to the current page. However, every reload, navigation, and syntax error (god forbid you forget to use rlwrap and press an arrow key) in the console makes the REPL completely stuck. I have to restart it (~10 seconds) and reload the page after that, then start again trying stuff out in a friendly environment.
I think, probably someone has figured it all out and has a workflow that works. Please help me set it all up from the start, because I feel like a failed software engineer.
For me Catnip provides the best dev experience for ClojureScript at the moment.
Check out figwheel! It's like livereload on steroids.
Working with clojurescript and front-end development was never so much fun!
See for yourself (the demo is a bit outdated – it's even better now!)
It not just reloads the page when files are changed – it provides you interactive programming Bret Victor was talking about (I recommend you to watch that talk if you haven't)
I've tried inside Emacs this tool https://github.com/cemerick/austin and works very well as you can see in his demo and screencast.
Have a good development
Juan
When in development mode turn :optimizations to :none, it makes a huge difference it won't change the initial compile time but any additional changes will only take milliseconds typically.
I have the following in my project.clj
:cljsbuild {:builds [{;; Directories of interest:
:source-paths ["src"]
;; Compiler flags:
:compiler {;; Where to save the file:
:output-to "resources/public/js/app.js"
;; Where to put the output directory
:output-dir "resources/public/js/out"
;; Optimizations:
:optimizations :none
}}]}
compilation time for a small file is too big
Try :optimizations :whitespace. And use lein cljsbuild auto
Second, from time to time I get stuff like this: ......
I haven't met this problem before. It looks like a bug in cljsbuild. Try to change another version maybe. I'm using [lein-cljsbuild "1.0.2"] with [org.clojure/clojurescript "0.0-2156"]. The 1.0.3 doesn't work in my setup.
Third thing which I failed to understand is REPL
In your case the key point is to find a way reloading namespaces without restart REPL or reloading page.
I find load-file is good for this.
My workflow is:
First start REPL: rlwrap lein trampoline cljsbuild repl-listen
Make sure there is (repl/connect "http://localhost:9000/repl") in my code.
Open my page in browser.
Do some test (my-namespace/my-func a b c)
Edit my codes.
In my REPL, run (load-file "path-to-my-file.cljs")
Repeat 4
This is still a pretty annoying workflow. load-file is slow and fragile so sometimes I browser to test. I hope someone can provide a better answer.
Related
In Python world, whenever I need to try something I'd just make a new file a.py and insert the code that I want to try, and run it. This works because of the shebang line
#!/usr/bin/env python3
Which tells the os which interpreter to call for the file.
Is there an equivalent to this in clojure? I don't want to jump through all the hoops of running lein new app and specifying the main ns, everytime I just want to check out what a few lines of code does in a file.
Note that I already know about lein repl. And I tried to use that as the shebang
#!/usr/bin/lein repl
But this just brings up an error
No :main namespace specified in
project.clj.
If you have Clojure CLI tools installed, then you can use shebang scripts:
test.clj:
#!/usr/bin/env clj
(def x 10)
(println "x =" x)
In terminal:
chmod +x test.clj
./test.clj
Output:
x = 10
You can do this with boot. See https://github.com/boot-clj/boot/wiki/Scripts
Also, the ClojureVerse has a thread on this at https://clojureverse.org/t/scripting-with-clj/1618/5 where some options are being discussed.
Still, you should be aware that such an approach is probably not very useful. On the one hand you quite often want to manage dependencies on the other there's the startup time of the JVM, in particular when you need to compile some clojure sources first. If you need to run your script a few times because you're trying out thing, the startup time quickly becomes are real obstacle.
As an idea, I usually keep a leiningen project around for quick experiments. Here, I can adjust the dependencies as needed and quickly fire up a REPL to tinker with ideas and try out things. For me, it is not uncommon to find this REPL up and running and an Emacs already connected to it.
Exploring Clojure - I am working through Clojure For The Brave And True. I created the hello world (in this case, I'm a little teapot). I can run it from lein repl just as the book suggests.
The author of the book appears to be a big emacs fan. I am comfortable with Intellij Idea, so installed the Cursive plugin. I then:
Set up a repl "runner" as shown on the Cursive site.
Tried loading the hello world into the repl. It appears to have done
so.
Now what? I presumed after loading the contents of the editor, I could run it, but have not figured out how. Obviously, this is a very noob question.
The code in my editor follows.
(ns clojure-noob.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "I'm a little teapot!")
)
The repl window is divided into two panes. The upper pain shows it is connected to the local nREPL server. Then, after loading it states:
Loading src/clojure_noob/core.clj... done
In the lower pane, per comments, I tried two variations of run, both of which failed miserable as you can see below (it didn't surprise me the second failed for it was calling out run, not the function).
run -main
CompilerException java.lang.RuntimeException: Unable to resolve symbol: run in this context, compiling:(/tmp/form-init2302589649746976452.clj:1:4481)
=> #object[clojure_noob.core$_main 0x24d21d67 "clojure_noob.core$_main#24d21d67"]
run clojure-noob.core/-main
CompilerException java.lang.RuntimeException: Unable to resolve symbol: run in this context, compiling:(/tmp/form-init2302589649746976452.clj:1:4481)
=> #object[clojure_noob.core$_main 0x24d21d67 "clojure_noob.core$_main#24d21d67"]
ANSWER
Thanks to comments from #Carcigenicate, I was able to figure out what to do. The answer is:
Enter (clojure-noob.core/-main) into the lower pane
Position cursor to the right of the closing paren
Press enter.
This resulted in the following:
(clojure-noob.core/-main)
I'm a little teapot!
=> nil
Told you it was a noob question!
This will be much easier in the next version of Cursive - the EAP will hopefully be out later this week or next week. You'll have the IntelliJ-standard ways of running -main functions more easily accessible:
Of course, the Clojure Way is to use the REPL as you're discovering, so continuing to explore that way of programming is definitely to be encouraged!
I'd like to do some OpenGL programming in Common Lisp, under Emacs and SLIME. I'm not set on it, but I'm currently trying to use SBCL. If I open up emacs from the start, create a new file with just this one line:
(ql:quickload :cl-opengl)
And then I do M-x slime (and wait for it to load), followed by C-c C-c to compile and run that line, SBCL crashes immediately, every time, prompting a dialog box that says sbcl quit unexpectedly:
I've saved the output that's accessible by clicking the "Report..." button; if that's useful, I can add that here (or put it on pastebin or something)... the short version is it's getting a SIGTRAP.
This happens every time I try to run this under SLIME... but, interestingly, it doesn't happen if I run SBCL from the command-line.
So, the question: Is this a bug in SBCL? In cl-opengl? Something I have mis-configured? Other? Any insights would be greatly appreciated.
Note:
I've done some google searching, and I found a page which provides a workaround of putting the following in ~/.swank.lisp:
(setf swank:*communication-style* :fd-handler)
Indeed, that gets me past the immediate crash, and gets me able to do some work. If that's simply the answer, someone please post it as an answer with an explanation of why that's the thing to do, so that others may find it. Otherwise, I'm imagining this to be a bug, though, that could be fixed, rather than worked around... and/or at least something that I could be helped to better understand; I still don't have a responsive REPL with my current code (basically on brian's brain, as a test case) running (via run), which may or may not be a separate question? Did changing the swank config change that situation for me?
Platform details:
OS: MacOS 10.6.8
SBCL: sbcl#1.1.10_0+fancy from MacPorts; launch header This is SBCL 1.1.10, an implementation of ANSI Common Lisp.
Emacs: macports-installed Emacs Version 24.3 (9.0) (per the GUI about window, or GNU Emacs 24.3.1 (x86_64-apple-darwin10.8.0, NS apple-appkit-1038.36) of 2013-04-07 per M-x version, or the emacs-app#24.3_1 port)
Slime: slime#20130630 from MacPorts
It sounds like a thread support issue with SWANK
The :fd-handler option changes the way SWANK communicates from the default, which is to use separate threads for communication, to using a loop approach (http://www.common-lisp.net/projects/slime/doc/html/Communication-style.html).
There used to be quite a few complaints about using SBCL with threading on Mac OS, these were largely fixed from the look of it; maybe SWANK is having similar issues?
I'm not 100% sure this is the sole cause of your problems, but it's the best explanation I could find.
I have been looking through my setup to see what was different
OS X 10.9
SBCL 1.1.8.0-19cda10
slime-20131003
But the most likely offender is still slime/swank.
I really recommend using quicklisp to manage your slime setup rather than macports, this will keep both slime and swank in sync and up to date. I've been using slime this way for a year or two and have had no issues so far.
From the quicklisp page:
To install and configure SLIME, use:
(ql:quickload "quicklisp-slime-helper")
Then follow the directions it displays. quicklisp-slime-helper will
create a file you can load in Emacs that configures the right
load-path for loading Quicklisp's installation of SLIME
I also made a small video showing how to install emacs+sbcl+quicklisp+slime under windows. The slime part is still relevant on all platforms.
Hope it helps.
I'm new to Clojure, and after too much of my life have been already wasted on waiting for Leiningen to run my code, I'm trying to move to Cake. While Cake's persistent JVM loads up blazing fast - it presents a bigger problem - my functions are also persistent!
To demonstrate the problem, I've started a cake project(using cake new mess-up-with-cake), and wrote this in core.clj:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
)
(println "I'm in core.clj, not inside in any function")
And this is project.clj:
(defproject mess-up-with-cake "0.0.1-SNAPSHOT"
:description "TODO: add summary of your project"
:dependencies [[clojure "1.2.0"]])
(use 'mess-up-with-cake.core)
(deftask my-task
(println "I'm in my task")
(main-function)
)
When running it with cake my-task, I get:
I'm in core.clj, not inside in any function
I'm in my task
I'm in the main function
No surprise here.
Now, I've changed core.clj to this:
(ns mess-up-with-cake.core)
(defn main-function[]
(println "I'm in the main function")
(println "I've made a change in the main function")
)
(println "I'm in core.clj, not inside in any function")
(println "I've made a change outside the main function")
And when I run it, I get
I'm in core.clj, not inside in any function
I've made a change outside the main function
I'm in my task
I'm in the main function
core.clj was clearly reloaded, but the change I've made inside the main function was not printed! Only when I stop the JVM with cake kill and rerun it I get the desired result - but if I have to restart the JVM every time I change a function, I might as well go back to lein...
Any idea how to force cake to reload my functions(and only my functions - reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM..)?
This may not directly answer your question, though I hope it helps:
It sounds like your workflow if you where using leiningen would be to run:
lein run
wait for the JVM to start up .... get bored ...
observe result
edit code
repeat
This is a very common pattern in most languages and it's occasionally used for Clojure development (and Cake is very helpful here). It is much more common for Clojure development to use a single instance of the project and connect the editor to that instance using nrepl (or Slime and Swank). Because most everyone leaves the project running while they do the development not many people feel this pain and so the solutions are not as good in my opinion. Cake has largely been merged into Leiningen and the future direction of the Cake project is not clear to me (I could very well be wrong on this point). Of the Clojureians I know, all of them have moved to Leiningen and connect to their project from an editor like Emacs or vim.
a common workflow is:
start Emacs
M-x nrepl-jack-in
Ctrl-c Crtl-l to reload all the namespace and all it's dependent namespaces (this is close to a solution to your problem)
hack, load, repeat ;-)
This workflow is not Emacs or VI specific, the same method is used from Eclipse and Intelij
re: " reloading the entire Clojure runtime + any libraries I'm using probably won't be much faster than restarting the JVM".
I find it to be no more than two seconds even with my larger projects
I used to struggle with the slow JVM startup speed as well, and had mixed success with Cake. You might want to take a look at the excellent autoexpect plugin for Leiningen, explained in some length in the author's blog post. Basically autoexpect reloads your code every time the working directory tree is updated (and evaluates any expect clause, reporting any test failures). Makes continuous testing a dream -- I sometimes have two shells going in Emacs -- one for the output of lein autoexpect, one for a connected REPL to send snippets of code to as the other poster is suggesting.
I like the continuous testing style so much I wrote a similar utility in Python for my non-Clojure development (described in this blog post) -- for Clojure, I use autoexpect.
I want to control a number of lein-plugins (lein-cljs build, lein-aws, lein-beanstalk) from my lein repl. Is there a way to do this?
For example, I want to be able to call
plugin/src/leiningen/cljsbuild.clj: once
from the repl -- however, I apparently can't (require 'leiningen.cljsbuild) into my lein repl.
Thanks!
I'm not sure if this addresses what you are actually trying to do, but do you know about lein interactive mode? EDIT: Since lein interactive doesn't exist in the new version of lein, the solution may be in some use of jark. Jark has an interactive mode and a plugin to use lein, so it may be possible to issue both lein commands and call clojure functions from a single interactive prompt.
The Vinyasa library claims to provide this functionality. At the time of this writing, vinyasa.lein is broken, but it may be fixed in the near future.