AlexCode
AlexCode

Reputation: 4123

Javascript namespacing with RequireJS, why?

I'm currently facing this argument about namespaces on javascript and I need a community opinion.

The scenario: The architect in charge of this project somehow is devoted to RequireJS and really wants to use it.

I must say that the application is a backoffice, layed out as a wizard, so you kind of go back and forth on 6 pages with some complex business logic to at the end fill something that here I can described as a process request.

Ok, no single page application no nothing fancy on those matters. Plain backoffice web app, multi-page, with a very complex UI where every page is requested to the server and all resources (css, javascript and such) must be loaded at page load.

Main question: Knowing the kind of app we're talking about, why RequireJS in the first place?

Second question: Why try to convince that the best approach for namespacing in javacript is by using RequireJS? Am I missing something?

My opinion: For me it makes no sense at all. It's cumbersome to use RequireJS here because no resource is loaded on demand, they are all loaded at page load (just because we need them all at page load). We need to support at least IE8, Chrome, Firefox and Opera and we already had a lot of trouble with the resource loading across all these browsers. There is already a lot of trickery to make sure everything loads as expected through Require.

For namespacing it's even worse. Sure it works but again, seems cumbersome to me and on this matter is actually very limited.

So am I missing something? I need a third (or a 100th) opinion here.

Thanks in advance

Upvotes: 6

Views: 2345

Answers (4)

AlexCode
AlexCode

Reputation: 4123

My current solution to prevent poluting the global environment and name clashes is by using $.extend.

File System tree looks something like the following:

RootFolder
  +-> js
  global.js
  ...
   +-> views
       index.js
       page1.js
       page2.js
       ...
index.html
page1.html
page2.html

So it's usually one global.js file with all application shared code and another specific per page.

For namespacing I like $.extend so on each js file I have something like:

var app = app || {};  

/* only one document ready block per view if needed */
$(document).ready(function(){
    /* initialization code */
});

/* extend the app namespace with the Page1 code */
$.extend(app, {
    page1: {
        SayHi: function SayHi(name){
            alert('Hi ' + name);
        }
    }
});

So you can access your code by calling:

app.page1.SayHi("Alex");

With this technique you:

  • Have full control of your code. No magical resource loading and fancy stuff that you don't have full control of.
  • No global environment pollution
  • No naming conflicts
  • The namespace tree can be as deep as you wish, you're the owner of your own complexity.
  • You can have several js files that actually contribute to the same namespace level. This is particularly useful on helper tools.
  • Depending on the javascript files you include on the page you can have a bigger or smaller app namespace.

Conclusion:

The Web environment the really easy, we shouldn't complicate it.

I'm not hitting on RequireJS, don't get me wrong. It does what it was meant for (on its essence is pure resource lazy loading). Everything else is stuff that also comes with the package but that are also doable in a cleaner and transparent way.

So if I don't need the main feature there's no point on using it.

Cheers!

Upvotes: 0

Daff
Daff

Reputation: 44215

No matter if it is a "single page app" or not, RequireJS helps with two things that are not easy without a lot of developer discipline on its own when developing client side JavaScript:

Production vs. Development environment

It is common sense by now to split your JavaScript applications into files that logically resemble different parts of your application. It is easier to debug and maintain. In production however, shipping many uncompressed files is bad for performance. So you concatenate all your files into a single file, minify it (e.g. using the Google closure compiler) and then ship it as a single gzipped file. There are many different ways to do this using command line tools (e.g. using GruntJS) but without a script loader like RequireJS you somehow have to set your page up for two different use cases (reference all your dev files as script tags or the single production.js) yourself. RequireJS has a NodeJS build tool that does all this for you.

Modularization

Now keeping your code in separate files is all good. But due to the nature of JavaScript and everything being global means that you can still run into weird things like name clashes. This is where namespacing comes in handy. But the even better alternative is to wrap everything into its own function (which introduces its own scope). This is why most JavaScript code comes in a self-executing anonymous function. If this function now returns an API it wants to expose you have web modules. You can test your modules API separately from your application and re-use it in other places.

Also read up in the Why Web Modules section from the RequireJS docs.

Upvotes: 3

micha
micha

Reputation: 49612

In my personal opinion the use of a javascript module system is almost never a bad idea. Requirejs is also not the only possible loader for javascript modules (but maybe the most popular one). Some alternatives are LABjs or HeadJS.

Those loaders are often easy to use (not much trouble at the start) but can help a lot when the project is becoming bigger and bigger. They avoid naming conflicts in global space and can also support you in the deployment step by minimizing/optimizing your modules. The most important fact is that they allow you to write more modular javascript code.

  • You have some utility functions? just create a utility module.
  • You have some functions you need on all pages? put them in a common module.
  • Some pages require a lot of specific javascript code? Create an extra module for those pages so you don't have to load this code on other pages.

Upvotes: 2

Lucero
Lucero

Reputation: 60276

AMD loaders (RequireJS is one) address different issues:

  • Proper modularization, separation of concerns
  • No global pollution
  • No name clashes
  • On-demand loading, or pre-deployment optimization
  • Depending on the loader, plugins for adressing advanced issues such as localized resources or load-time compilation

I'm a big fan of such loaders and find them useful for everything but very small single-page apps.

Upvotes: 4

Related Questions