I’m trying to embed a Twitch stream in a dynamic based web app, think React. The Twitch Embed Everything doc give the example of adding the following to your <body>
<!-- Load the Twitch embed JavaScript file -->
<script src="https://embed.twitch.tv/embed/v1.js"></script>
And this works fine at the top of my app. However, I don’t want to load the Twitch JS library for every client if they don’t need it.
So I’m trying to dynamically load the above script by triggering a flag that then loads. The problem is all the dynamic methods of loading successfully load the script and I can see it in my Developer Tools → Sources tab in Chrome, but window.Twitch
never gets set and is undefined
.
I’ve tried loading it with a jquery ajax call:
$.getCachedScript("https://embed.twitch.tv/embed/v1.js")
.done(function() {
// window.Twitch returns undefined even after waiting
)}
I’ve tried loading it by building a <script>
element and adding it to the <body>
or <head>
elements:
let script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://embed.twitch.tv/embed/v1.js";
$("head").append(script);
I’ve even added a listener for the load
event on the script
object and the script successfully loads. I just cannot access window.Twitch
anywhere.
Why does the script only work if it’s hard-coded into the <body>
or <head>
?
After spending two days, I figured this out no later than 20 minutes after posting this. Maybe this will help someone else with this problem.
The issue is the Twitch code has this line at the top that tries to detect its environment and how it will make Twitch
(which is t()
) available:
"object" == typeof exports && "object" == typeof module ? module.exports = t() : "function" == typeof define && define.amd ? define([], t) : "object" == typeof exports ? exports.Twitch = t() : e.Twitch = t()
Upon using a little Github Copilot to break that down, the script detects exports
and module
in my Meteor application and then sets module.exports = t()
which sets Twitch
as an export of this module. It never makes it to last else
of the inline if
which is e.Twitch = t()
which would set Twitch
into the global window
object. So that’s why window.Twitch
is never set.
After figuring this out, it was a matter if finding where the script’s exports
are at. Logging modules
after the $.getScript(...)
success showed that Twitch
was inside of modules.parent.parent.exports
which ended up being the client entry point JS file of my Meteor app.
So in the .done
callback of $.getScript(...)
I needed to do:
// Access the set export from the Twitch Embed script
const { Twitch } = require("/client/main.js");
// Set the Twitch object to the window for the rest of the app to use as normal
window.Twitch = Twitch;
Dynamically loading the Twitch Embed JS library with no source modifications.