Skip to content

Instantly share code, notes, and snippets.

@branneman
Last active September 27, 2016 11:49
Show Gist options
  • Save branneman/37865bcfc5d102c2be6c to your computer and use it in GitHub Desktop.
Save branneman/37865bcfc5d102c2be6c to your computer and use it in GitHub Desktop.
Conditioner.js bootstrap with JavaScript Mustard Cut & Polyfill loading
<!doctype html>
<html>
<head>
...
<script>
(function(d){
if (!('querySelector' in d && 'addEventListener' in window)) return;
d.documentElement.className += ' has-js';
d.addEventListener('DOMContentLoaded', function() {
var s = d.createElement('script');
s.setAttribute('src', '/static/js/vendor/requirejs/require.js');
s.setAttribute('data-main', '/static/js/main');
d.body.appendChild(s);
});
}(document));
</script>
</head>
<body>
...
</body>
</html>
(function(){
require.config({
map: {
'*': {
classList: 'polyfills/classList',
conditioner: 'vendor/conditionerjs/conditioner'
}
}
});
var polyfills = [];
if (!('classList' in document.documentElement)) {
polyfills.push('classList');
}
// ... more feature detections ...
require(['conditioner'].concat(polyfills), function(conditioner) {
conditioner.init();
});
}());
@rikschennink
Copy link

I'm going with a has-js class instead of a no-js class, because Progressive Enhancement.

Interesting, I'm going to think on this some more.

a simple x.className += ' has-js' will have to do then.

It might be simple, but it's probably fast as well.

Also, right now I can call insertBefore on the current script at the end of the body. What do you propose for inserting the script tag at the end of the body?

I'd say document.body.appendChild()

I copied it from the Google Analytics code, but I'm unsure why they add it as well.

They have added it because Google Analytics is embedded in the head and they use a 'queue' object for all the tracking stuff (it works before the script is loaded).

I don't see any other way, I want them to be conditionally loaded, every browser gets different polyfills.

I would find a common set of functionality and merge those. Or, you could only polyfill once a module loads that requires certain polyfills. Certainly for conditional modules that would be preferable.

@branneman
Copy link
Author

Updated! Thanks for the response so far :)

@rikschennink
Copy link

Looks nice, I've taken a stab at shortening the mustard cut a bit. And have implemented the bouncer pattern.

(function(){

    var d = document;
    if (!('querySelector' in d && 'addEventListener' in window)) {return;}

    d.documentElement.className += ' has-js';
    d.addEventListener('DOMContentLoaded', function() {
        var s = d.createElement('script');
        s.setAttribute('src', '/static/js/vendor/requirejs/require.js');
        s.setAttribute('data-main', '/static/js/main');
        d.body.appendChild(s);
    });

}());

Also the new module enabled property in Conditioner might be interesting in relation to the polyfills. It's a micro mustard cut.

To prevent polluting the global scope with the _polyfills variable you could wrap the entire main.js in a self executing function or maybe even make a separate polyfills module.

@branneman
Copy link
Author

Manual minification, I love it. We can do even better:

(function(d){
    // ...
}(document));

Also, would it be possible to shorten both the setAttribute calls? I know s.src = will work, but will this work for the data attribute as well?

var s = d.createElement('script');
s.src = '/static/js/vendor/requirejs/require.js';
s['data-main'] = '/static/js/main';

Or we could go crazy and save more bytes:

(function(d, f){
    s[f]('src', '/static/js/vendor/requirejs/require.js');
    s[f]('data-main', '/static/js/main');
}(document, 'setAttribute'));

On second thought, let's stop here ;) We should leave minification to a minifier.

Anyway, I've updated the gist with the sane changes.

@rikschennink
Copy link

Haha, brilliant! :-) Excellent plan to leave minifying to the pros ;)

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