ponyfoo.com

The Web Wars

Fix
A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

There have always been wars in browser-land. Browsers, specs, politics, lots of politics. Even libraries had theirs.

What once was the browser utility library war, has now been settled, jQuery won that. We are now in the midst of another one, the framework war, with AngularJS leading the competition. There are lots to pick from though, and it isn’t anywhere near settled. Popular frameworks include BackboneJS, EmberJS, SproutCore, KnockoutJS, just to name a few.

Before Node, and frameworks like Angular, it wasn’t all that common opening a web project and finding front-end code organized in a way that scaled. This war will probably drag on for at least a couple more years. Maybe even indefinitely.

As we can see on TodoMVC, there are a boatload of different MV* frameworks out there. I expect that many of those won’t make it very far, while a few will gain more traction.

I’ll also be covering CommonJS vs RequireJS vs LazyJS, an alternative I developed.

angularjs.png
angularjs.png

I believe AngularJS has a good chance of winning. It’s a great combination of MV* patterns, great modularization. It’s debatable whether IoC will captivate developers at large, but they certainly implemented it in a clean and coherent way. Their solution is highly extensible, higly comprehensive, and, considering its extensive feature-set, extremely intuitive and easy to use. So, kudos Google!

However, it won’t enjoy the widespread adoption that jQuery has. jQuery is, ultimately, a utility library that’s meant to be auxiliary to your application, AngularJS is an integral solution, and it restricts how you can organize your front end architecture.

Lets get into RequireJS, a script loader that resembles the AngularJS dependency injection mechanism.

A little background history

There was a time when Node was coming up, when they had to decide on a spec to organize the complex code architecture that comes with a web application’s back end. The CommonJS Modules/1.1 spec was conceived. But it didn’t quite work in browser-land.

It wasn’t that long ago CommonJS and RequireJS took sides in a little skirmish. Fortunately, that’s more or less settled. To be fair, I created LazyJS in hopes to reignite that argument. I’ll expand on that later.

CommonJS Modules/1.1

Modules, as defined by the CommonJS spec, the so-called Node way, are directly related to the files that contain them, and can be included using require. A module will contain all properties published in the public interface defined in module.exports.

// util.js

module.exports = {
	public_api: true,
	log_message: function(message){
		console.log(message);
	}
};

// main.js

var util = require('./util.js');
expect(util.public_api).toBeTruthy();
util.log_message('foo');

// > foo

This pattern is very good for Node.

  • Everything that’s not exposed with module.exports is considered private to the module
  • Modules are interpreted once, and their results are stored for subsequent calls to require
  • It’s similar to what we see in other, non-prototypal, server side languages
  • Modules just execute and return a value. You are not tied to a particular pattern

RequireJS

requirejs.jpg
requirejs.jpg

AMD is a concession to the fact that browsers are just terminals and, unlike Node, assets are fetched over the network. This introduces a host of problems, such as latency, uncertainty (that the file will ever load), asynchronicity, and such.

AMD attempts to correct these issues by providing an asynchronous module loading pattern.

define('module', function(dep1, dep2){
	return function(){};
});

Benefits of using RequireJS include the following.

  • Modular code that isn’t limited to one module per file, like CommonJS modules are
  • AMD modules work even if they aren’t resolved immediatly, due to dependencies such a script in an external CDN
  • DI pattern. Dependencies are inferred from the arguments, resolved, and injected to the module function, all of which is done by RequireJS

Behind enemy lines

If you are like me, you don’t care about the politics behind different specs and solutions. All that matters is getting a clean solution that just works.

It’s a fact that CommonJS was not aimed at the browser, and although I prefer it for Node, I wouldn’t try and force it into browser-land. However, RequireJS attempts to do too much when it comes to the browser, and kind of fails at it.

You need a lot of boilerplate code in order to get AMD working, and it shouldn’t have to be that way.

RequireJS set out to be a simple and easy to use script loading solution, but that’s not quite what you find here.

RequireJS allows modules on the Object level, but I’m not so hot on the idea that my script loader should also take on the task of providing inversion of control and dependency injection mechanisms

Besides that, there are some unwanted complications. The example above won’t work when the JS is minified, because the arguments on the anonymous function will get renamed to something like a, b, meaning they won’t be able to infer the names of the modules anymore. The solution, is even more verbose.

define('module', ['dep1', 'dep2'], function(dep1, dep2){
	return function(){};
});

This leaves you wondering why they try so hard to provide something that just won’t work in production environments. And why does everyone have to modify their code to comply with yours? That’s just not right.

How is LazyJS any different?

  • Modules don’t need to adhere to silly conventions, you can you require them providing the /path/to/the/source.js
  • Faster, very little JS is parsed on page load, after that, necessary JS is parsed on demand
  • Less tightly coupled. Directives are comments that don’t define the way you should style your code
  • Less ceremony. Use the same tools and concepts in development and production
  • Succint. Give it a hint of which modules you depend on, that’s it
  • KISS

LazyJS is different in that it can become whatever you want it to be. It’s different in that it lets you organize blocks of code (entire files or chunks), and specify their dependencies.

For now it doesn’t even have an API, it’s just an idea. And I want to spend some time figuring out the best “out of the box” feature-set, without staining everyone’s code with extra code.

Suppose you want it to “become” CJS, then you should reference a bundle, disable AJAX calls, and let it resolve everything on its own before, synchronously, giving you a result back.

Similarly, you can leave it pretty much on its current state, expose the .lookup(url, done) function, and voilá, you’ve got RequireJS. Sort of.

Feedback regarding LazyJS is welcome, and I promise to try my best to leave it as agnostic and unopinionated as possible.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments