views:

1997

answers:

5

I've written a small Swing App before in Clojure and now I'd like to create an Ajax-style Web-App. Compojure looks like the best choice right now, so that's what I'm going to try out.

I'd like to have a real tiny edit/try feedback-loop, so I'd prefer not to restart the web server after each small change I do.

What's the best way to accomplish this? By default my Compojure setup (the standard stuff with ant deps/ant with Jetty) doesn't seem to reload any changes I do. I'll have to restart with run-server to see the changes. Because of the Java-heritage and the way the system is started etc. This is probably perfectly normal and the way it should be when I start the system from command-line.

Still, there must be a way to reload stuff dynamically while the server is running. Should I use Compojure from REPL to accomplish my goal? If I should, how do I reload my stuff there?

+2  A: 

This is highly configuration dependent but works for me and I think you can adapt it:

  1. Put compojure.jar and the jars under the compojure/deps directory are in your classpath. I use clojure-contrib/launchers/bash/clj-env-dir to do this, all you need to do is set the directory in CLOJURE_EXT and it will find the jars. CLOJURE_EXT Colon-delimited list of paths to directories whose top-level contents are (either directly or as symbolic links) jar files and/or directories whose paths will be in Clojure's classpath.

  2. Launch clojure REPL

  3. Paste in hello.clj example from compojure root directory

  4. Check localhost:8080

  5. Re-define the greeter (defroutes greeter (GET "/" (html [:h1 "Goodbye World"])))

  6. Check localhost:8080

There are also methods for attaching a REPL to an existing process, or you could keep a socket REPL embedded in your server or you could even define a POST call that will eval on the fly to allow you to redefine functions from the browser itself! There are lots of ways to approach this.

Timothy Pratley
+13  A: 

Here's an answer I got from James Reeves in the Compojure Google Group (the answer's here with his permission):

You can reload a namespace in Clojure using the :reload key on the use or require commands. For example, let's say you have a file "demo.clj" that contains your routes:

(ns demo 
  (:use compojure))

(defroutes demo-routes 
  (GET "/" 
    "Hello World") 
  (ANY "*" 
    [404 "Page not found"]))

At the REPL, you can use this file and start a server:

user=> (use 'demo) 
nil 
user=> (use 'compojure) 
nil 
user=> (run-server {:port 8080} "/*" (servlet demo-routes)) 
...

You could also put the run-server command in another clojure file. However, you don't want to put it in the same file as the stuff you want to reload.

Now make some changes to demo.clj. At the REPL type:

user=> (use 'demo :reload) 
nil

And your changes should now show up on http://localhost:8080

auramo
+4  A: 

I have a shell script that looks like this:

#!/bin/sh                                                                                                                                   
CLASSPATH=/home/me/install/compojure/compojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure/clojure.jar
CLASSPATH=$CLASSPATH:/home/me/clojure-contrib/clojure-contrib.jar
CLASSPATH=$CLASSPATH:/home/me/elisp/clojure/swank-clojure

for f in /home/me/install/compojure/deps/*.jar; do
    CLASSPATH=$CLASSPATH:$f
done

java -server -cp $CLASSPATH clojure.lang.Repl /home/me/code/web/web.clj

web.clj looks like this

(use '[swank.swank])                                                                                                                        
(swank.swank/ignore-protocol-version "2009-03-09")                                                                                          
(start-server ".slime-socket" :port 4005 :encoding "utf-8")

Whenever I want to update the server I create an ssh tunnel from my local machine to the remote machine.

Enclojure and Emacs (running SLIME+swank-clojure) can connect to the remote REPL.

dnolen
I've read about connecting to remote REPL before, but can you tell me how do I do that in emacs? My SLIME knowledge is currently limited to M-x slime -> start hacking...
auramo
Use M-x slime-connect to connect to a possibly remote runnnig swank server. You can start a swank server as outlined above in "web.clj"
ordnungswidrig
The new Leiningen build tool (http://github.com/technomancy/leiningen) automates this. You can just type "lein swank" at a command line and then M-x slime-connect (or "lein repl" to get a command line REPL.)
Paul Legato
A: 

You might be interested in this setup also.

Timothy Pratley
+3  A: 

Following up on Timothy's link to Jim Downing's setup, I recently posted on a critical addition to that baseline that I found was necessary to enable automatic redeployment of compojure apps during development.

Chas Emerick
Great post! How well does it all integrate with NetBeans? I'm an eclipse user for my day job, but am looking for a better platform to branch out into Clojure.
Adam
NetBeans has *excellent* support for maven, and the enclojure plugin is the best clojure environment at the moment, IMO. Emacs/swank/slime users will certainly disagree, but I suspect there's no chance of détente between the emacs/vim/IDE camps regardless.
Chas Emerick