Skip to content

Manually include resources in document head

Max Ziebell edited this page Aug 23, 2020 · 2 revisions

Why would you need this?

Ever wanted to only copy and paste your Hype container with the JavaScript reference but couldn't do so because you had stuff in your document head that your file depended on? This approach works great for cases where you don't have access privileges to the page head like in Content Management Systems or some page builders or need your initial embed to be self-contained.

What is HTML document head?

The head of an HTML document is the part that is not displayed in the web browser when the page is loaded. It contains information such as the page title, links to external CSS files, links to custom favicons and other metadata (like keywords). It furthermore can contain direct CSS and JavaScript declarations but this article is about managing linked content your Hype document relies on.

Including external resources will causes Hype to add the resources to the HTML document head, causing the JavaScript libraries to be available in the global namespace and the custom CSS styling to be applied. Hype links JavaScript and CSS files you add to your Hype project resources panel as external resources to the HTML head to have them accessible and loaded before the Hype document loads. This works as the head section has a special characteristic that the browser will not show anything until all the external resources are fully loaded (render blocking).

Helper function addToHead

This helper takes the approach to remove the resources from the head by unchecking the "include in document <head>" and adding them into a JavaScript function that is triggered on scene load. Then this approach waits for the external resources to be loaded and initialized and triggers a callback (like forwarding to the next scene). This works because external styles, scripts and other resources provide load events and if a script loads successfully, the onload event triggers. We can use this fact to add external resources from within our Hype document to the document head and track their loading status. Then once we have loaded all resources we then can progress to display our Hype animation. This has the added benefit of removing render blocking resources and speeding up the initial page load. Specially interesting for pages that contain other information apart from our Hype animation. The function is pretty simple and straightforward:

function addToHead (urls, callback){
	var tag, len = urls.length;
	for (var i=0; i<len; i++){
		switch (urls[i].split('.').pop().toLowerCase()){
			case 'js':
				var tag = document.createElement("script");
				tag.src = urls[i];
				break;
				
			case 'css': 
				var tag = document.createElement("link");
				tag.rel = "stylesheet";
				tag.type = "text/css";
				tag.href = urls[i];
				break;
		}
		tag.onload = function(){
			if ((--len)==0 && typeof callback == "function") callback();
		};
		document.head.appendChild(tag);
	}	
}

And this is how you trigger the function with a callback that fires after loading is done:

// let us load some sample data
addToHead([
	'https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js',
	'${resourcesFolderName}/test.css',
], function(){
	console.log("callback fired");
	hypeDocument.showNextScene();
});

Special case: Including Hype extensions with this approach

If you are using Hype Events in the external documents (specifically the HypeDocumentLoad) you might need to re-trigger that event for them to work properly. Here is a simple approach to do just that using the hypeDocument.notifyEvent approach discussed in Hype Events

You would need to include the hypeDocument.notifyEvent helper

hypeDocument.notifyEvent = function(event, element) {
	var eventListeners = window['HYPE_eventListeners'];
	if (eventListeners == null) {
		return;
	}
	var result;
	for (var i = 0; i < eventListeners.length; i++) {
		if (eventListeners[i]['type'] == event['type'] && eventListeners[i]['callback'] != null) {
			result = eventListeners[i]['callback'](this, element, event);
			if (result === false) {
				return false;
			}
		}
	}
	return result;
};

And then trigger a HypeDocumentLoad event after the resources have loaded and before switching to a new scene or doing anything with it.

// let us load some sample data
addToHead([
	'https://cdn.jsdelivr.net/gh/worldoptimizer/HypeAnimationFrame/HypeAnimationFrame.js',
	'https://cdn.jsdelivr.net/gh/worldoptimizer/HypeGlobalBehavior/HypeGlobalBehavior.min.js',
	'${resourcesFolderName}/test.css',
], function(){
	console.log("callback fired");
	hypeDocument.notifyEvent({type:'HypeDocumentLoad'}, element);
	hypeDocument.showNextScene();
});

Example files

https://gumroad.com/l/XXKsk

Clone this wiki locally