Skip to main content

Considerations for JavaScript in Modern (2013) Java/Maven Projects

Disclaimer: I'm a Java developer, not a JavaScript developer. This is just what I've picked up the last years plus a little research the last days. It's just a snapshot of my current knowledge and opinions on the day of writing, apt to change over the next weeks/months.

We've gone all modern in our web applications, doing MVC on the client side with AngularJS or Ember, building single-page webapps with REST backends. But how are we managing the growing amount of JavaScript in our application?

Yeoman's logo (not necessarily the conclusion of this blog post)

You ain't in Kansas anymore

So far we've just been doing half-random stuff. We download some version of a library and throw it into our src/main/webapp/js/lib, or we use it from a CDN, which may be down or unreachable when we want to use the application..

Some times the JS is minified, other times it's not. Some times we name the file with version number, other times without. Some times we get the latest library of master branch and name it with the commit-id in the file name, other times we write the commit-id into the top of the included file, or maybe forget about it completely (but please note the source in the commit message at least!). We write CoffeeScript/Typescript that generates JavaScript and we check both files in.

Sigh.

This is a mess. Add to it the mess of just including all JavaScript libraries into the global scope and loading them in random order. 

So, there are some camps out there who are figuring out how to solve this.

There's the Google/GWT/Closure camp, which should be very appealing to Java developers, doing everything "properly" with Maven and Ant plugins. There's also James Ward's WebJars.org which looks promising, but the library coverage is still kind of scrawny.

On the other side, there's the traditional webapp makers, the PHP/Ruby/Node camp(s) which depend on having either of these tools on the command line and using them during development and during the build process. 

My gut feeling is that the latter camp is where the most interesting activity is coming from. These guys have the most experience with hacking and building together tools for easing web development, and they're busier than ever. 

Why not just use Maven plugins and WebJars?

There are plenty of maven plugins for doing JavaScript processing, and you can treat JavaScript libraries as regular runtime dependencies if you want (just overlay them into your webapp).

However, Maven plugins and webjars are regularly far behind the respective Node/Ruby tools because:
  • Maven plugins are tedious to create, so most library devs can't be bothered, and leave it to volunteers from the community.
  • Many library devs don't use Maven anyway.
  • Many library devs are mainly JavaScript developers. Maybe they know a little Ruby or PHP at the most. Probably a lof of them hate Java.
  • The maven plugins use older versions of tools since they are lagging behind. This will be annoying for you as you may have to start patching plugins to get the latest fixes from the JS library in question.
And Maven projects has a tendency to suck things into their tediously slow lifecycle, and depend on the IDE  to speed things up. This works great for some few big languages and libraries, but it's impossible for our IDE's to keep up with the myriad of web development going on out there (although IntelliJ IDEA is doing a fine job of trying).

So, let's run through the various things we want to do with our JavaScript:

Automating tasks, scripting

How do we run the whole build, and trigger other JavaScript processing? We need a scripting tool for automating tasks: copying stuff around, running optimizers, etc. Some place we can call into during the Maven build (using maven-exec-plugin or something like that).

Equivalent in Java land: Ant, Gradle, bash/bat

Solution: Grunt

Alternatives: Pure Node.js? Bash/bat.

Downloading, managing dependencies

Manually downloading JavaScript libraries and upgrading them is a hassle.

Equivalent in Java land: (parts of) Maven, Ivy

Solution: Bower. Based on Node/npm. No central repository, but central registry, uses Git for downloading.

Alternatives: JamJS. Doing it manually.

Managing dependencies at runtime

Since JavaScript has no packages or namespaces, this can get messy quickly, so you need to handle which libraries come into play in which places.

Equivalent in Java land: Maven, packages, classloader fiddling, OSGi

Solution: RequireJS

Alternatives: YepNope. Anything that implements CommonJS or AMD.

JavaScript MVC framework

I'm not sure if that's a good term for it, but the point is to place logic in organized places, and get features like dependency injection and separate your JavaScript from the DOM as much as possible. If you're just working the DOM with JQuery, you're doing it wrong (cause you can't unit-test it).

Equivalent in Java land: Spring MVC, Struts

Solution: AngularJS (from the Google camp) or Ember (from the Rails camp)

Alternatives: Knockout.js, Backbone.js and many others. There's a real framework war going on.

Running unit-tests and web-tests

I haven't researched too much in this direction, as we've just followed the AngularJS recommended choice of the Karma test runner. I like the concept that I can run pure JavaScript unit tests without firing up a browser.

This choice is likely to depend a lot on what other tools you pick. Regarding mocking, I've heard good things about Sinon.js which will work with any testing framework.

Writing JavaScript or generating it

Instead of writing "raw" JavaScript, you stick use the friendly CoffeeScript, the strongly typed TypeScript or the functional ClojureScript. All these transform into JavaScript in the end, although the first two are compiled with Node.

The reason why you should do this is that JavaScript has a lot of sharp edges that can bite you if you don't know the language well.

You could also skip this step and save yourself the extra build-step and level of source-mapping.

Finding the JavaScript source of compressed JavaScript

Make sure you get this right or debugging will be a right pain. The point is to be able to look up where in which source file you are inspecting from your browser, and source maps are the key. There are many tools that can generate source maps for you, but I'm not sure which one I would use yet. Not sure how this applies to CSS (see below).

Styling

Now I know this isn't part of JavaScript, but I'll do some notes about CSS here since it's often handled in the same part of the build. You do not want to type CSS manually, as the standard has moved very slow since its inception.

I'm still kind of fresh in this area. There's a CSS-preprocessor called LESS, and there's another one called Sass. Now Sass comes in two different syntaxes: the original .sass (which is kinda whitespace-sensitive stuff), and there's the new .scss which looks a lot more like CSS than Sass does.

There are also some things called Compass and Bourbon, which are both some kind of mixin-managers for Sass, which allow you to not have to deal with vendor-prefixes and other goodness. Both of these are Ruby-based, so

I'd think I'd go for Sass with .scss syntax these days, probably with Bourbon added.

By the way, here's a recent podcast episode from TheChangelog on this subject.

What about Yeoman?

It's somewhat of a starter kit for client-side applications. It features several of the above mentioned technologies in an "opinionated" stack, including Grunt and Bower. I think I'd definitely take this for a spin, as it encompasses the tools I would choose today.

Conclusions

Make sure you are left with a stack that lets you keep a quick roundtrip. Save file, refresh in the browser, change is there.

  • Stick to Node/NPM. Node is supposedly working well cross-platform now. 
  • Grunt is great. Give up on trying to do everything with Maven. 
  • Avoid Ruby? The way I see it I have to drag in Node/NPM at some point anyhow, and if I can then do without managing Ruby versions on my systems, all the better. JRuby via Maven is also an option. (counter-point: Sass, Bourbon and Compass tend towards Ruby)
  • Write pure JavaScript or try out CoffeeScript. I'd say Typescript is a bit too bleeding edge for now (though I may be wrong). ClojureScript is too different from the resulting JS, unless you're using Clojure on the server-side.
  • Frame your JavaScript in a framework like AngularJS or Ember. These have a great ramp-up for getting newcomers started on building single-page applications with tests.
  • Use Sass. With SCSS syntax because that is most similar to normal CSS.

---------------------------------------
PS: If you enjoy podcasts like I do, I recommend JavaScript Jabbers. A lot of the things above I picked up from a few of their episodes here:

Popular posts from this blog

Encrypting and Decrypting with Spring

I was recently working with protecting some sensitive data in a typical Java application with a database underneath. We convert the data on its way out of the application using Spring Security Crypto Utilities. It "was decided" that we'd be doing AES with a key-length of 256, and this just happens to be the kind of encryption Spring crypto does out of the box. Sweet!

The big aber is that whatever JRE is running the application has to be patched with Oracle's JCE in order to do 256 bits. It's a fascinating story, the short version being that U.S. companies are restricted from exporting various encryption algorithms to certain countries, and some countries are restricted from importing them.

Once I had patched my JRE with the JCE, I found it fascinating how straight forward it was to encrypt and decrypt using the Spring Encryptors. So just for fun at the weekend, I threw together a little desktop app that will encrypt and decrypt stuff for the given password and sa…

Managing dot-files with vcsh and myrepos

Say I want to get my dot-files out on a new computer. Here's what I do:

# install vcsh & myrepos via apt/brew/etc
vcsh clone https://github.com/tfnico/config-mr.git mr
mr update

Done! All dot-files are ready to use and in place. No deploy command, no linking up symlinks to the files. No checking/out in my entire home directory as a Git repository. Yet, all my dot-files are neatly kept in fine-grained repositories, and any changes I make are immediately ready to be committed:

config-atom.git
    -> ~/.atom/*

config-mr.git
    -> ~/.mrconfig
    -> ~/.config/mr/*

config-tmuxinator.git  
    -> ~/.tmuxinator/*

config-vim.git
    -> ~/.vimrc
    -> ~/.vim/*

config-bin.git   
    -> ~/bin/*

config-git.git          
    -> ~/.gitconfig

config-tmux.git  
    -> ~/.tmux.conf    

config-zsh.git
    -> ~/.zshrc

How can this be? The key here is to use vcsh to keep track of your dot-files, and its partner myrepos/mr for operating on many repositories at the same time.

I discovere…

Always use git-svn with --prefix

TLDR: I've recently been forced back into using git-svn, and while I was at it, I noticed that git-svn generally behaves a lot better when it is initialized using the --prefix option.

Frankly, I can't see any reason why you would ever want to use git-svn without --prefix. It even added some major simplifications to my old git-svn mirror setup.

Update: Some of the advantages of this solution will disappear in newer versions of Git.

For example, make a standard-layout svn clone:

$ git svn clone -s https://svn.company.com/repos/project-foo/

You'll get this .git/config:

[svn-remote "svn"]
        url = https://svn.company.com/repos/
        fetch = project-foo/trunk:refs/remotes/trunk
        branches = project-foo/branches/*:refs/remotes/*
        tags = project-foo/tags/*:refs/remotes/tags/*

And the remote branches looks like this (git branch -a):
    remotes/trunk
    remotes/feat-bar

(Compared to regular remote branches, they look very odd because there is no remote name i…

Microsoft ups their Git efforts another notch

This week Microsoft announced first class Git support embedded in the coming version of Visual Studio.

Now, it's not completely shocking. We could have seen it coming since Microsoft started offering Git repos on CodePlex, and more recently offering a Git client for TFS. In any case, these are some big news. Scott Hanselman weighs on some features and some more background here.

For those who are a bit unaware of what the Git situation on Windows looks like these days, I've dotted down these notes:
Some explanation on these:

msysGit has long been The Way to use Git on Windows. It's basically a port of Git itself, so it's a command-line tool.GitExtensions (includes Visual Studio integration), TortoiseGit, Git Shell, posh-git and most other tools are powered by msysGit.libgit2 is a native library for doing Git stuff. It is developed completely separate from Git itself. The above tools could (and should) probably use libgit2 instead of hooking onto and around msysGit.Github…