├── README.md └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # Header Snippets 2 | A collection of snippets to put in your header. 3 | 4 | ### Background 5 | 6 | In my [A Bloatless Web post](https://itnext.io/a-bloatless-web-d4f811c7991b) I have shown tiny runtime features detection to avoid bloating code, or making network requests, in modern browsers. 7 | 8 | I haven't wasted much time explaining those features detection, but they can be handy, and I want to collect them somewhere in here. 9 | 10 | Please note these snippets should be used in your pages only if you need those features, and it's not wise to just trash everything in. 11 | 12 | ## Features Detection: Origami Style 13 | 14 | Forget linters and formatting, use the least amount of maintainable code to reliably inject a patch when necessary. 15 | 16 | Semicolons might be necessary to avoid IDE highlight issues. 17 | 18 | ### The most basic detection 19 | 20 | ```html 21 | 24 | ``` 25 | 26 | Above snippet does the following things: 27 | 28 | * is there a `Reflect` object in the global `this` context ? 29 | * if yes, nothing else will be executed, happy browsing 🎉 30 | * if not, the _OR_ `||` will pass through the code on the right, executing it 31 | * the code on the right will be executed only on browsers that do not have [Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect#Browser_compatibility) which are only legacy browsers 32 | * the `document.write` in those browsers will always work without a single warning or issue 33 | * `document.write` will grants, in those browsers, the next script on the header/page will be executed **after** the injected one has been parsed 34 | * the operation is blocking for legacy, implicitly inviting them to update their browsers if they think the Web is a bit slow (it's their fault, after all), and fully irrelevant for modern browsers 35 | 36 | If you are wondering why the final `` is written as `<\x2fscript>`, it's because otherwise the browser would close the current script at that position, resulting in a partially broken page. 37 | 38 | Theoretically I could omit that final `<\x2fscript>` completely, and let the browser dial with the never closed ` 45 | 46 | ``` 47 | 48 | Once upon a time, until IE 10 was published, unfortunately before the evergreen Edge was born, it was possible to reach specific versions of IE through [conditional comments](https://www.sitepoint.com/internet-explorer-conditional-comments/) via JS or HTML. 49 | 50 | The benefit of this technique is that not a single browser different from the one you are targeting will ever even consider the content within those funny looking comments. 51 | 52 | The script can be inline too. 53 | 54 | ```html 55 | 58 | ``` 59 | 60 | Above snippet, as example, will patch `setTimeout` and `setInterval` for IE9 and lower, providing extra arguments functionality. 61 | 62 | ### The multiple inline detection 63 | 64 | ```html 65 | 68 | ``` 69 | 70 | Using a combination of the _AND_ `&&` operator, it is possible check multiple things or, if not satisfied, fallback through an _OR_ `||`. 71 | 72 | 73 | ### The inline try/catch 74 | 75 | ```html 76 | 79 | ``` 80 | 81 | Above snippet will check in one single `try` the existence of the `EventTarget` and its ability to be used as constructor, falling back to a polyfill. 82 | 83 | Don't worry about global scope pollution, the `catch` argument will never leak outside its `catch` block. That `e` won't exist anywhere else. 84 | 85 | ### The IIFE 86 | 87 | ```html 88 | 97 | ``` 98 | 99 | Immediately Invoked Function Expressions are a way to create a temporary private scope, avoiding in this case pollution of the global scope or simply short-cutting some code through arguments. 100 | 101 | Above snippet performs the following operations: 102 | 103 | * pass the global context as `g` to the IIFE 104 | * also pass the global identifier of the constructor we want to test 105 | * verify the constructor exists, it's usable as such, and it produces the expected result 106 | * if any of the previous cases fail, throw an error, in case it's not automatically thrown 107 | * delete the badly implemented constructor from the global context 108 | * bring in the polyfill for such constructor 109 | 110 | Combining all techniques described above we can bring in selectively anything we need for our application. 111 | 112 | ## Shortcuts 113 | 114 | There are various ways to simplify features detection, or reduce repeated check. 115 | 116 | Nothing in here is strictly needed, but it might become handy if you need many detections. 117 | 118 | ### LEGACY 119 | 120 | ```html 121 | 122 | ``` 123 | 124 | Above snippet, placed at the very top of the page, can be used to both distinguish between ES2015 and ES5 targeted browsers, or inject, on demand, polyfills as we go. 125 | 126 | The advantage of polluting the global scope upfront with a `LEGACY` boolean is to be able to find out, even after patching `Reflect`, if the browser needed such patch or not. 127 | 128 | ### polyfill(test, url) 129 | 130 | ```html 131 | 135 | ``` 136 | 137 | Above snippet would perform the following actions: 138 | 139 | * is the first argument a string? 140 | * if yes, and such string is not in the global context, throw an error by executing such string. 141 | * if not, execute the function instead. 142 | * if there is an error or the global name is unknown, bring in the polyfill. 143 | 144 | ```html 145 | 149 | 153 | ``` 154 | 155 | Please note using `document.write` must be performed inline on the page otherwise `polyfill(...)` will destroy your document. It is also important to understand that in order to have incremental patching, each `polyfill(...)` might need its own script a part, otherwise the next `polyfill(...)` wont consider the potentially already fixed behavior the previous write pulled in. 156 | 157 | _TL;DR_ `polyfill(...)` here is not usable as generic JS loader, it's better used one ` 178 | ``` 179 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 |