Already touched upon this topic in my HTTP/2 write-up (don’t do this without setting up HTTP/2 first), but although I did initial testing back then only got back to it seriously yesterday. So, let met give some very quick instructions on how to get it working in PSK, though likely it will be similar in any other Polymer application.
<page-*>
elements
Start of with making every page an element. In my case these elements are called <page-*>
elements, so your index.html
looks something like:
<iron-pages attr-for-selected="data-route" selected="{{route}}">
<page-welcome data-route="home"></page-welcome>
[...]
</iron-pages>
It’s possible to set this up in different ways as well, but this is the best way I have found so far to organize my application in Polymer.
Lazy loading them
My approach is to trigger the loading of the elements from the router. This might be somewhat debatable from a logical point of view (a router shouldn’t be loading anything), but the alternative of creating an entire element which on becoming visible would lazy load the <page-*>
seemed uglier to me than simply loading the element from the router.
So, on my app
I defined a function loadDependency
as follows:
var loadedDependencies = [];
app.loadDependency = function(el){
if(loadedDependencies.indexOf(el) === -1){
loadedDependencies.push(el);
app.importHref('/elements/' + el + '.html', function(){
window.dispatchEvent(new Event('resize'));
}, function(){
alert('Failed loading the requested page.');
});
}
};
and my routing functions look like
page('/', function () {
app.loadDependency('dashboard/page-welcome');
app.route = 'home';
});
Things of note:
- I have to trigger a
resize
event after the element is loaded. The reason for this is that some elements - likeiron-list
do not correctly initialize otherwise, it might be worth trying out commenting out that line and checking whether everything works for you. - The
alert
is just a stop-gap solution and of course it’s not wise to leave it that way.
The elements.html
file
One very common mistake is that people list all their elements in the elements.html
file. This file is meant to only list the dependencies from your index.html
(excluding the lazy loaded elements of course). Do not list dependencies of dependencies here (e.g. an element used by a <page-*>
). Dependencies of <page-*>
elements should - like with every other custom element - be listed at the top of the file. That way those dependencies are only loaded once required.
Passing attributes
UPDATE: It seems this has been solved in Polymer 1.3, see the last item on the release notes.
To pass attributes from the router to the pages it will look like
page('/search/:query', function (data) {
[...]
app.set('params.searchQuery', data.params.query);
});
and
<page-search data-route="search" search-query$="{{params.searchQuery}}"></page-search>
The reason for the odd usage of $=
is that during page load the page-search
element isn’t registered and thus a plain DOM element on which the Polymer DOM magic can’t work. By making it an attribute property however Polymer won’t worry about ‘properly’ binding it and instead will simply set it as an attribute anytime the property is changed.
Flash of unloaded elements
One problem you might encounter is that you get to see a page which isn’t fully loaded yet. Now, depending on the approach you use there are a lot of different ways to ‘fix’ this, but in the end all of them depend on having some code in the success
callback of the importHref
method. In my case I have a simple overlay (which looks like the barebones of my application) with pointer-events: none;
and
document.getElementById('loading').style.opacity = 0;
in my loadDependency
success callback. Maybe not the most generic setup and I am sure there are neater ways to program this, but it gets the job done perfectly.
Last thoughts
All considered with HTTP/2 setting up lazy loading is easier than it’s ever been before, but there are still some pain points, but none of them are too bad. Once Polymer releases it’s new router stuff might get either easier or harder, we shall see, but I hope it won’t be too different all considered. For that matter, creating a lazy loading <lazy-pages>
would actually be relatively easy as well and once Polymer properly supports extending custom elements that might actually be the best option.
Comments
Post a Comment