I'm currently working on improving one of our sites PageSpeed insights score, at the moment we're hovering around 90
, we'd like to break into the mid 90's if possible.
One of the sticking points we have is that the Ajax toolkit script manager is generating its script at the top of the page, google flags this as a "should fix" issue and is complaining that the script is render blocking and should be moved to the bottom of the page or loaded asychronously or via the defer
attribute.
I'm using the following to combine our scripts into one .js
file to minimize requests:
<ajaxToolkit:ToolkitScriptManager ID="manScript" LoadScriptsBeforeUI="false" runat="server" EnableViewState="false" ScriptMode="Release">
<CompositeScript ScriptMode="Release" Path="/CMSGlobalFiles/Js/combinedajax.min.js">
<Scripts>
<asp:ScriptReference Name="WebForms.js" Path="/CMSGlobalFiles/Js/aspnet/WebForms.js" Assembly="System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<asp:ScriptReference Name="MicrosoftAjax.js" Path="/CMSGlobalFiles/Js/aspnet/MicrosoftAjax.js" />
<asp:ScriptReference Name="MicrosoftAjaxWebForms.js" Path="/CMSGlobalFiles/Js/aspnet/MicrosoftAjaxWebForms.js" />
</Scripts>
</CompositeScript>
</ajaxToolkit:ToolkitScriptManager>
Is there a way to set either defer
or async
on the CompositeScript
tag that gets output? Or any other way of moving this to the bottom of the page?
I've tried the following:
protected override void Render(HtmlTextWriter writer)
{
StringWriter output = new StringWriter();
base.Render(new HtmlTextWriter(output));
string outputAsString = output.ToString();
if(outputAsString.Contains("<script src=\"/CMSGlobalFiles/Js/combinedajax.min.js\" type=\"text/javascript\"></script>"))
{
outputAsString = outputAsString.Replace("<script src=\"/CMSGlobalFiles/Js/combinedajax.min.js\" type=\"text/javascript\"></script>", string.Empty);
}
writer.Write(outputAsString);
}
And then manually including a reference to the script at the bottom of the page:
<script type="text/javascript">
function downloadJSAtOnload() {
createScript("/CMSGlobalFiles/Js/combinedajax.min.js?v=1");
createScript("//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js");
createScript("/cmsglobalfiles/js/vendor/modernizr.js");
createScript("/cmsglobalfiles/js/main.min.js");
createScript("/cmsglobalfiles/js/vendor/wow.min.js");
}
function createScript(path) {
var element = document.createElement("script");
element.src = path;
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
This removes the generated composite script and creates a new one before the closing body tag, this brings our score up to 95
but I think this is loaded too late as we're getting a lot of console errors:
ReferenceError: Sys is not defined
WebForm_InitCallback is not defined
Which indicates the script manager is broken, is there a way to achieve this at all?