Sane web development with Compojure, Jetty, and Maven

I find myself slipping back into web development in the new year. I’ve known this was coming for some time, so I’ve had a fair chance to carefully choose my weapons:

What has really tied this all together is Maven (and a couple of plugins for it), which has enabled me to fill in a couple of gaps in what is otherwise the most pleasant web development environment I’ve ever used (where Pylons was the prior champ, FWIW).

The biggest gap is in automatic application reloading/redeployment – in concrete terms, when I save a Clojure source file, my application should be reloaded nearly immediately, thereby avoiding any code-build-deploy cycle. To be precise, this capability is built into Jetty (as it is in many other Java-based app servers). The question is, how to most readily utilize it.

I came across this post by Jim Downing, which describes how to set up a Maven project for a Compojure application, enabling development-mode app reloading using the maven-jetty-plugin (the formatting on that post appears to have degraded since it was published; you can check out the project described in the post here). This certainly appears to fit the bill; unfortunately, the setup that Jim describes there doesn’t quite work for me – when I save a source file, the application is automatically redeployed, but no changes are picked up.

Thankfully, the fix is easy. Below is the relevant section of my pom.xml, configuring maven-jetty-plugin to add my Clojure source root as an extra classpath element. This allows Clojure, running in the jetty application server, to find and load any Clojure source files that are newer than their AOT-compiled counterparts in the usual target/classes directory (note the webAppConfig/extraClasspath elements):

<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>maven-jetty-plugin</artifactId>
    <version>6.1.15</version>
    <configuration>
        <contextPath>/</contextPath>
        <webAppConfig>
            <extraClasspath>src/main/clojure</extraClasspath>
        </webAppConfig>
        <scanIntervalSeconds>5</scanIntervalSeconds>
        <connectors>
            <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                <port>8080</port>
                <maxIdleTime>60000</maxIdleTime>
            </connector>
        </connectors>
        <scanTargetPatterns>
            <scanTargetPattern>
                <directory>src/main/clojure</directory>
                <includes>
                    <include>**/*.clj</include>
                </includes>
            </scanTargetPattern>
        </scanTargetPatterns>
    </configuration>
</plugin>

With that, I’m just a mvn jetty:run away (or, really, a single click away in NetBeans) from having a development process identical to paster serve --reload, with the added benefit of Clojurey goodness.

♬♫The more you know…♪♬

(Apologies to those who aren’t familiar with American pop culture.)

If you want to compile Clojure code (and really, if you’re involved in a project of any size or importance, you should be, if only to avoid forcing Clojure to generate bytecode at runtime, which will slow down the sort of rapid development enabled by automatic app redeployment as describe above), do me a favor and use clojure-maven-plugin. (The post I reference above manually invokes the Clojure compiler using ant’s exec task, but that was what you had to do back in July 2009.) It’s a great piece of kit, and additionally serves as a perfect gateway drug to Maven – which, despite the controversy, and my own quibbles with various aspects of it, will eventually save your bacon in any larger project.

About these ads
This entry was posted in Clojure, Maven. Bookmark the permalink.

7 Responses to Sane web development with Compojure, Jetty, and Maven

  1. Anonymous says:

    What happened to Foundercast?

    • Chas Emerick says:

      You mean, of course, Foundercast. Doug wanted to take a break from it for a while – not sure when (if?) he wants to move it along again.

      In the meantime, you can check out Strictly Professional, which is the podcast that I host (also occasionally).

  2. Freddy says:

    Very very cool.

    Thanks for clueing me in to Enlive. It’s a great combination with Compojure.

    Just a small detail, your contextPath tag belongs within the webAppConfig tag, otherwise it doesn’t work, i.e. it will ignore you if you change the context path to something else than ‘/’.

  3. Freddy says:

    By the way, what do you use for database access? clojure.contrib.sql or something else?

    • Chas Emerick says:

      We’re using CouchDB almost exclusively at this point, interfacing with it using clutch, which is an excellent couch access lib for clojure (disclosure: which I’ve contributed to here and there).

  4. Anonymous14 says:

    This post is really not very easy to follow. It’s unclear what needs to be used from Jim Downing’s post and what should be replaced w/ clojure-maven-plugin.

    An updated template pom.xml with your changes and clojure-maven-plugin would be helpful.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s