Load External Libraries with Unpoly
The way I wrote webapplications in the past was referencing single javascript libraries and plugins and call their methods either in inline scripts or with a final javascript file. This way you could add scripts per page, like a large chart library or maps and you only load what you need.
This is all possible because there is a full reload for every webpage which fetches all the resources like additional javascript or css.
html
head
link(href="page.css")
body
div.row
div.col-6<small class="hashtag text-monospace text-muted">#map</small>
div.col-6<small class="hashtag text-monospace text-muted">#content</small>
script(src="https://cdn.com/jquery.js")
script(src="https://cdn.com/leaflet.js")
script(src="/app.js")
With the need of websites behaving app-like and the wish for softer and slicker page transitions, single-page apps (SPA) became popular and there was no hard reload anymore.
It doesn't matter if you use Vue, Turbolinks, Intercooler oder anything that doesn't break the javascript lifecycle with a hard server reload – you have to rethink how to write javascript.
The Problem
In my example I used the pretty neat library Unpoly, that is helping to enhance classic html websites with smooth page transitions by swapping out server rendered html via ajax, without reloading the page.
As long as you load all the used javascript on your first pageload, you are fine. But if you are used to add site specific javascript inline or load it on demand, you are out of luck, since unpoly doesn't parse any script tags in the returned html fragment1.
Imagine this scenario by navigate from page Index...
html
head
title "Index"
link(href="page.css")
body
div.row
div.col-6<small class="hashtag text-monospace text-muted">#map</small>
div.col-6<small class="hashtag text-monospace text-muted">#content</small>
a(href="/map", up-target="body")
script(src="https://cdn.com/unpoly.js")
...to page Map with Unpoly. The <body>
gets swapped out with the following and you assume the new script tags are going to be executed.
html
head
title "Map"
link(href="page.css")
body
div.row
div.col-6<small class="hashtag text-monospace text-muted">#map</small>
div.col-6<small class="hashtag text-monospace text-muted">#content</small>
script(src="https://cdn.com/unpoly.js")
script(src="https://cdn.com/leaflet.js")
script.
var map = L.map('map').setView([50.493054,12.8190702], 16);
But that is not the case.
With a full page reload I get Unpoly and the Leaflet library and then I initialize the map afterwards.
But if I navigate to this page with Unpoly, the script tags are getting ignored and even if I use Unpoly compilers leaflet.js
is not available1
The solution to this is
- move the inline javascript into it's own file and wrap it in
up.compiler()
- load the additional assets like the Leaflet library and its css via javascript
The Solution
Load script and css files dynamically. I use these functions for loadScript and loadCSS but anything else, like jQuery's $.getScript()
should work. Just make sure, that script tags are added only once (both linked script take care of that).
html
head
title "Map"
link(href="page.css")
body
div.row
div.col-6<small class="hashtag text-monospace text-muted">#map</small>
div.col-6<small class="hashtag text-monospace text-muted">#content</small>
script(src="https://cdn.com/unpoly.js")
// load app.js in your initial page call.
script(src="/app.js")
// app.js
// if you need the promise polyfill https://polyfill.io/v3/polyfill.min.js?flags=gated&features=Promise
up.compiler('<small class="hashtag text-monospace text-muted">#map</small>', function(e) {
// include loadCSS function in your script
// @link https://gist.github.com/marcus-at-localhost/514ce85df6fb3ab10719a7cacce50770
loadCSS('https://cdn.jsdelivr.net/npm/leaflet@1.5.1/dist/leaflet.min.css');
// include the loadScript function
// @link https://gist.github.com/marcus-at-localhost/da0cc3da4bfa70399963a4bd32b9e5bf
loadScript('https://cdn.jsdelivr.net/npm/leaflet@1.5.1')
.then( function () {
var map = L.map('map').setView([50.493054,12.8190702], 16);
});
return function(){
map.remove();
};
});
You can look at the code of this page https://schmetterlinge-im-luchsbachtal.de/entdecken to see it work.
Update: just found a complete article from the Unpoly devs, oh well :).