Skip to content

Instantly share code, notes, and snippets.

@desandro
Created January 31, 2013 20:26
Show Gist options
  • Save desandro/4686136 to your computer and use it in GitHub Desktop.
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?
@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