Disclosure
This is aimed as a guide to add scripts or styles to the <head>
tag of websites that you host and do not have access to the source or do not want to monkey patch source.
Additional note, you can ride on the free tier of CloudFlares service workers if you do not serve more than 100k requests on your foundry instance /join
route.
Introduction
In this example, we will be creating a service worker on CloudFlare which gives us the option to inject a <link>
element into the <head>
element of a websites served HTML. For the example, we will be inject a style sheet into the <head>
to change the appearance of FoundryVTT.
The link we will be applying is the style effects from Foundry VTT Prettier Login Screen by TheEpicSnowWolf.
Requirements
- CloudFlare domain, or sub-domain, pointing to your FoundryVTT instance.
- A hosted FoundryVTT instance that can be served by your domain or sub-domain.
- Minimal knowledge of JavaScript.
Steps
1). Open CloudFlare and Login.
2). (If you have multiple domains) Use the drop down or the cards to select the domain your foundry instance is hosted on.
3). Click the Workers tab at the top:
4). On the Workers page, click Manage Workers
5). On the Manage Workers page, click Create a Worker
6). In the script section, lets create an element handler:
class ElementHandler {
element(element) {
element.append(`<link
rel="stylesheet"
type="text/css"
data-id="foundry-login"
href="https://cdn.jsdelivr.net/gh/TheEpicSnowWolf/Foundry-VTT-Prettier-Login-Screen@main/foundry_login.css"
>`, {html: true});
console.log("injected");
}
}
This element handler, will consume the <head>
element on the HTML dom and append a link to the foundry_login.css
script found in the Foundry VTT Prettier Login Screen repository by TheEpicSnowWolf.
7). Next lets add a handle request function:
async function handleRequest(req) {
const res = await fetch(req)
if (res.url.includes('example.com/join')) {
return new HTMLRewriter().on("head", new ElementHandler()).transform(res)
}
return res;
}
This function is designed to take the request, process the request, and check if the URL itself matches the /join
route. In the script above, replace the example.com
with your domain or sub-domain.domian.tld
(ex dnd.example.com
)
8). After that, add the event listener to hook into the worker API:
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
9). Click the Save and Deploy button:
10). With the script saved, click the script name in the upper right hand corner:
11). On the workers configuration page, uncheck the box that says Workers.dev route
12). Use the drop down menu in the upper right hand corner to select your domain name.
13). Click the Workers tab again
14). This time, click the Add Route button.
15). In the Add Route screen, change the Route to be example.com
or sub-domain.domian.tld
with a trailing /join
if you are doing this for foundry.
16). In the Worker drop down, select the new worker you created:
17). Click the save button:
18). Finally, visit your website where the service worker is attached ❤️
Conclusion
This is incredibly useful for sites where you do not want to monkey with the code and instead inject other scripts. It can be used for Analytics, Authentication, and much more. The possibilities are endless! 😄
Source Code
Source code for service worker: Foundry VTT Service Worker
Shoutouts
Credit to @TheEpicSnowWolf on GitHub for putting together the CSS in the repository Foundry VTT Prettier Login Screen
Credit to Derek Johnson on StackOverflow for the original code snippet in their StackOverflow question "Inject HTML with Cloudflare worker"
Top comments (0)