Skip to content

Instantly share code, notes, and snippets.

@ebidel
Last active May 1, 2021 15:42
Show Gist options
  • Save ebidel/1ba71473d687d0567bd3 to your computer and use it in GitHub Desktop.
Save ebidel/1ba71473d687d0567bd3 to your computer and use it in GitHub Desktop.
Fast Polymer app loading - optimized for first render, progressively enhanced lazy loading
<!DOCTYPE html>
<html>
<head>
<style>
body.loading #splash {
opacity: 1;
}
#splash {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
transition: opacity 300ms cubic-bezier(0,0,0.2,1);
opacity: 0;
will-change: opacity;
z-index: 1;
background: url(...) no-repeat;
background-color: #E53935;
}
</style>
<!-- 1. Async HTML Imports do not block rending. Benefit of keeping it declarative
(instead of dynamically loading it later in JS) is that the parser can go
to town pre-fetching resources, etc. -->
<link rel="import" id="bundle" href="elements.html" async>
</head>
<!-- 2. Don't use <body unresolved>. It's a simple FOUC solution, but hides
the page until imports and Polymer are loaded. Intead, control FOUC manually with
a splash screen. -->
<body class="loading">
<!-- 3. Light weight splash screen is outside of Polymer/imports and styled by
the main page. 1st paint is fast, even on polyfilled browsers. Alternatively,
one could create an "app shell" and style the page's un-upgraded elements
similar to their final upgraded version. -->
<div id="splash"></div>
<!-- Elements wait on the page and are upgraded when elements.html loads. -->
<paper-drawer-panel>
...
</paper-drawer-panel>
<script src="app.js" async></script>
</body>
</html>
// 4. Conditionally load the webcomponents polyfill if needed by the browser.
// This feature detect will need to change over time as browsers implement
// different features.
var webComponentsSupported = ('registerElement' in document
&& 'import' in document.createElement('link')
&& 'content' in document.createElement('template'));
if (!webComponentsSupported) {
var script = document.createElement('script');
script.async = true;
script.src = '/bower_components/webcomponentsjs/webcomponents-lite.min.js';
script.onload = finishLazyLoading;
document.head.appendChild(script);
} else {
finishLazyLoading();
}
function finishLazyLoading() {
// (Optional) Use native Shadow DOM if it's available in the browser.
window.Polymer = window.Polymer || {dom: 'shadow'};
// 6. Fade splash screen, then remove.
var onImportLoaded = function() {
var loadEl = document.getElementById('splash');
loadEl.addEventListener('transitionend', loadEl.remove);
document.body.classList.remove('loading');
// App is visible and ready to load some data!
};
var link = document.querySelector('#bundle');
// 5. Go if the async Import loaded quickly. Otherwise wait for it.
// crbug.com/504944 - readyState never goes to complete until Chrome 46.
// crbug.com/505279 - Resource Timing API is not available until Chrome 46.
if (link.import && link.import.readyState === 'complete') {
onImportLoaded();
} else {
link.addEventListener('load', onImportLoaded);
}
}
@oliver92
Copy link

@czellweg i still got onImportsLoaded called before all elements were loaded, infact it got called right away, the loading stays for just 2 ms...

Edit: The actual elements are imported, but i think after the imports polymer it`s self does more work, to order the elements on the page, and apply more styling to them, which it can be seen as the splash is already removed by then.

@arturparkhisenko
Copy link

arturparkhisenko commented Jan 18, 2016

How about browser support on it? How to avoid this: crbug.com/504944 - readyState never goes to complete until Chrome 46. on Mac Chrome 41 i have empty element (just tag) and its without async!
<link rel="import" id="bundle" href="elements.html"> ?
I need that because i need to debug my code.. and i got that i described in previous comment.
Tested on Mac Chromium 24 - works fine.
Fixed (i found fix there on gaming youtube) by adding this case with interactive on line37:

if ( link.import && (link.import.readyState === 'complete' || link.import.readyState === 'interactive')) {
  onImportLoaded();
}

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