Bower vs Nexus

When learning something new the fastest way is often to compare it to something similar that you already know well. If you are familiar with either the dependency distribution system common in most JVM based systems, Nexus, or the front end JavaScript system bower, the other system should hopefully be a bit more familiar to you after you have read this post.

Both Bower and Nexus has the same common goal. To provide a distribution channel for prepared artifacts. However they go about the task in quite different ways.  The simplest way of explaining the differences between the two systems is to compare the two primary operations which they both share; retrieving artifacts and publishing artifacts.

NexusRetrieval

BowerRetieval

As you can see the nexus retrieval mechanism is straight forwards, only involving the nexus server and the client. In the case of bower three parts are involved in the transaction: the client, the bower registry and a git repository containing the artifact. This is the key in understanding the bower system. A bower registry simply acts as a map between an artifact id and the git repository which contains all versions of the artifact. The bower registry does not contain the version information, that is maintained as git tags in the git repository. This becomes apparent if we compare the publishing procedures:

NexusPublish

BowerPublish

The two systems are achieving the same goal, but through very different methods. Nexus is a fully fledged file repository; while bower is little more than a git repository registry and some git commands bundled into a client.

In practice this means that the bower system is much more lightweight than nexus and other centralized distribution systems, such as npm. The Bower registry does none of the heavy file transfer or storage. Instead it completely relies on the Git repositories for its distribution. But this requires that the Git repositories are publicly available without access control (or at least available to everyone which has access to the registry). It also means that the artifact intended for distribution is stored with the source code. One last thing to note is that in contrast to many other JavaScript distribution system bower is fully capable of handling both HTML and CSS, a well as JavaScript.

Hopefully the comparison of Nexus and Bower have shed some light on the the unfamiliar system!

Further reading:

http://chariotsolutions.com/blog/post/javascript-apps-bower-or-not-bower/

Web Workers in Angular

Web Workers in Angular is simple in theory, but it requires a bit of tinkering to get them to feel like a part of the application. This post intends to explain a method which can make Web Workers in Angular (almost) seamless.

With the introduction of web workers web developers finally had the ability to allow long running, CPU intensive operations in the browser. These types of operations would otherwise have caused the GUI thread (the only thread up until this point) to block, and the GUI to freeze.

However the web worker syntax specification is a bit awkward, especially when combined with angularjs. To maintain complete backward compatibility and to protect developers from common parallel programming pitfalls the workers have a VERY limited exchange of information with the main browser thread. The main and web worker thread only communicate through message passing. All messages between the two are deep cloned (transferable objects can be used to minimize the overhead associated with the cloning). All this is well and good, it protects us from ourselves. But it makes for awkward programming.

Keeping the main and the web worker threads completely separated mean that resources loaded in the main thread is not loaded in the web worker thread automatically. In an angular application it means that if an angular app is using a web worker, the angular context is not automatically accessible in the web worker. If we do not load angular explicitly in the web worker it will only be capable of standard javascript. Whats worse is that a web workers needs to be loaded from a URL! What this normally means is that the developer specifies the javascript file that contains the web worker code like this:

var worker = new Worker('worker.js')

By using an addition to the web specification, which allows us to create object URL’s, we can get around the requirement of loading the web workers from separate files. This addition to the standard allows us to generate URL’s for snippets if blobs. Blobs can be pretty much anything, but we are interested in text that can be executed as javascript. A good explanation of this technique can be found here.

var blobURL = URL.createObjectURL(new Blob([
    "var i = 0;//web worker body"
    ], { type: 'application/javascript' }));
var worker = new Worker(blobURL);

We can not, and do not want to, get around the fact that the main and worker threads have separate contexts. But we can mitigate this inconvenience by this by leveraging the powerful dependency injection framework that angular ships with.

I have created an attempt at this here: https://github.com/FredrikSandell/angular-workers. angular-workers provide an angular service which takes a list containing dependencies, a function and returns a web worker, called AngularWorker, based on the functions source. The process is visualized in the sequence diagram below.

AngularWorkerCreation

Once the promise of an AngularWorker has been resolved the application is able to repeatedly use the initialized AngularWorker for heavy duty work. The angular worker communicates the result to the main thread through an angular promise. Within the web worker function we are ensured that an angular context exists and that the dependencies which we specified at initialization are present.

AngularWorkerExecution

A potential use case for this is to perform CPU intensive processing of large AJAX responses without locking the main GUI thread. This is the problem which first made me investigate this issue. The angular services which are used in the web worker can be handled as any other service and can therefore be tested as any other part of the angular application!