Reputation: 5540
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 do some operations 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
function MainWrapper(props) {
return (<>
<Head>
<script defer
src="https://www.10studio.tech/lib/patches.js"
onload="(function(){console.log('patches.js fully loaded MainWrapper')}).call(this)" >
</script>
</Head>
<CssvarsWrapper></CssvarsWrapper>
<OfficejsWrapper></OfficejsWrapper>
{props.children}
</>)
}
export default MainWrapper;
CssvarsWrapper/index.js
is defined as follows
function CssvarsWrapper(props) {
return (<>
<Head>
<script defer
src="https://www.10studio.tech/lib/patches.js"
onload="(function(){console.log('patches.js fully loaded in CssvarsWrapper')}).call(this)">
</script>
{console.log("CssvarsWrapper > index.js > CssvarsWrapper")}
<script defer
src="https://unpkg.com/css-vars-ponyfill@2/dist/css-vars-ponyfill.min.js"
onload="(function(){console.log('css-vars-ponyfill.min.js fully loaded in CssvarsWrapper'); onCssVarsPonyfillLoad()}).call(this) ">
</script>
</Head>
{props.children}
</>)
}
OfficejsWrapper/index.js
is defined as follows
function OfficeWrapper(props) {
return (
<>
<Head>
<script defer
src="https://www.10studio.tech/lib/patches.js"
onload="(function(){console.log('patches.js fully loaded in OfficeWrapper')}).call(this)">
</script>
{console.log("OfficejsWrapper > index.js > OfficeWrapper")}
<script defer
src='https://appsforoffice.microsoft.com/lib/1/hosted/office.js'
onload="(function(){console.log('office.js fully loaded in OfficeWrapper'); onOfficejsLoad()}).call(this) ">
</script>
</Head>
{props.children}
</>
)
}
lib/Patches.js
contains real operations:
console.log("in patches")
... ...
function onCssVarsPonyfillLoad() {
console.log("patches.js > onCssVarsPonyfillLoad()")
cssVars({
onlyLegacy: false,
onComplete: function (cssText, styleElms, cssVariables, benchmark) {
}
});
}
function onOfficejsLoad() {
Office.onReady(function () {
console.log("office.js is ready.");
patch();
})
}
However, my test showed that this implementation cannot always respect a correct order of loading of files, regardless of the defer
tag. For example, as the following screenshot shows, css-vars-ponyfill.min.js fully loaded in CssvarsWrapper
and office.js fully loaded in OfficeWrapper
were before patches.js fully loaded
, as a consequence onCssVarsPonyfillLoad
and onOfficejsLoad
were not ready when they were called.
Actually, we should ensure that patches.js
is always loaded before css-vars-ponyfill.min.js
and office.js
. Does anyone know how to ensure that?
Additionally, is this approach (i.e., wrapping a component around content of every page to do some operations upstream) correct?
Upvotes: 1
Views: 230
Reputation: 37318
The way the previous developer decided to implement this loads scripts multiple times and particular it loads patches.js
more than once.
I suggest you try to ditch this implementation and use Docusaurus scripts-array
inside docusaurus.config.js
to define these scripts and use defer
on office.js
and css-vars-ponyfill.min.js
and define the onload
script for each script there. That's the proper way to load external (and internal like patches.js
) scripts in Docusaurus.
docusaurus.config.js
:module.exports = {
...
scripts: [
{
src: '/lib/patches.js'
},
{
src: 'https://appsforoffice.microsoft.com/lib/1/hosted/office.js',
defer: true,
onload: "(() => { console.log('office.js loaded'); onOfficejsLoad(); })()"
},
{
src: 'https://unpkg.com/css-vars-ponyfill@2/dist/css-vars-ponyfill.min.js',
defer: true,
onload: "(() => { console.log('css-vars-ponyfill.min.js loaded'); onCssVarsPonyfillLoad(); })()"
}
],
}
We use defer
on these two scripts and that means that the scripts will be executed and loaded after the document has been parsed, but before firing DOMContentLoaded
.
Trying this on a local Docusaurus project I got the scripts loading on the expected order every single time after clearing the cache:
in patches
office.js loaded
patches.js > onCssVarsPonyfillLoad()
css-vars-ponyfill.min.js loaded
patches.js > onCssVarsPonyfillLoad()
cssVars:onComplete
office.js is ready.
using this patches.js
file:
console.log("in patches")
function onCssVarsPonyfillLoad() {
console.log("patches.js > onCssVarsPonyfillLoad()");
cssVars({
onlyLegacy: false,
onComplete: function (cssText, styleElms, cssVariables, benchmark) {
console.log('cssVars:onComplete');
}
});
}
function onOfficejsLoad() {
console.log("patches.js > onCssVarsPonyfillLoad()");
Office.onReady(function () {
console.log("office.js is ready.");
// patch();
})
}
Upvotes: 1
Reputation: 2472
TLDR;
You need to add to add defer
to your <script>
tag if you want your scripts to be executed in order.
You can read more about it here: https://www.w3schools.com/tags/att_script_defer.asp
A bit longer version
I want to highlight few things over your implementation though
You are working in a virtual DOM env, your components might mount/unmount depending over many use cases. I would never recommend any one loading files like this:
<script
src="/lib/patches.js"
onload="(function(){console.log('patches.js fully loaded 1')}).call(this)">
</script>
Instead I would recommend defining the methods in a single file and export it so I can just use any method I want to use within my app. This will not just kill the loading of file each time your component is mounted but also improve the efficiency and execution.
This approach is rather called modular approach. Check this out https://stackoverflow.com/a/49616670/1681154 and if you want to read more about modular approach, I found a good explanation here: https://javascript.info/import-export.
If you can't afford to break down the modules but rather want to use the approach you are currently using, you need to use defer
to ensure script is executed in the same order it is defined.
Upvotes: 0