Search code examples
javascriptgatsbyhelmet.js

Gatsby site, Script not available on first page request with Helmet


I have a Gatsby site that I'm trying to add a third-party js widget to but for some strange reason it will only load if I refresh the page manually. On first page load, it as is if it doesn't exist at all, no errors in dev-tools, nothing... but if I refresh the page, it then appears. It's almost as if it's lazy loading? Is there a way to force load?

I've checked the elements, console, and network tabs in dev tools but there's nothing to indicate any errors. elements shows the tags that I would expect, console shows nothing at all, and network everything shows up with 200.

Could this be an issue with Gatsby and/or Helmet, it might be but I don't think it's an issue with the widget itself (it's third-party, I have no control over it, see last paragraph)?

<Helmet
    script={[
        {
            type: 'text/javascript',
            src: '//widget-url.com/path/to/jsfile.min.js',
        },
        {
            type: 'text/javascript',
            innerHTML: `
               (function() {
                   var widget = Stuff.happens.here();
                   widget.Initialise();
                })();
            `,
        },
    ]}
/>

In the body I then have:

<div id='widget-id'></div>

Things I've tried to attempt to understand where the issue is:

  • As I mentioned, I have to force refresh the page where the widget is located. If I force refresh any other page, it doesn't help. So something I tried is: rather than only including the JS into the head of the page in question, I would including it on ALL pages. But this has made no difference.

  • I've also tried adding the widget to a simple stand-alone html file, the widget loads without problem. Which leads me to think that it's probably not a widget issue?

I don't know where to go from here :(


Solution

  • The problem is that you are pointing a DOM element that may or may not be rendered at the moment your request the script.

    In your case, I'd try:

    <Helmet>
        <script async defer src="//widget-url.com/path/to/jsfile.min.js" />
        <script async defer>
         {`
          (function() {
              var widget = Stuff.happens.here();
               widget.Initialise();
             })();   
          `}
        </script>
    </Helmet>
    

    Or using one of the multiple Server-Side Rendering APIs. onRenderBody should work:

    // gatsby-ssr.js
    import React from "react"
    export const onRenderBody = ({ setHeadComponents, setPostBodyComponents }) => {
      setHeadComponents([
        <script 
          src="//widget-url.com/path/to/jsfile.min.js"
          type="text/javascript"
          async
        />,
        <script
          dangerouslySetInnerHTML={{
          __html: `
            (function() {
             var widget = Stuff.happens.here();
              widget.Initialise();
            })();   
         `,
        }}
       />, 
     ])
    }