├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── index.es6 └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | .* 4 | !.gitignore 5 | !.travis.yml 6 | *.db* 7 | *.log* 8 | *.js* 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes to Preload Fill 2 | 3 | ### 1.0.0 (February 1, 2017) 4 | 5 | - Initial version 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Preload Fill 2 | 3 | You want to help? You rock! Now, take a moment to be sure your contributions 4 | make sense to everyone else. 5 | 6 | ## Reporting Issues 7 | 8 | Found a problem? Want a new feature? 9 | 10 | - See if your issue or idea has [already been reported]. 11 | - Provide a [reduced test case] or a [live example]. 12 | 13 | Remember, a bug is a _demonstrable problem_ caused by _our_ code. 14 | 15 | ## Submitting Pull Requests 16 | 17 | Pull requests are the greatest contributions, so be sure they are focused in 18 | scope, and do avoid unrelated commits. 19 | 20 | 1. To begin, [fork this project], clone your fork, and add our upstream. 21 | ```bash 22 | # Clone your fork of the repo into the current directory 23 | git clone https://github.com//preloadfill 24 | # Navigate to the newly cloned directory 25 | cd preloadfill 26 | # Assign the original repo to a remote called "upstream" 27 | git remote add upstream https://github.com/jonathantneal/preloadfill 28 | # Install the tools necessary for development 29 | npm install 30 | ``` 31 | 32 | 2. Create a branch for your feature or fix: 33 | ```bash 34 | # Move into a new branch for a feature 35 | git checkout -b feature/thing 36 | ``` 37 | ```bash 38 | # Move into a new branch for a fix 39 | git checkout -b fix/something 40 | ``` 41 | 42 | 3. Be sure your code follows our practices. 43 | ```bash 44 | # Test current code 45 | npm run test 46 | ``` 47 | 48 | 4. Push your branch up to your fork: 49 | ```bash 50 | # Push a feature branch 51 | git push origin feature/thing 52 | ``` 53 | ```bash 54 | # Push a fix branch 55 | git push origin fix/something 56 | ``` 57 | 58 | 5. Now [open a pull request] with a clear title and description. 59 | 60 | [already been reported]: issues 61 | [fork this project]: fork 62 | [live example]: http://codepen.io/pen 63 | [open a pull request]: https://help.github.com/articles/using-pull-requests/ 64 | [reduced test case]: https://css-tricks.com/reduced-test-cases/ 65 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # CC0 1.0 Universal 2 | 3 | ## Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an “owner”) of an original work of 8 | authorship and/or a database (each, a “Work”). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific works 12 | (“Commons”) that the public can reliably and without fear of later claims of 13 | infringement build upon, modify, incorporate in other works, reuse and 14 | redistribute as freely as possible in any form whatsoever and for any purposes, 15 | including without limitation commercial purposes. These owners may contribute 16 | to the Commons to promote the ideal of a free culture and the further 17 | production of creative, cultural and scientific works, or to gain reputation or 18 | greater distribution for their Work in part through the use and efforts of 19 | others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation of 22 | additional consideration or compensation, the person associating CC0 with a 23 | Work (the “Affirmer”), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and 25 | publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights (“Copyright and 31 | Related Rights”). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 1. the right to reproduce, adapt, distribute, perform, display, 34 | communicate, and translate a Work; 35 | 2. moral rights retained by the original author(s) and/or performer(s); 36 | 3. publicity and privacy rights pertaining to a person’s image or likeness 37 | depicted in a Work; 38 | 4. rights protecting against unfair competition in regards to a Work, 39 | subject to the limitations in paragraph 4(i), below; 40 | 5. rights protecting the extraction, dissemination, use and reuse of data 41 | in a Work; 42 | 6. database rights (such as those arising under Directive 96/9/EC of the 43 | European Parliament and of the Council of 11 March 1996 on the legal 44 | protection of databases, and under any national implementation thereof, 45 | including any amended or successor version of such directive); and 46 | 7. other similar, equivalent or corresponding rights throughout the world 47 | based on applicable law or treaty, and any national implementations 48 | thereof. 49 | 50 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 51 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 52 | unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright 53 | and Related Rights and associated claims and causes of action, whether now 54 | known or unknown (including existing as well as future claims and causes of 55 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 56 | duration provided by applicable law or treaty (including future time 57 | extensions), (iii) in any current or future medium and for any number of 58 | copies, and (iv) for any purpose whatsoever, including without limitation 59 | commercial, advertising or promotional purposes (the “Waiver”). Affirmer makes 60 | the Waiver for the benefit of each member of the public at large and to the 61 | detriment of Affirmer’s heirs and successors, fully intending that such Waiver 62 | shall not be subject to revocation, rescission, cancellation, termination, or 63 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 64 | by the public as contemplated by Affirmer’s express Statement of Purpose. 65 | 66 | 3. Public License Fallback. Should any part of the Waiver for any reason be 67 | judged legally invalid or ineffective under applicable law, then the Waiver 68 | shall be preserved to the maximum extent permitted taking into account 69 | Affirmer’s express Statement of Purpose. In addition, to the extent the Waiver 70 | is so judged Affirmer hereby grants to each affected person a royalty-free, non 71 | transferable, non sublicensable, non exclusive, irrevocable and unconditional 72 | license to exercise Affirmer’s Copyright and Related Rights in the Work (i) in 73 | all territories worldwide, (ii) for the maximum duration provided by applicable 74 | law or treaty (including future time extensions), (iii) in any current or 75 | future medium and for any number of copies, and (iv) for any purpose 76 | whatsoever, including without limitation commercial, advertising or promotional 77 | purposes (the “License”). The License shall be deemed effective as of the date 78 | CC0 was applied by Affirmer to the Work. Should any part of the License for any 79 | reason be judged legally invalid or ineffective under applicable law, such 80 | partial invalidity or ineffectiveness shall not invalidate the remainder of the 81 | License, and in such case Affirmer hereby affirms that he or she will not (i) 82 | exercise any of his or her remaining Copyright and Related Rights in the Work 83 | or (ii) assert any associated claims and causes of action with respect to the 84 | Work, in either case contrary to Affirmer’s express Statement of Purpose. 85 | 86 | 4. Limitations and Disclaimers. 87 | 1. No trademark or patent rights held by Affirmer are waived, abandoned, 88 | surrendered, licensed or otherwise affected by this document. 89 | 2. Affirmer offers the Work as-is and makes no representations or 90 | warranties of any kind concerning the Work, express, implied, statutory 91 | or otherwise, including without limitation warranties of title, 92 | merchantability, fitness for a particular purpose, non infringement, or 93 | the absence of latent or other defects, accuracy, or the present or 94 | absence of errors, whether or not discoverable, all to the greatest 95 | extent permissible under applicable law. 96 | 3. Affirmer disclaims responsibility for clearing rights of other persons 97 | that may apply to the Work or any use thereof, including without 98 | limitation any person’s Copyright and Related Rights in the Work. 99 | Further, Affirmer disclaims responsibility for obtaining any necessary 100 | consents, permissions or other rights required for any use of the Work. 101 | 4. Affirmer understands and acknowledges that Creative Commons is not a 102 | party to this document and has no duty or obligation with respect to 103 | this CC0 or use of the Work. 104 | 105 | For more information, please see 106 | http://creativecommons.org/publicdomain/zero/1.0/. 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Preload Fill [Preload Fill][Preload Fill] 2 | 3 | [![NPM Version][npm-img]][npm-url] 4 | [![Build Status][cli-img]][cli-url] 5 | [![Licensing][lic-img]][lic-url] 6 | [![Changelog][log-img]][log-url] 7 | 8 | [Preload Fill] is a polyfill for the [preload link type]. 9 | 10 | Visit a [CodePen Example of Preload] demonstrating asynchronously loaded CSS. 11 | 12 | **THIS PROJECT IS IN A DRAFT STAGE** 13 | 14 | ```html 15 | 16 | ``` 17 | 18 | ## Usage 19 | 20 | Install [Preload Fill] to your project. 21 | 22 | ```sh 23 | npm install jonathantneal/preloadfill --save-dev 24 | ``` 25 | 26 | Import [Preload Fill] within your script. 27 | 28 | ```js 29 | import 'preloadfill'; 30 | ``` 31 | 32 | ## Additional Reading 33 | 34 | [Smashing Magazine: Preload: What Is It Good For?](https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/) 35 | 36 | --- 37 | 38 | [Preload Fill] is 558 bytes after being transpiled, minified, and gzipped. 39 | 40 | [Preload Fill]: https://github.com/jonathantneal/preloadfill 41 | 42 | [CodePen Example of Preload]: http://codepen.io/jonneal/details/dNdRaj 43 | [preload link type]: https://w3c.github.io/preload/ 44 | 45 | [npm-url]: https://www.npmjs.com/package/preloadfill 46 | [npm-img]: https://img.shields.io/npm/v/preloadfill.svg 47 | [cli-url]: https://travis-ci.org/jonathantneal/preloadfill 48 | [cli-img]: https://img.shields.io/travis/jonathantneal/preloadfill.svg 49 | [lic-url]: LICENSE.md 50 | [lic-img]: https://img.shields.io/badge/license-CC0--1.0-blue.svg 51 | [log-url]: CHANGELOG.md 52 | [log-img]: https://img.shields.io/badge/changelog-md-blue.svg 53 | -------------------------------------------------------------------------------- /index.es6: -------------------------------------------------------------------------------- 1 | try { 2 | // throw if the document does not support preload 3 | if (!document.createElement('link').relList.supports('preload')) { 4 | throw Error; 5 | } 6 | } catch (error) { 7 | (() => { 8 | const selector = 'link[rel="preload"]'; 9 | 10 | // iframe 11 | const iframe = document.createElement('iframe'); 12 | 13 | iframe.style.cssText = 'display:none'; 14 | 15 | iframe.src = 'javascript:false'; // eslint-disable-line no-script-url 16 | 17 | document.head.appendChild(iframe); 18 | 19 | const iframeWindow = iframe.contentWindow; 20 | const iframeDocument = iframeWindow.document; 21 | 22 | iframeDocument.close(); 23 | 24 | iframeWindow.addEventListener('load', () => { 25 | // preload link[rel="preload"] by element 26 | const preloadLinkByElement = (element) => { 27 | const as = element.getAttribute('as'); 28 | 29 | if (forward[as]) { 30 | forward[as](element); 31 | } 32 | }; 33 | 34 | const forward = { 35 | // forward [rel="preload"][as="script"] load event 36 | script(element) { 37 | const onload = (event) => { 38 | preload.removeEventListener('load', onload); 39 | 40 | iframeDocument.head.removeChild(preload); 41 | 42 | element.dispatchEvent(new CustomEvent('load', event)); 43 | }; 44 | 45 | const preload = iframeDocument.createElement('script'); 46 | 47 | preload.addEventListener('load', onload); 48 | 49 | preload.src = element.href; 50 | 51 | iframeDocument.head.appendChild(preload); 52 | }, 53 | // forward [rel="preload"][as="style"] load event 54 | style(element) { 55 | const onload = (event) => { 56 | preload.removeEventListener('load', onload); 57 | 58 | iframeDocument.head.removeChild(preload); 59 | 60 | element.dispatchEvent(new CustomEvent('load', event)); 61 | }; 62 | 63 | const preload = iframeDocument.createElement('link'); 64 | 65 | preload.addEventListener('load', onload); 66 | 67 | preload.href = element.href; 68 | 69 | preload.rel = 'stylesheet'; 70 | 71 | iframeDocument.head.appendChild(preload); 72 | } 73 | }; 74 | 75 | // preload link[rel="preload"] by mutations 76 | const preloadLinkByMutation = (mutations) => mutations.reduce( 77 | (nodes, mutation) => nodes.concat.apply(nodes, mutation.addedNodes), 78 | [] 79 | ).reduce( 80 | (nodes, node) => nodes.concat.apply( 81 | nodes, 82 | node.matches && node.matches(selector) && node || 83 | node.querySelectorAll && node.querySelectorAll(selector) || [] 84 | ), 85 | [] 86 | ).forEach(preloadLinkByElement); 87 | 88 | // observe mutations 89 | new MutationObserver(preloadLinkByMutation).observe( 90 | document.documentElement, 91 | { 92 | childList: true, 93 | subtree: true 94 | } 95 | ); 96 | 97 | // preload link[rel="preload"] by selector 98 | Array.prototype.forEach.call( 99 | document.documentElement.querySelectorAll(selector), 100 | preloadLinkByElement 101 | ); 102 | }); 103 | })(); 104 | } 105 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preloadfill", 3 | "version": "0.0.0", 4 | "description": "A polyfill for the preload link type", 5 | "author": "Jonathan Neal (http://jonathantneal.com)", 6 | "license": "CC0-1.0", 7 | "repository": "jonathantneal/preloadfill", 8 | "homepage": "https://github.com/jonathantneal/preloadfill#readme", 9 | "bugs": "https://github.com/jonathantneal/preloadfill/issues", 10 | "main": "index.js", 11 | "jsnext:main": "index.es6", 12 | "files": [ 13 | "index.es6", 14 | "index.js" 15 | ], 16 | "scripts": { 17 | "build": "babel index.es6 --out-file index.js", 18 | "clean": "git clean -X -d -f", 19 | "pre-commit": "echo 'Running pre-commit checks...' && exit 0", 20 | "prepublish": "npm run test && npm run build", 21 | "test": "npm run test:ec && npm run test:es", 22 | "test:ec": "echint", 23 | "test:es": "eslint index.es6" 24 | }, 25 | "engines": { 26 | "node": ">=4.5.0" 27 | }, 28 | "devDependencies": { 29 | "babel-cli": "^6.18.0", 30 | "babel-preset-env": "^1.1.8", 31 | "echint": "^3.0.0", 32 | "echint-config-dev": "^1.0.0", 33 | "eslint": "^3.8.1", 34 | "eslint-config-dev": "^1.0.0", 35 | "pre-commit": "^1.2.2" 36 | }, 37 | "babel": { 38 | "presets": [ 39 | [ 40 | "env", 41 | { 42 | "loose": true 43 | } 44 | ] 45 | ] 46 | }, 47 | "browserslist": [ 48 | "last 2 versions" 49 | ], 50 | "echint": { 51 | "extends": "dev" 52 | }, 53 | "eslintConfig": { 54 | "extends": "dev" 55 | }, 56 | "pre-commit": [ 57 | "pre-commit", 58 | "test" 59 | ], 60 | "keywords": [ 61 | "document", 62 | "dom", 63 | "load", 64 | "loaded", 65 | "loading", 66 | "preload", 67 | "preloaded", 68 | "preloading", 69 | "link", 70 | "rel", 71 | "as", 72 | "script", 73 | "style", 74 | "polyfill" 75 | ] 76 | } 77 | --------------------------------------------------------------------------------