Require.js is hurting my brain. Some fundamental questions about how it loads scripts / modules

Suppose these are my config.js or main.js:

require.config({ // paths are analogous to old-school <script> tags, in order to reference js scripts paths: { jquery: "libs/jquery-1.7.2.min", underscore: "libs/underscore-min", backbone: "libs/backbone-min", jquerymobile: "libs/jquery.mobile-1.1.0.min", jquerymobilerouter: "libs/jquery.mobile.router.min" }, // configure dependencies and export value aliases for old-school js scripts shim: { jquery: ["require"], underscore: { deps: ["jquery"], exports: "_" }, backbone: { deps: ["underscore", "jquery"], exports: "Backbone" }, jquerymobilerouter: ["jquery", "backbone", "underscore"], jquerymobile: ["jquery", "jquerymobilerouter", "backbone", "underscore"] } }); require(["jquery", "backbone", "underscore", "app/app.min", "jquerymobilerouter", "jquerymobile"], function ($, Backbone, _, App) { console.log($); console.log(Backbone); console.log(_); $("body").fadeIn(function () { App.init(); }); }); 
  • If I understand correctly, the paths config parameter allows you to reference scripts, a-la <script> in HTML. Assuming this is the case, do I still need alias scripts like jQuery with $ or underscore with _ in my actual requirement below? It seems strange that I would have to, given that if you reference jQuery with the standard <script> , $ can be used in all your scripts automatically. Shouldn't it be the same with paths ?

  • I am new to the shim config option, which, as I understand it, has replaced the deprecated order! plugin order! . What does the exports property actually do? It does not seem to create an alias for the script; for example, if I set exports to underline to "whatever" and then try console.log(whatever) , it is undefined. So what is the point?

  • How can jQuery scripts be used "globally?" That is, how can I use the $ alias in my App.js module or any other module in my application folder? Should I require jQuery in every single module and an alias of $ every time? Or so did I do it here properly?

I would really appreciate any other criticism of this particular script; the documentation for Require.js, in my opinion, is poor; the things that I really would like to know more about seem to get clouded and leave me scratching my head.

+44
javascript jquery module requirejs
Jun 14 2018-12-12T00:
source share
2 answers
  • The paths say require.js where to look when you need this dependency.

    For example, I have settings like this:

     "paths": { "jquery": "require_jquery" }, "shim": { "jquery-cookie" : ["jquery"], "bootstrap-tab" : ["jquery"], "bootstrap-modal": ["jquery"], "bootstrap-alert": ["jquery"] }, 

    this means that every time in the module i do

     define( ['jquery'] 

    requirejs loads the require_jquery file from the main path, rather than trying to load jquery.js. In your case, it will download the jQuery source file, which will then be available worldwide. I personally do not like this approach, and for this reason in the require_jquery.js file I do:

     define( ["jquery_1.7.2"], function() { // Raw jQuery does not return anything, so return it explicitly here. return jQuery.noConflict( true ); } ); 

    which means jQuery will only be defined inside my modules. (This is because I am writing Wordpress plugins, and therefore I can enable my own version of jQuery without touching the external version).

  • Export (reading from documents simply should be the name of the module you are using, so that it can be detected if the load is correct. Here . Therefore, if you want to set the export to underline, it should be _

  • jQuery should be global, as I explained, if you just import it, the file is executed and jQuery is global

EDIT - reply to comments.

  • yes, I mean this, you must export $ or jQuery for jQuery and _ for the backbone. From what I got from the documents, this is necessary only in some cases with edges and will not be needed for libraries that declare themselves in the global namespace as jQuery.

    I think requirejs needs them when it has to refuse to load jQuery from the CDN. I think that requirejs first tries to load jQuery from the CDN, and then does a check to make sure it was loaded correctly, checking that there is an "exported" variable, and if it does not load it, it forms a local file system (unless of course you , configured rollbacks). This is what was needed when requirejs cannot see the 404 return.

  • jQuery is available globally as it is declared global. If you just download and run the jQuery script, you will get two global characters, $ and jQuery (or you can do what I did and avoid it). Inside the define() function, you can alias jQuery to be what you want.

     define( [ 'jquery' ], function( jq ) { // jq is jquery inside this function. if you declared it // globally it will be also available as $ and jQuery } ); 
+22
Jun 14 2018-12-12T00:
source share

Just to clear up any confusion around exports , he suggested that any shim library would attach a property to the global context ( window or root ) or modify an existing global property (like the jQuery plugin). When requireJS receives a command to load the dependent dependency, it parses the global context for the property corresponding to the exports value of this shim configuration, and if it finds it, returns it as the value of this module. If it does not find it, it loads the associated script, waits for its execution, then finds the global character and returns it.

It is important to remember that if the shim configuration does not contain the value exports , any init method in this config will NOT be executed. The dependency loader must find the value for the module (this is what exports says) before this module can be initialized, so a property is required if there is an init strip for this module.

: I also need to indicate that if the module in question calls define anywhere, any shim configuration you have for this module will be ignored. This actually caused me some headaches because I wanted to use the shim configuration to call the jQuery jQuery.noConflict(true) method for un-globify jQuery and keep it in the scope only for modules that require it, but couldn't force its work. (See the Update below for information on how to easily do this using a map configuration instead of a shim configuration.)

update 2: a recent question about google group requireJS made me realize that my explanation might be a little misleading, so I would like to clarify. A JS request will reuse the encrypted dependency if it has been downloaded via requireJS at least once. That is, if you just use the <script> on the hosting page (e.g. underline), for example:

 <script src='lib/underscore.js'></script> <script src='lib/require.js' data-main='main.js'></script> 

... and you have something similar in your requireJS configuration:

 paths: { 'underscore': 'lib/underscore' }, shim: { 'underscore': { exports: '_' } } 

Then the first time you execute define(['underscore'], function (_) {}); or var _ = require('underscore'); RequireJS will reload the underscore library, rather than reuse the previously defined window._ , because as far as requireJS knows, you never loaded the underscore before. Of course, he can check if _ defined in the root area, but he has no way to check that _ already has the one specified in the paths configuration. For example, both prototype and jquery are assigned window.$ By default, and if requireJS assumes that "window. $" Is jQuery, when it is actually a prototype, you will end up in poor condition.

All this means that if you mix and match script loading styles, for example, your page will end up like this:

  <script src='lib/underscore.js'></script> <script src='lib/require.js' data-main='main.js'></script> <script src='lib/underscore.js'></script> 

Where the second instance of the underscore is the one loaded by requireJS.

Basically, a library should be loaded via requireJS so that requireJS knows about it. However, the next time you need to emphasize, requireJS will go "hey, I already loaded this, so just cancel all exports and don't worry about loading another script."

This means that you have two real options. One of them is what I consider an anti-pattern: just don't use requireJS to express dependencies for global scripts. That is, as long as the library attaches the global root context, you can access it if this dependency is not explicitly required. You can understand why this is an anti-pattern - you basically just excluded most of the benefits of using the AMD loader (explicit dependency list and portability).

Another, better option is to use requireJS to load everything, to the extent that the only actual script tag you have to create yourself is the one that originally requires requireJS. You can use gaskets, but in 95% of cases it is really not that difficult to add an AMD wrapper to the script. It may take a little more work to convert all your non-AMD libraries into AMD-compatible, but once you have done one or two, it becomes much easier - I can use any common jQuery plugin and convert it to an AMD module in less than a minute. Usually it's just a matter of adding

 define(['jquery'], function (jQuery) { 

above and

  return jQuery; }); 

at the bottom. The reason I have jquery matching with jquery rather than $ is because I noticed that most plugins these days are wrapped in closures like this:

 (function ($) { // plugin code here })(jQuery); 

And it is a good idea to pay attention to the estimated volume. You can, of course, match 'jquery' with $ directly, assuming the plugin does not expect to find jquery instead of $ . This is just the basic shell of AMD - the more complex ones, as a rule, try to determine what type of bootloader is used (commonJS vs AMD vs regular ol globals) and use a different boot method depending on the result. You can easily find examples of this with a few seconds on Google.

Update. The workaround I used to support using jQuery.noConflict(true) with RequireJS worked, but there was a very small modification to the jQuery source for it, and since then I realized that it is a much better way to do the same thing without changing jQuery. Fortunately, James Burke, the author of RequireJS, added it to the RequireJS documentation: http://requirejs.org/docs/jquery.html#noconflictmap

+22
Feb 26 '13 at 20:33
source share



All Articles