nfl / react-helmet

A document head manager for React
MIT License
17.28k stars 657 forks source link

Ensure asynchronous loading of files and execution of functions #545

Open chengtie opened 4 years ago

chengtie commented 4 years ago

I'm taking over a website by V2 Docusaurus.

One particularity of our website is that we need to load office.js and css-vars-ponyfill.min.js, and run some functions in patches.js in the very beginning. So the previous developer decided to use the following approach.

In every .mdx.md page, he wrapped the content by a component MainWrapper:

<MainWrapper>
    ... ...
    Real content
    ... ...
</MainWrapper>

MainWrapper/index.js is defined as follows

import React from 'react';
import Head from '@docusaurus/Head';

function MainWrapper(props) {
    return (<>
        <Head>
            <script
                src="/lib/patches.js" 
                onload="(function(){console.log('patches.js has been fully loaded')}).call(this)" >
            </script>
            <script async defer 
                src='https://unpkg.com/css-vars-ponyfill@2/dist/css-vars-ponyfill.min.js'
                onload="(function(){console.log('css-vars-ponyfill.min.js has been fully loaded'); onCssVarsPonyfillLoad();}).call(this)">
            </script>
            <script async defer 
                src='https://appsforoffice.microsoft.com/lib/1/hosted/office.js'
                onload="(function(){console.log('office.js has been fully loaded'); onOfficejsLoad();}).call(this)">
            </script>
        </Head>
        {props.children}
    </>)
}

export default MainWrapper;

lib/Patches.js contains real operations:

var pushStateRef = history.pushState;
var replaceStateRef = history.replaceState;

console.log("already inside patches.js")
console.log("history.pushSate and replaceState have been saved")

function patch() {
    if (!history.pushState) {
        history.pushState = pushStateRef;
        history.replaceState = replaceStateRef;
        console.log("history.pushState and replaceState have been set back")
    };
}

... ...

function onCssVarsPonyfillLoad() {
    console.log("already inside patches.js > onCssVarsPonyfillLoad()")
    ... ...
}

function onOfficejsLoad() {
    Office.onReady(function () {
        console.log("already inside Office.onReady");
        patch();
    })
}

My tests show that, sometimes, this implementation can ensure loading patches.js before office.js and css-vars-ponyfill.min.js as <script async defer do. However, sometimes, this order cannot be ensured:

enter image description here

@docusarus/Head uses react-helmet. Does anyone know how to fix this loading order problem? What I want is loading patches.js before anything else, is there any workaround?

Kurt-von-Laven commented 3 years ago

As a workaround, have you already tried using react-helmet-async?