0

I am using the loadOnReady="true" attribute of <apex:includeScript /> to defer loading of scripts till DOM rendering is complete.

Here's my VF page skeleton:

<apex:page doctype="html-5.0"
           applyHtmlTag="false"
           applyBodyTag="false"
           showHeader="false"
           sidebar="false"
           standardStylesheets="false"
           cache="false"
           id="example"
           title="Example Title"
           Controller="exampleController">

    <html>

    <head>
    
        <apex:stylesheet value="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.css')}"/>
    
    </head>
    
    <body>
    
        ....
        ......
        
        <!-- Just before BODY closing tag-->
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.jQuery3,'/jquery-3.5.1.slim.min.js')}"/>
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.PopperJS2,'/popper.min.js')}"/>
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.js')}"/>        
    
    </body>
    
    </html>
    
</apex:page>

This has a strange effect on the code of the rendered page. The inclusion of scripts is actually happening AFTER the closing HTML tag - which is semantically incorrect!!!

When I inspect the source of the rendered page, I see:

    </body>
    </html><script type="text/javascript">Sfdc.onReady(function(){
Sfdc.Resource.addJavaScripts(['/resource/****20000/jQuery3/jquery-3.5.1.slim.min.js','/resource/****19000/PopperJS2/popper.min.js','/resource/****14000/Bootstrap4/bootstrap.min.js']); SfdcApp && SfdcApp.Visualforce && SfdcApp.Visualforce.VSManager && SfdcApp.Visualforce.VSManager.vfPrepareForms(["loginPage:siteLogin:loginComponent:loginForm"]);

});</script>

Following @sfdcfox's comments I replaced <apex:stylesheet /> and <apex:includeScript /> with vanilla HTML tags. At least these resources moved back into the correct location inside the tags. However, SF still keeps outputting sections of scripts and stylesheets both before and after the body tags.

The current output stands at:

<!DOCTYPE HTML>
<head><script src="/static/111213/js/perf/stub.js" type="text/javascript"></script><script src="/faces/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript?rel=1597694166000" type="text/javascript"></script><script src="/static/111213/js/functions.js" type="text/javascript"></script><script src="/jslibrary/1595625414226/sfdc/main.js" type="text/javascript"></script><script src="/jslibrary/jslabels/1597696824000/en_US.js" type="text/javascript"></script><script src="/static/111213/desktop/desktopAjax.js" type="text/javascript"></script><script src="/static/111213/js/picklist4.js" type="text/javascript"></script><script src="/resource/1478908878000/jquery310min" type="text/javascript"></script><script src="/jslibrary/1586381828226/sfdc/VFState.js" type="text/javascript"></script><script src="/jslibrary/1589998732226/sfdc/NetworkTracking.js" type="text/javascript"></script><script>try{ NetworkTracking.init('/_ui/networks/tracking/NetworkTrackingServlet', 'network', '06641000001OIbR'); }catch(x){}try{ NetworkTracking.logPageView();}catch(x){}</script><script>(function(UITheme) {
    UITheme.getUITheme = function() { 
        return UserContext.uiTheme;
    };
}(window.UITheme = window.UITheme || {}));</script></head><span id="j_id0:j_id1"></span>

    <html>
    <head>
<meta HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE" />
<meta HTTP-EQUIV="Expires" content="Mon, 01 Jan 1990 12:00:00 GMT" />

        <meta content="width=device-width, initial-scale=1.0" name="viewport" />
        
        <link href="/resource/****16000/FontAwesome4/font-awesome-4.7.0/css/font-awesome.css" rel="stylesheet" />
        <link href="/resource/****31000/Bootstrap4/bootstrap-4.5.2-dist/css/bootstrap.min.css" rel="stylesheet" />
        <link href="/resource/****13000/AcadResources/InstApp.css" rel="stylesheet" />
        ....
        ........
    </head>
    
    <body>
    
        ...........
        ..............
        
        <script src="/resource/****44000/jQuery3/jquery-3.5.1.slim.min.js"></script>
        <script src="/resource/****58000/PopperJS2/popper.min.js"></script>
        <script src="/resource/****31000/Bootstrap4/bootstrap-4.5.2-dist/js/bootstrap.min.js"></script>     
        
    </body>
    </html><script type="text/javascript">Sfdc.onReady(function(){
    SfdcApp && SfdcApp.Visualforce && SfdcApp.Visualforce.VSManager && SfdcApp.Visualforce.VSManager.vfPrepareForms(["j_id0:j_id9"]);

});</script>

Just can't figure out what's causing the output of the extra <head> section BEFORE the <html> tag and likewise the additional tags after </html>.

Where am I going wrong?

Thank you.

1
  • This is working fine in my org. Maybe there is some other code in your page that is interfering with this. Commented Aug 18, 2020 at 7:27

1 Answer 1

1

You shouldn't mix applyHtmlTag=false and apex:includeScript. I can imagine how bad things could happen if you do this. Either use a normal script tag, or use default HTML generation (applyHtmlTag=true).

This should fix your current problem:

<head>
    <link rel="stylesheet" href="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.css')}"/>
    <script defer src="{!URLFOR($Resource.jQuery3,'/jquery-3.5.1.slim.min.js')}">
    </script>
    <script defer src="{!URLFOR($Resource.PopperJS2,'/popper.min.js')}">
    </script>
    <script defer value="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.js')}">
    </script>
</head>

Or, simply using default HTML generation should work:

<apex:page doctype="html-5.0"
           showHeader="false"
           sidebar="false"
           standardStylesheets="false"
           cache="false"
           id="example"
           title="Example Title"
           Controller="exampleController">
        <apex:stylesheet value="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.css')}"/>
        <!-- Just before BODY closing tag-->
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.jQuery3,'/jquery-3.5.1.slim.min.js')}"/>
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.PopperJS2,'/popper.min.js')}"/>
        <apex:includeScript loadOnReady="true" value="{!URLFOR($Resource.Bootstrap4,'/bootstrap.min.js')}"/>        
</apex:page>
3
  • Thank you VERY MUCH @sfdcfox. That definitely alleviated part of the problem. Now the stylesheets and scripts are back in their desired locations. However, SFDC still continues to output strange head and script sections before and after the HTML tags. I've updated my question with the most recent output at the bottom part. Any thoughts. Commented Aug 18, 2020 at 13:56
  • @miCRoSCoPiC_eaRthLinG I see you're insisting on applyHtmlTag=false. I believe that's causing the core issue, as far as I can tell. Also, note the use of the defer attribute to align with loadOnReady=true. Try using the latter design, as I suggested. I'll look and see if I can replicate the script-after-html problem and get back to you.
    – sfdcfox
    Commented Aug 18, 2020 at 14:22
  • Thank you very much for your help - much appreciated. I found a couple of resources that suggested applyHtmlTag=true increases the processing time and hence negatively affects page rendering time. I am perhaps a bit old-school and would like more control over the layout - hence trying to do it the hard way. Defer attribute is now included. Thanks for pointing that out :D Commented Aug 19, 2020 at 4:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .