Asynchronous load of JavaScript

Has anyone here tested JavaScript loading asynchronously in Plone? I'm using XSLT + Xpath in the Diazo rule and have success with transform to HTML, but, does not has load in correct order.

For eg, The JQuery library are load after all JavaScript's, causing an error with the others load.

Code Snippet:

<?xml version="1.0" encoding="UTF-8"?>
<rules
    xmlns="http://namespaces.plone.org/diazo"
    xmlns:css="http://namespaces.plone.org/diazo/css"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:esi="http://www.edge-delivery.org/esi/1.0"
    xmlns:str="http://exslt.org/strings"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <theme href="index.html" css:if-content="#visual-portal-wrapper" />

    <xsl:template match="//script[contains(@type, 'text/javascript')]">
        <xsl:copy>
            <xsl:attribute name="async">true</xsl:attribute>
            <xsl:copy-of select="@*" />
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

     ...

I think making use of require js will sofve that issue.

Hi, Cleber! Not much experience with async but I think you should probably exclude jQuery and other harder dependencies from using it, since you can't make sure in which order they will be loaded and executed. Also I'd remove the type=text/javascript part since on HTML5 it's not required and might eventually get some of your scripts dropped. So I'd change first line to:

<xsl:template css:match="script:not([src*=jquery])">

Or something more specific, like:

<xsl:template css:match="script:not([src*=resourceplone.app.jquery])">

If css:match does not work I think the XSLT version would be:

<xsl:template css:match="//script[@src[not(contains(., 'resourceplone.app.jquery'))]]">

Or:

<xsl:template css:match="//script[not(contains(@src, 'resourceplone.app.jquery'))]">

Abs, mano :slight_smile:

Hi "MANO", cool, good idea, I'll test and any news I inform :wink: tks

1 Like

why are you using Diazo for that? if you want your script to load after jQuery place it after jQuery or, better, at the bottom of the page.

check the attributes of the script tag:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

and note the following:

  • don't use async for inline scripts
  • dynamically inserted scripts execute asynchronously by default

Do you have success doing this with portal_javascript of Plone? Can you share a preview of configuration so I can take it as a basis?

Using as below I had the expected result.

<xsl:template match="//script[(contains(@type, 'text/javascript') or contains(@type,'application/javascript')) and not(contains(@src, 'jquery
    <xsl:copy>
        <xsl:attribute name="async">true</xsl:attribute>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

mmm, I think now I understand (and that's why is always better to give a small background on you use case and explain what are you trying to do and why are you trying to do it, instead of how are you trying to do it):

you're using Plone 4 and you want to execute a script registered globally in the resource registry asynchronously, right?

well, I think you can't do that besides hacking the HTML like you're doing using Diazo.

IIRC, Plone's resource registry predates the async attribute in HTML5.

the good news is I have an alternate solution for you: install collective.blueline and add manually your <script> tag in one of the available viewlets.

you can even place it in the footer, for best results.

Cleber, avoid checking for type. In HTML5 it's optional so you risk losing some scripts by being so specific. Cheers!