1

I am creating a wirejs app using requirejs. For IE 8 I am using polyfills: cujo/poly js library and require this lib be preloaded before wirejs is loaded.

If I used curl as the AMD loader, as per the documentation, I have following option available:

curl({ preloads: [ "poly" ] });

What works for me is:

// in index.html

<script data-main="js/app" src="js/lib/require.js"></script>

// in js/app.js

define(function(){
   // set configuration options
   requirejs.config({// set config with paths});

   // require the library and HOPE it will load before
   // everything else!
   require(['poly']);

});

This document recommends using shim config for this purpose. However, I haven't been able to figure out how. Some of the things I tried:

// DID NOT WORK!!
requirejs.config({

....
"shim": {
   "poly": {
     "exports": "poly"
    }
 }
});

Is there a better way to approach this?

Any help appreciated!...thanks for your time!

Vikram
  • 4,162
  • 8
  • 43
  • 65
  • I'm not sure why James removed support for ensuring that some modules get loaded first. If there is a way to use shim config to ensure that a global script loads first, then perhaps this github issue describing how to browserify poly.js may help: https://github.com/cujojs/poly/issues/28#issuecomment-29720704 – unscriptable Aug 22 '14 at 19:14

2 Answers2

5

I do use RequireJS together with polyfills, but I don't use RequireJS to load them. The goal of a polyfill is to make a browser which lacks feature X look as if it does in fact have feature X. I prefer a setup in which all the code I run (with the exception of the polyfills themselves) runs with the polyfills already loaded so that the code runs with the same set of features available to it, no matter what browser runs the code. So I want my polyfills loaded before RequireJS too.

But if we ignore this preference, could RequireJS be used to load the polyfills? Yes, but RequireJS won't make it easy. There's no trivial way to tell RequireJS "this body of code must be loaded before you load anything else", which is what you'd want for polyfills. What you'd have to do is manually invoke require so that your polyfills are loaded first. Your index.html could be something like:

<script>
    require = {
       // Your config.
       //
       // Setting a global require before loading RequireJS is one way to give it
       // a config.
    };
</script>
<script src="js/lib/require.js"></script>
<script>
    // No data-main above...
    //
    // This double require ensures that the polyfills are loaded first.
    require(["poly"], function () {
        require(["js/app"]);
    });
</script>

js/app.js becomes:

define(function(){
    // whatever...
});

In a large application where there may be multiple entry points other than js/app, you have to use the double require like above every time you want to load a module from outside a RequireJS module to ensure that the polyfills are loaded first.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Yes, this will work fine. Unfortunately, any setup requiring that polyfills be loaded first will be slower than embedding the polyfills into the app bundle. Fwiw, using multiple script tags with async="false" would be faster than using embedded require() calls such as you've shown since requirejs would have to finish loading poly before starting to load js/app. – unscriptable Aug 22 '14 at 19:22
  • Thanks guys!! QQ: I got some "success" when I used `cujo/poly` with `deps require.config` [here](http://requirejs.org/docs/api.html#config-deps) option. So my `require-config` looks like this: `{ // paths...// packages...// , 'deps': ['poly/all'] }`. I ran this in IE8 couple of times and it seems to have pre-loaded polyfill lib. Do you guys think this would be a viable option? – Vikram Aug 22 '14 at 19:30
  • @unscriptable You say: "any setup requiring that polyfills be loaded first will be slower than embedding the polyfills into the app bundle." I'll lose sleep over this when someone provides hard data showing that the difference in performance is *significant*. – Louis Aug 22 '14 at 19:31
  • @unscriptable You also say: "Fwiw, using multiple script tags with async="false" would be faster than using embedded require() calls such as you've shown since requirejs would have to finish loading poly before starting to load js/app." But you previously talked about "embedding the polyfills into the app bundle". If the polyfills are included into the bundle, then the app is going to load as soon as the polyfills are requested because they are in the same bundle. The 2nd `require` will add a tiny amount of time to the whole operation because the app will *already* be loaded. – Louis Aug 22 '14 at 19:33
  • @Vikram The modules you give to `deps` are just *scheduled* for loading immediately. When they will execute is not guaranteed at all. They could execute after your application has started executing. (From [the doc](http://requirejs.org/docs/api.html#config-deps): "**It does not block** any other require() calls from starting their requests for modules [...]") – Louis Aug 22 '14 at 19:35
2

I ran into the same problem, and my solution was to make Require.js load the polyfills as dependencies for me. You can see in this gist how I solved it in combination with Conditioner.js, but the solution is the same without it.

I've chosen to feature detect loading polyfills, so newer browsers don't make unnecessary requests. Feature detection makes this specific solution superior.

In your index.html:

<script src="/js/require.js" data-main="/js/main"></script>

In the file /js/main.js:

var _polyfills = [];
if (!('classList' in document.documentElement)) {
    _polyfills.push('polyfills/classList');
}
// ... more feature detects & polyfills ...

require(['bootstrap'].concat(_polyfills), function(bootstrap) {
    bootstrap.run(); // Bootstrap your app here!
});
  • Let's say `bootstrap` needs module `foo` (which is a third-party library) and `foo` needs `classList`. How do you prevent `foo` from loading before `classList` is loaded? What you show in your answer does not prevent this problem. Also, given that `r.js` is unable to follow computed dependencies, how do you run the optimizer on this kind of code so that it runs on multiple platforms? – Louis May 20 '15 at 10:07