ive installed typekit on my site, the usual two lines of js just after the opening head tag but its extremely slow / unresponsive to load in the fonts, this is completly remedied by refreshing the page, after that the typekit font load in perfectly and really quickly. But from a users point of view they will never know to do that, so they will be served the default fonts.
I have the typekit js as the very first thing under the opening head tag before the metatags and before loading in jquery, jquery-ui and other scripts.
Has any one else had trouble with this ?
what seemed to work for me was to load the script in an asynchronous pattern - as specified on the typekit blog, ive copied it in bellow
Standard asynchronous pattern
This first pattern is the most basic. It’s based on patterns written about by web performance experts like Steve Souders and used in other JavaScript embed codes like Google Analytics.
<script type="text/javascript">
TypekitConfig = {
kitId: 'abc1def'
};
(function() {
var tk = document.createElement('script');
tk.src = '//use.typekit.com/' + TypekitConfig.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (rs && rs != 'complete' && rs != 'loaded') return;
try { Typekit.load(TypekitConfig); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();
</script>
This pattern uses a single inline tag to dynamically add a new script element to the page, which loads the kit without blocking further rendering. An event listener is attached that calls Typekit.load() once the script has finished loading.
How to use it:
Place this snippet at the top of the so the download starts as soon as possible.
Edit the highlighted TypekitConfig object and replace the default with your own Kit ID.
You can add JavaScript font event callbacks to the TypekitConfig object.
Advantages:
Loads the kit asynchronously (doesn’t block further page rendering while it loads).
Disadvantages:
Adds more bytes to your html page than the standard Typekit embed code.
Causes an initial FOUT in all browsers that can’t be controlled or hidden with font events.
Related
I have some javascript that is not required for my initial page load. I need to load it based on some condition that will be evaluated client-side.
$(document).ready(function() {
let someCondition = true; // someCondition is dynamic
if (someCondition) {
var element = document.createElement('script');
element.src = 'https://raw.githubusercontent.com/Useless-Garbage-Institute/useless-garbage/master/index.js';
element.defer = true; // does this make a difference?
element.onload = function() {
// do some library dependent stuff here
document.getElementById("loading").textContent = "Loaded";
};
document.body.appendChild(element);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="loading">Loading...</h1>
Does it make a difference (in terms of how browser will treat the script tag), if a new tag created using javascript, after document is ready, has 'defer' attribute or not? I think there is no difference, but how can I say for sure?
I believe I understand how deferred scripts behave when script tag is part of the initial html (as described here). Also, this question is not about whether element.defer=true can be used or not (subject of this question).
No that doesn't make any difference, the defer attribute is ignored in case of "non-parser-inserted" scripts:
<script defer src="data:text/javascript,console.log('inline defer')"></script>
<script>
const script = document.createElement("script");
script.src = "data:text/javascript,console.log('dynamic defer')";
script.defer = true;
document.body.append(script);
</script>
<!-- force delaying of parsing -->
<script src="https://deelay.me/5000/https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Look at your browser's console or pay attention to the logs timestamps to see that the dynamically inserted script actually did execute while we were waiting for the delayed script to be fetched.
There's a difference between adding them to the function and adding directly the CDN ( especially in your case ).
Let's look at the code execution of the above-mentioned code first,
You have added the jquery CDN first ( without defer ) so that loads first.
$(document).ready will be fired once after the complete load of jquery.
There'll be the creation and insertion of a new script tag to the dom.
Download the https://raw.githubusercontent.com/Useless-Garbage-Institute/useless-garbage/master/index.js asynchronously.
Let's look at another approach: adding CDN to the code:
Your DOM will have 2 script tags.
Both will start loading based on the type of load parallelly ( defer async etc ).
Notice you are not waiting for the dom ready event to load the second script.
I suggest adding only the main JS part in a js file and adding it to the CDN. Others can wait load with the delay.
In case you are really needed with a js src, then don't load it the first way since it waits for the complete page load.
I suggest you read and look at web-vitals and SEO for this.
and for your other question, yes you can add defer attribute with element.defer=true to the elements while creating and loading to DOM.
Hope this answer helps you!
Feel free to comment if you get any errors or doubts.
I think the JQuery Arrive lib will solve your case.
I'm using an online ordering solution (white label solution) that only allows code edits via Google Tag Manager. I want to display a chat widget on the solution. Currently using LiveChat but want to change to MessageBird. Having problems with inserting code on single page app.
https://developers.messagebird.com/api/omnichannel-widget/
I've inserted the MessageBird Omnichannel widget via Google Tag Manager firing on all pages or history change (to allow for single page web app).
<script>
var MessageBirdChatWidgetSettings = {
widgetId: '37d411fb-b884-4342-a226-5c8aac703e44',
initializeOnLoad: true,
};
!function(){"use strict";if(Boolean(document.getElementById("live-chat-widget-script")))console.error("MessageBirdChatWidget: Snippet loaded twice on page");else{var e,t;window.MessageBirdChatWidget={},window.MessageBirdChatWidget.queue=[];for(var i=["init","setConfig","toggleChat","identify","hide","on","shutdown"],n=function(){var e=i[d];window.MessageBirdChatWidget[e]=function(){for(var t=arguments.length,i=new Array(t),n=0;n<t;n++)i[n]=arguments[n];window.MessageBirdChatWidget.queue.push([[e,i]])}},d=0;d<i.length;d++)n();var a=(null===(e=window)||void 0===e||null===(t=e.MessageBirdChatWidgetSettings)||void 0===t?void 0:t.widgetId)||"",o=function(){var e,t=document.createElement("script");t.type="text/javascript",t.src="https://livechat.messagebird.com/bootstrap.js?widgetId=".concat(a),t.async=!0,t.id="live-chat-widget-script";var i=document.getElementsByTagName("script")[0];null==i||null===(e=i.parentNode)||void 0===e||e.insertBefore(t,i)};"complete"===document.readyState?o():window.attachEvent?window.attachEvent("onload",o):window.addEventListener("load",o,!1)}}();
</script>
This works fine on our desktop version - where the widget loads to an area "off screen" to the bottom right but it causes problems on the mobile version - slowing down page loads and interfering with page elements and other tags firing via Google Tag Manager. I suspect the problem relates to our online ordering solution being a single page web app?
I walk through the problem here on video: https://www.loom.com/share/efacb3ebe89e49ceb7b5049da8a31a58
I was previously using LiveChat and also inserted the code via GTM (same triggers). This worked fine and I have this currently on the website.
<script type="text/javascript">
window.__lc = window.__lc || {};
window.__lc.license = 11857671;
(function() {
var lc = document.createElement('script'); lc.type = 'text/javascript'; lc.async = true;
lc.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'cdn.livechatinc.com/tracking.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(lc, s);
})();
</script>
<noscript>
Chat with us,
powered by LiveChat
</noscript>
<!-- End of LiveChat code -->
<script src="https://73b0e137397e4eceb870f14567b2e515.js.ubembed.com" async></script>
I have tried firing the MessageBird widget tag on only the main page, same problem. I have also tried not initializing the MessageBird widget, same problem.
I would appreciate any advice or suggestions.
My angularjs 1.5 application is running in an MS Dynamics 365 environment inside an iFrame on the actual page.
Anyway, it seems like that angularjs is waiting until all JS-operations from Dynamics, even outside the frame (script-loading etc.), have been finished and only then it's going to bootstrap the actual own app.
That causes many performance loading problems.
I understand that it could (not sure) be in angulars nature to wait for all scripts cause there could be something relevant for it's execution.
But if there are many other not relevant scripts on that page, it causes huge problems.
Is there a way to say "Hey angular! Wait for the scripts "jQuery.js, module1.js" etc." and then you are allowed to bootstrap because thats actually all what you need"?
Just to put the right facts in context, iframes are loaded asynchronously, which means immediately your page is loading it kicks off as well. Now, you can manually control the loading behavior of the iframe by deferring when its loaded into the DOM using a Javascript code that creates the iframe:
function createIframe() {
let iframe = document.createElement("iframe");
iframe.src = "<angularjs-app-url>";
iframe.scrolling = "auto";
iframe.frameborder = "0";
iframe.width = "200px";
iframe.height = "100px";
document.getElementById("div-that-holds-the-iframe").appendChild(iframe);
}
Then you can check if the JS files: jquery.js, module1.js are loaded before calling the createIframe() function:
window.onload = function() {
if (window.jquery && module1){
createIframe();
}
}
Create a script which load the iframe and then add the attribute defer in the call:
<script src="yourscrypt.js" defer></script>
See more in:
https://www.w3schools.com/tags/att_script_defer.asp
I'm in the process of building a new website for my wife's business, using Squarespace. Don't tell her, since it's one of her Christmas presents. :)
However, I'm experiencing a weird issue. About half of the pages on the site include content from a third-party widget called Healcode. Those pages have a strange jerkiness to them on pageload, where the logo and navbar move around -- ultimately winding up in the right spot, but looking bad while doing so. Pages that don't have a third-party widget don't have this jerkiness.
Example of page that jerks: https://coconditioning.squarespace.com/yoga-classes/
Example of page that doesn't jerk: https://coconditioning.squarespace.com/private-coaching/
The Healcode widget is javascript code that looks like this:
<script type="text/javascript">
healcode_widget_id = "ay12237c4nc";
healcode_widget_name = "schedules";
healcode_widget_type = "mb";
document.write(unescape("%3Cscript src='https://www.healcode.com/javascripts/hc_widget.js' type='text/javascript'%3E%3C/script%3E"));
// Healcode Schedule Widget for Conscious Conditioning L.L.C. : Weekly Schedule New
</script>
<noscript>Please enable Javascript in order to get HealCode functionality</noscript>
Any help would be MUCH appreciated. Thank you in advance!
You could hide the page until the body loads:
<body style = 'display: none'; />
And in your javascript, adding window.onload():
healcode_widget_id = "ay12237c4nc";
healcode_widget_name = "schedules";
healcode_widget_type = "mb";
document.write( unescape("%3Cscript src='https://www.healcode.com/javascripts/hc_widget.js' type='text/javascript'%3E%3C/script%3E"));
// Healcode Schedule Widget for Conscious Conditioning L.L.C. : Weekly Schedule New
window.onload = function()
{
document.body.style.display = 'block';
};
Also, is document.write() the best solution for you?
Don't try to use document.write if possible as with document.write JS parser doesn't know where to put it. at best, the browser will ignore it. at worst, it could write over the top of your current document. Use appendChild
function loadHealCodeScript () {
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://www.healcode.com/javascripts/hc_widget.js'
document.body.appendChild(script);
}
window.onload = loadHealCodeScript; // load healcode after page has been loaded
The jittering effect is happening because the healcode is loading its script before the page has completely loaded. If possible place all you javascripts after the body tag rather than head
As suggested by google also https://developers.google.com/maps/documentation/javascript/tutorial?hl=en#asynch
I want to give a minimal js code to random websites so that they can add a widget.
The code needs to run after the main page loads and include a parameter with the domain name. ( I don't want to hardcode it)
One option is to add this code just before the </body> (so It will run after the page loads):
<script type="text/javascript" id="widget_script">
document.getElementById('widget_script').src=location.protocol.toLowerCase()+"//mywebsite.com/?u="+encodeURIComponent(window.location.host);
</script>
This works in IE but not in Firefox. I see with Firebug that the src property is created correctly but the script from my site is not loaded.
My question is : what is the best way to do that ? (preferably by putting minimal lines on the header part.)
To further clarify the question: If I put a script on the header part, how do I make it run after it is loaded and the main page is loaded? If I use onload event in my script I may miss it because it may load after the onload event was fired.
You can try to statically include the script with document.write (is an older technique and not recommended to use as it can cause problems with more modern libraries):
var url = location.protocol.toLowerCase() +
"//mywebsite.com/?u="+encodeURIComponent(window.location.host);
document.write('<script src="', url, '" type="text/javascript"><\/script>');
Or with dynamically created DOM element:
var dynamicInclude = document.createElement("script");
dynamicInclude.src = url;
dynamicInclude.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(dynamicInclude);
Later edit:
To ensure the script is run after onload this can be used:
var oldWindowOnload = window.onload;
window.onload = function() {
oldWindowOnload();
var url = location.protocol.toLowerCase() +
"//mywebsite.com/?u="+encodeURIComponent(window.location.host);
var dynamicInclude = document.createElement("script");
dynamicInclude.src = url;
dynamicInclude.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(dynamicInclude);
}
I do not believe it can be shorter than this, apart from shorter variable names :)
Why not use the getScript method of jQuery to do the loading? If you don't want to be dependant on jQuery, you can trace through the source to learn how they tackled it.
Viewing a widely used library is always going to show you solutions to problems you didn't know you had. For example, you can see how jQuery manages to generate a callback when the script is loaded, and how it avoids a purported memory leak in IE.
You probably want to be implementing the non-blocking script technique. Essentially instead of modifying the src of a script, you're going to create and append a whole new script element.
Good write up here and there are standard ways to do this in YUI and jQuery. It's quite straightforward with only one gotcha which is well understood (and documented at that link).
Oh and this:
One option is to add this code just
before the </body> (so It will run
after the page loads):
...is not technically true: you're just making your script the last thing in the loading order.