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:

Comments

Popular posts from this blog

Open source CMS evaluations

I have now seen three more or less serious open source CMS reviews. First guy to hit the field was Matt Raible ( 1 2 3 4 ), ending up with Drupal , Joomla , Magnolia , OpenCms and MeshCMS being runner-ups. Then there is OpenAdvantage that tries out a handful ( Drupal , Exponent CMS , Lenya , Mambo , and Silva ), including Plone which they use for their own site (funny/annoying that the entire site has no RSS-feeds, nor is it possible to comment on the articles), following Matt's approach by exluding many CMS that seem not to fit the criteria. It is somewhat strange that OpenAdvantage cuts away Magnolia because it "Requires J2EE server; difficult to install and configure; more of a framework than CMS", and proceed to include Apache Lenya in the full evaluation. Magnolia does not require a J2EE server. It runs on Tomcat just like Lenya does (maybe it's an idea to bundle Magnolia with Jetty to make it seem more lightweight). I'm still sure that OpenAdvant

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

What I've Learned After a Month of Podcasting

So, it's been about a month since I launched   GitMinutes , and wow, it's been a fun ride. I have gotten a lot of feedback, and a lot more downloads/listeners than I had expected! Judging the numbers is hard, but a generous estimate is that somewhere around 2000-3000 have listened to the podcast, and about 500-1000 regularly download. Considering that only a percentage of my target audience actively listen to podcasts, these are some pretty good numbers. I've heard that 10% of the general population in the western world regularly listen to podcasts (probably a bit higher percentage among Git users), so I like to think I've reached a big chunk of the Git pros out there. GitMinutes has gathered 110 followers on Twitter, and 63, erm.. circlers on Google+, and it has received 117 +'es! And it's been flattr'ed twice :) Here are some of the things I learned during this last month: Conceptually.. Starting my own sandbox podcast for trying out everythin

The academical approach

Oops, seems I to published this post prematurely by hitting some Blogger keyboard shortcut. I've been sitting for some minutes trying to figure out how to approach the JavaZone talk mentioned in my previous blog-post. Note that I have already submitted an abstract to the comittee, and that I won't publish the abstract here in the blog. Now of course the abstract is pretty detailed on what the talk is going to be about, but I've still got some elbow room on how to "implement" the talk. I will use this blog as a tool to get my aim right on how to present the talk, what examples to include, what the slides should look like, and how to make it most straightforward and understandable for the audience. Now in lack of having done any presentations at a larger conference before, I'm gonna dig into what I learned at the University, which wasn't very much, but they did teach me how to write a research paper, a skill which I will adapt into creating my talk: The one

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 o