Skip to content

Instantly share code, notes, and snippets.

@desandro
Created January 31, 2013 20:26
Star You must be signed in to star a gist
Save desandro/4686136 to your computer and use it in GitHub Desktop.
Can you help me understand the benefit of require.js?

I'm having trouble understanding the benefit of require.js. Can you help me out? I imagine other developers have a similar interest.

From Require.js - Why AMD:

The AMD format comes from wanting a module format that was better than today's "write a bunch of script tags with implicit dependencies that you have to manually order"

I don't quite understand why this methodology is so bad. The difficult part is that you have to manually order dependencies. But the benefit is that you don't have an additional layer of abstraction.


Here's my current JS development work flow.

Development

When in development-mode, all scripts have their own tag in the DOM.

<script src="depA1/dep1-for-module-A.js"></script>
<script src="dep2-for-module-A.js"></script>
<script src="moduleA/moduleA.js"></script>
<script src="dep1-for-module-B.js"></script>
<script src="module-B.js"></script>
<script src="moduleC/module-C.js"></script>
<script src="script.js"></script>

There is no abstraction layer. This allows me to better debug individual files. The browser reads separate files, so I can debug with Developer Tools. I like how it's straight-forward.

Dependencies are basically managed right here. depA1 needs to be listed before moduleA. It's explicit.

Modules

Modules are 'transported' by attaching to the global namespace.

( function( global ) {
  var dep1 = global.depA1;
  var dep2 = global.depA2;
  function ModuleA() {
    // ...
  }
  // export
  global.ModuleA = ModuleA;
})( this );

Production

All scripts are concatenated and minified. One HTTP request on load.

<script src="site-scripts.js"></script>

The Concat + minify task is maintained separately. It's part of a build process. Makefile or what-have-you. For dependency management, the ordering of scripts matches how they were listed in the HTML.

Changing modes

This can be done easily with some sort of configuration and templating. For example, by setting prod_env config variable to true or false, the site is either in production, serving the one file, or development mode, serving every single file.

{% if prod_env %}
  <script src="site-scripts.js"></script>
{% else %}
  <script src="dep1/dep1-for-module-A.js"></script>
  <script src="dep2-for-module-A.js"></script>
  <script src="moduleA/moduleA.js"></script>
  ...
{% endif %}

Discussion

  • What benefit does require.js provide over this workflow?
  • How does require.js address minimizing HTTP requests? Is this any better than concat/minifing all the scripts?
@guybedford
Copy link

@salient1 for CSS includes you can use a plugin like Require-CSS. There is also LESS support and it works with builds.

@thanpolas
Copy link

Hi all, I finished a proof of concept for a new way of dependency management. It's a working solution that allows discreet, unobtrusive and powerful dependency management. I'll quote from the README of Mantri.

Mantri is...

  • A Robust and discreet Dependency Management System.
  • Synchronous. Everything is done before DOMContentLoaded event triggers.
  • A Grunt plugin.
  • A command line tool (soon).
  • Cross-browser.

Mantri does not...

  • Dictate how you write your code. Vanilla JS, AMD, commonJS, knock yourselves out.
  • Need any runtime on your production file.
  • Need any dependency declarations in your production file.
  • Have any problem moving around JS files or folders.
  • Have any problem working with other dependency systems.
  • Polute your namespace. But you are free to if you want.

... I'll be going through documentation and a blog post announcing the tool in the near future and would welcome any early feedback you may have.

@thanpolas
Copy link

@kamov
Copy link

kamov commented Jun 15, 2013

Good reading... thanks to all.

In conclusion?

@crdesai
Copy link

crdesai commented Jun 26, 2013

Great reading!
I am interested in "changing modes" section in the original post. If we want to live debug in production environment if somethingis not working right, how can this be achieved using requireJS? Any ideas will be great.

@wyuenho
Copy link

wyuenho commented Jul 22, 2013

@TechplexEngineer
Copy link

Is this not a good candidate for a Stackoverflow question?

@masswerk
Copy link

Yet another issue with require.js and the like: The DOMContentLoaded-event fires as soon as all the originally embedded scripts have loaded and the original DOM of the document is present. Since injected files or scripts loaded via XHR are not included in this, they will not be present at this time. This results in breaking the load process and deferring the time the page is ready, effectively leading to longer page load and parsing times. Even more, the scripts will compete for network-slots with other embedded assets (images, fonts, etc), slowing them down yet again.

So JS is NOT where you should manage your dependencies, use build-tools or server-side includes to manage them.
Regarding page load times, attempting to handle dependancies via JS always comes at the expense of your users and the general performance of your site. Especially, if the actual page is to be rendered via JS, resulting effectively in a second load cycle for the assets inlined by the generated code. Using some partials loaded via XHR would result in a third cycle and so on.

(Remember late 1990s, how fast the web used to be then?)

@jasonmcaffee
Copy link

@masswerk - I think you should try to work more with require.js. Your statements are a bit flawed.
With require, your main/app module waits for dependencies to load before doing any work, so the Dom content loaded event isn't an issue (usually I put my dom ready event registry inside my main module)

Usually this isn't an issue when in production, as require.js is a build tool, and will concat your js into 1 file. (usually you'll end up with multiple xhr script loading only when in development).

The asynchronous loading aspect is beneficial when you have a really large site, and want to load features/packages only when needed. E.g. I have a labs site, which is a SPA and has a webgl demo link. I don't include Threejs in my minified js, as I only want to load it when someone clicks on my webgl demo link.

Take a look at the optimization documentation:
http://requirejs.org/docs/optimization.html

@masswerk
Copy link

@jasonmcaffee - Hm, I've seen some require.js in production using still JS-managed dependencies. On the other hand, using a completely other load-cycle-model in testing than in production isn't the best either. (Who is bothering about this anymore at all? E.g.: Developers have eventually become used to jQuery and $(document).ready in such extent that they even don't know that they could have loaded their data already in the head section and could have all things calculated and ready for some time even before the event fires. And using tools like require.js keeps you even more from considering these things, as they're triggering late while in the development phase.)
Fact is, we're all using computers that are beasts, only the NSA would have access to just some 20 years ago, and are using the best optimized software that ever existed (JS engines). And using this, there are just too many projects, where you can watch pages rendering like it were the mid 1990s.


Here's a model to speed up web apps:

  1. Include a source-tag to the data-set server-side
  2. Use something like Plexer.js ( http://www.masswerk.at/plexer ) to spawn your model-logic to a concurrent process
  3. Have your model ready at DOMContentLoaded
  4. Have more tiny scripts (they will be cached and will be available instantaneously) and not a single, compiled one for every page-type (so the browser will have to load any additional bits only)

@livingeek
Copy link

A little off topic, but an interesting project I've been using, is jam.js. Been loving it for managing JS libraries and packaging them to be used. Uses the Require framework, but adds some functionality to it. Figured some people on here may find it interesting.

@bradw2k
Copy link

bradw2k commented Aug 22, 2013

Most medium-sized web apps (which is what most of us are building, right?!) do not need the syntactic vomit that RequireJS sprays all over the project. It is not hard to get even several dozen <script> tags in the right order. It. Is. Not. But it is at least as difficult to maintain RequireJS config files and the require() and define() statements. I have seen devs spending hours pairing to figure out their RequireJS config files.

Furthermore, many web apps will simply not benefit from lazy loading, because they will require loading almost everything at a certain choke point -- such as immediately after user login. If you can determine a clear choke point like this, it should be straight forward to configure the script bundling accordingly. Or maybe all of your custom scripts minify to 50K -- in which case you are insane to try to optimize performance by breaking that apart. Now, of course there will be apps where lazy loading will be beneficial. But I think they will be a small minority, based on the medium-sized business apps I have worked on.

Bottom line is that good devs will actually figure out whether or not it makes sense to use RequireJS on a project -- because it is not free. It complicates your ECMAScript5 code, despite what the sycophants say. People who spout that RequireJS should be used as a rule are either sheeple or self-congratulating hipster "experts."

@david-mark
Copy link

There is no benefit:

https://gist.github.com/cinsoft/2845842

...only liabilities (and lies). ;)

@albanx
Copy link

albanx commented Sep 30, 2014

Great discussion. I am very interested in understanding the benefits of requirejs. Still after reading this discussion I cannot understand the benefits (for serious web developers).

For example someone says "With RequireJS ... don't have to worry about keeping track of dependencies or load order". Normally I use to develop with objects in JS so in my JS I can load:

<script src="object1.js"></script>
<script src="object3.js"></script>
<script src="someframework(jquery).js"></script>
<script src="object2.js"></script>

The order does not matter, if objects does not depend from each other.
But if objects will depend (object3 extends object2 that extends object1) from each other then I should load them in order, so I can just do:

<script src="object1.js"></script>
<script src="object2.js"></script>
<script src="object3.js"></script>
<script src="someframework(jquery).js"></script>

And that is fine, because so I know the entire flow of my app ( If I am the developer I should know how my app works, right?!!, because I am not the developer then I would not know the dependecies)

@danicomas
Copy link

@albanx in requirejs you have the control too. Exists the dependiencies of the libraries. Look at this: http://requirejs.org/docs/api.html#config shim and deps block.

RequireJS is a way to have the code organized and it avoids to use libraries without previous dependency.

@samvdb
Copy link

samvdb commented Jun 5, 2015

After using RequireJS in several larger projects i would advise AGAINST the use of requirejs. The promise of automatic dependency handling sounds like music in your ears but you will encounter so many problems when actually using it. From async loading problems, shim configurations / config hacks to make a library work to just plain frustration. It simply is the worst opensource project in existence and i would rather use internet explorer 5 for the rest of my life than requirejs.
Do yourself a favor and don't touch it. It adds so many levels of complexity to your project that might already be complex enough. Write plain javascript files and use a taskrunner like grunt to concat / minify the libraries. /endrant

@MichelBartz
Copy link

@samvdb Similar experience here.

RequireJS is a prime example of the hell that front-end development has become, it is now harder to develop a JavaScript application than building a thousand file C project. I've worked with many languages and for the past few years JavaScript and its environment have been the constant outlier when it comes to nonsensical libraries and tools that get in the way and make simple work a nightmare for the developer who does not know all the ins and out of the library currently in favour, a library that is often poorly documented and not developer friendly.

We should heavily encourage developers to stay away from such libraries as they promote coding practice that are nefarious, not adapted to JavaScript, encourages laziness and poor knowledge of your own code base.

@gnulnx
Copy link

gnulnx commented Jan 6, 2016

Joined a medium size team on a medium sized project using requirejs. Total nightmare. It's like all my prior experience of web programming (15 years) on the front end has been tossed aside. I have require modules not properly loading similar to the second comments in this thread: http://stackoverflow.com/questions/10959095/intermittent-requirejs-load-error. Oh sure when it works it just works...but then so do script tags...and once they are ordered they stay ordered. Plus modern web frameworks like django let you compartmentalize functionality into templates.

And while I'll admit that this project likely isn't using requirejs properly I also haven't seen anything that makes me even remotely believe it's worth using. Personally I would never in a million years introduce requirejs into a project. There are so many other traditional way's to handle these issues that it just doesn't make sense.

Software engineers really should know how code works and not try to abstract away every last detail.

@philer
Copy link

philer commented Jan 14, 2016

This thread made me think about my current practice and helped me decide to continue not using require.js.

I don't think require.js is bad. To me it seems more like a habit. You can use require.js to manage your dependencies or you can use something else or you can do it yourself. Doesn't seem to cause much issues either way.

If, and only if, your client side application actually consists of more than several dozen individual js files then automated dependency management will certainly have its benefits. On one project we currently have around 40 modules (some of them global, some only used on specific pages) and some of the meta modules are only supposed to be loaded (i.e. their factory function executed) when they are actually needed. For that purpose I wrote our own dependency manager which has less than 50 lines of js.

In order to get all the dependencies to the client we use grunt to uglify all the modules into one monolithic file. For development the files are simply concatenated without uglifying. The Gruntfile is the only place where all the modules are listed and it is pretty easy to figure out in which order they belong (core / meta modules first, page-specific modules at the end). Even if we wanted to include the source files individually we could do that relatively simply by extracting the module list into a json file and including them via our server side template engine.

Now this is only my setup for a bigger project. Obviously there are even larger projects out there, but considering how easy it was to set up our own dependency management, which is tailored to our particular needs, I doubt that an even larger project couldn't handle that.

However I have a lot of much smaller (client side) projects where I only need anywhere between 3 and maybe 20 js files. I assume that most projects on the web are of this scale, even though they don't like to admit this. After all, if your client side actually uses hundreds of non-trivial modules chances are your site will become slow as f*ck. For projects like that I hardly think your dependency graph will reach any significant complexity. Just create a single global object as your application's namespace (I usually give it a project-specific name to avoid collision with generic names like app). Wrap all your modules into an IIFE and inject the modules into your namespace. Looks like this:

main.js:

(function(global) {
  "use strict";
  global.my_app = {
    // some useful shortcuts
    $win: jQuery(global),
  };
})(window || this);

SomeModule.js

(function(app) {
  "use strict";
  var mod = app.SomeModule = {
    // ...
  };
})(my_app);

You can also do the class-like approach like this:

SomeClass.js

(function(app) {
  "use strict";
  var SomeClass = app.SomeClass = {
    // ...
  };
  SomeClass.prototype = Object.create(app.ParentClass, {
    // properties
  };
})(my_app);

I've done a fair few projects like this and I've never run into any issues.

@WinfieldHill
Copy link

A few years have passed since this was started, so there are far more options now. However I wanted to share how RequireJS is still an excellent tool for medium'ish (maybe large to some people) sized projects.

We use RequireJS on a daily basis in an e-comm project (similar to ATG) and I love it. Was the initial config a little tricky? Yes but after that it's been excellent. That tricky part is in reference to our need to create a modified version of the multi-page with shim support pattern to make it fit our needs - the original pattern didn't work due to our existing codebase/file structure. For an idea of the project complexity front and back: the project has north of 600 JS files (there are the usual inline scripts as well that aren't counted) and north of 3,000 class files (src).

Using RequireJS in the way we've implemented it has allowed us to progressively modularize the application, which was only realistic option. To say it's flexible would be an accurate statement as it's currently supporting 2 modes of operation in production - dist and src (which we can toggle for debugging). We run r.js using clojure compiler and node uglify2, since both were necessary to allow teams without node to compile the project (they just need to wait a minute or 2 😄 ). We're also in the early stages of a service based approach for our client-side assets that are tied to RequireJS i.e. imagine a 3rd party that specializes in writing the front-end code for your site and delivering it via Akamai/Verizon/some CDN. Network throttling tests over the HTTP and HTTPS schemes has gone smoothly (scaled back to dial up speeds) and we've added transpiling into the mix so we can stay current (maps provided via Babel 6).

In summary, RequireJS is the exit point for most of the platform JS in a hybrid (2-3 mincat'd scripts in dist) and modular (src) distribution, and it's doing what it was designed to do flawlessly.

@PabloVallejo
Copy link

I totally agree with what @philer stated, I've use the same setup in several projects with 20 to 30 js dependencies and haven't run into any issues. Not to say that RequireJs isn't a great library.

@Sean-Bradley
Copy link

require.js is a dependency to manage your dependencies.

@danielsokolowski
Copy link

danielsokolowski commented Oct 10, 2016

require.js is layer that is not needed, it tries to solve a problem than one can explicitly resolve using <script> tags. It stems from the lack of recognition that on the frontend JS is a second class citizen - the author of the question is right to ask the 'why' and should stick to what is simpler to them.

There is of course positive though, it and other projects like it have served their purpose. They highlight that there is a desire (not to be confused with need) for JS module loading on the front end and browser community has listened; I invite the reader to google 'ECMAScript 6 modules'

@nezarat
Copy link

nezarat commented Dec 9, 2016

Yes I'm agree with questioner. Why we should learn a lot of framework's syntax and usages while we can do it easily and purely with java-script itself and JQuery! require, backbone, underscore, ..... and thousands of frameworks!!! if you are a developer you can think and use your mind :) such a problems are really easy to solve, browsers guaranteed loading scripts and css files in order of their declaration! load libraries like jquery at first and then your custom scripts ... even you can load see below:

$.getScript( "ajax/test.js" )
.done(function( script, textStatus ) {
console.log( textStatus );
})
.fail(function( jqxhr, settings, exception ) {
$( "div.log" ).text( "Triggered ajaxError handler." );
});

don't fill your mind with unnecessary things!!!

@pvanroos
Copy link

I read each and every post above from 2013 to now. The general trend I'm noting as time progresses is to avoid using requirejs. Is that fair approximation?

@gertcuykens
Copy link

A fair approximation would be that modules have been a problem for a decade and we only have es6 module solution on paper... If you are loading modules asynchronously you still going to need requirejs. But with a typescript compiler its pretty transparent and the compiler takes care of the boilerplate code and sourcemaps. My only complaint about requirejs is that its 26KB minified.

To browser vendors not implementing es6 modules, **** ***

@onigetoc
Copy link

onigetoc commented Dec 4, 2017

What i see it sometime and often, one person develope a small app and use require without knowing why is using it. Just because everyone do it.

@gramacyan
Copy link

My biggest concern about requirejs/AMD and the well-known (distributed) libraries is that they assume the AMD implementation knows how to identify the module. This by using a path/url as identifier.

For example:

/vendor/DistributedLib.js

define([], function(){  
   return {
      use: function() {}
   };  
});

main.js

define(['/vendor/DistributedLib'], function(lib){  
   lib.use();  
});

That's all fine and dandy, but what happens if we concatenate the files:

define([], function(){  
   return {
      use: function() {}
   };  
});
define(['/vendor/DistributedLib'], function(lib){  
   lib.use();  
});

Our dependency suddenly lost it's id! This piece of code no longer works.

The AMD specification allows setting an id as first parameter but I notice no one sets it in their distributed libraries. Most developers assume that if define && define.amd exists we are using requirejs / path-identifiers. IMHO the id should always be set unless it is an anonymous module:

define('DistributedLib', [], function(){  
   return {
      use: function() {}
   };  
});
define(['DistributedLib'], function(lib){  
   lib.use();  
});

Some time ago I created an AMD implementation (smd.js) since I didn't want file-loading. I was pretty baffled to find out that however I followed the spec, 99% of the libraries out there are not compatible. This because of the anonymous declarations.

Maybe I'm totally wrong here (and not seeing the bigger picture), but it seems to me the AMD pattern is not being used properly (unless you are using requirejs-like systems)?

@Skura23
Copy link

Skura23 commented Jul 12, 2019

Hey guys, can we use es6 module as a replacement of require.js in 2019?

@JamesTheHacker
Copy link

No, because the browser doesn't understand ES6 imports like node does.

To the nay sayers ... RequireJS is used in Magento2. A large project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment