Javascript namespacing with RequireJS, why?
Asked Answered
E

4

6

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.

  • What do you think of this?
  • What do you use?
  • Why?

Thanks in advance

Eponymy answered 17/12, 2012 at 20:22 Comment(4)
Do you use using statements in C# ? This is the same thing.Alright
C# "Using" statements are not the same as AMD tools for JavaScript... at all.Eponymy
"Using" imports the types contained in a namespace into the immediately enclosing compilation unit or namespace body. "require" imports the specified module into the current script/module. Sounds pretty similar to me, but that's just my opinionAlright
AMD stands for Async Module Definition which is a lot more than the shortcutting and object namespace, which is all "using" in C# does.Eponymy
L
4

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.

Lowtension answered 17/12, 2012 at 20:42 Comment(3)
From that list I only actually link the last two to AMD loaders.Eponymy
Since ever I've been having separated files for each page so the concerns were well delimited but no namespaces. As applications stated to be heavier on the client-site I started encapsulating my code in domain functions to avoid poluting the global environment and also prevent name clashes. From my experience I know that RequireJS doesn't "just work". Compatability and stability across all browsers (specially old ones) is not straight-forward so why try to kill a fly with a bazooka?Eponymy
@Eponymy the absence of globals is fully part of the AMD concept: requirejs.org/docs/whyamd.htmlSalim
G
3

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.

Gustafsson answered 17/12, 2012 at 20:44 Comment(1)
Due the replies I posted an answer to my own question explaining the way I enforce namespacing and why. You actually have a really strong point on the environment dependent configurations. Thanks!Eponymy
D
2

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.
Dimissory answered 17/12, 2012 at 20:44 Comment(1)
I kind of commented your points on my answer. Basically I fully agree with you, I just don't like the overhead and loss of control to achieve something that can actually be quite simple and transparent.Eponymy
E
0

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!

Eponymy answered 18/12, 2012 at 9:7 Comment(2)
Defining your javascript in modules is a recommended best practice. I don't believe any 1 framework solves all problems, but react is a great solution that offers backwards compatibility to browsers that don't support module loading. You went out of your way to avoid using something you didn't take the time to understand, and ended up with a much less desirable pattern. IF you insist on not using require, the least you can do is learn about immediately invoked function expressions, and how they can help you define namespaces in javascript safely.Alright
You're commenting on an almost 3y old post. Anyway, I admit this wasn't a good approach but it was more of a release under frustration :) I never implemented any of this and actually, a couple of months later we moved everything to AngularJS anyway and no more RequireJS. Anyway, all the decisions weren't made out of not understanding the tools, but precisely the opposite.Eponymy

© 2022 - 2024 — McMap. All rights reserved.