-
-
Save branneman/37865bcfc5d102c2be6c to your computer and use it in GitHub Desktop.
<!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(); | |
}); | |
}()); |
I'm going with a has-js
class instead of a no-js
class, because Progressive Enhancement.
I'd run the mustard cut in the
head
so you can remove theno-js
earlier
This is possible, however since I'm loading the polyfills in my main.js
, this means I can't use classList
anymore, a simple x.className += ' has-js'
will have to do then.
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 also think the async doesn't matter if it's the last script being loaded
I copied it from the Google Analytics code, but I'm unsure why they add it as well.
Replace
querySelector()
withgetElementById()
Sure, why not ;)
get rid of the global
deps
variable
You're right. I've removed the deps
variable, and underscored the polyfills
variable to indicate it's private.
I'm a little worried about servering all the polyfills as separate files
I don't see any other way, I want them to be conditionally loaded, every browser gets different polyfills.
Sorry to go OT a bit, but just to chip in re: your last point: have you seen https://polyfill.io ?
It's "Polyfill As A Service" and I am lovin' the idea: you simply link to 1 script endpoint and the UA automagically receives appropriate polyfills. You can—of course—also specify features explicitly:https://cdn.polyfill.io/v1/docs/features/
Anyway, off-topic for your use-case but my feeling is that this could be an elegant way to deal with polyfills…
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.
Updated! Thanks for the response so far :)
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.
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.
Haha, brilliant! :-) Excellent plan to leave minifying to the pros ;)
I'd run the mustard cut in the
head
so you can remove theno-js
earlier and use it in your CSS. Use it later on for the mustard cut statement?Replace
document.querySelector('#js-mustard-cut')
withdocument.getElementById('js-mustard-cut')
it's a lot faster. I'm also wondering if it's possible to just select the existing<script>
element and add the src and async attributes to it. I also think the async doesn't matter if it's the last script being loaded but I'm not sure.You could do the following to get rid of the global
deps
variable:I'm a little worried about servering all the polyfills as separate files, concatting and minifying them would be faster I guess.