Embedding Compressed Unity WebGL Builds on Ghost CMS
Today I explore the steps required to embed and host a Unity WebGL build within a static Ghost CMS page using gzip compression.
Prerequisites
- A WebGL Build of your game out of Unity using the default gzip compression algorithm
- A custom theme (or a way to alter your theme)
- A way to ssh into your server and edit your nginx configuration (so probably a self-hosted solution...)
The Problem
Games are really big, especially by internet standards, where we want to be transmitting as little "across the wire" as possible. Therefore engines such as Unity try to help us out by compressing the archives we need to run the game. This compression means smaller file sizes to download. It can also mean faster load times IF we set up our web server correctly. Otherwise we can't take advantage of the browser downloading the gzipped package while it is also extracting it.
Despite this not being an overly complex problem to solve there are a few Ghost specific stumbling blocks that can make what should be a five minute task take three days. In addition to the Ghost specific problems Unity also does not supply configuration steps for nginx so I can save you some Googling, as I have already done it for you.
The Solution
There are two major steps to getting our WebGL build working. The first is to get it on the site. The second is to get it served properly, let's take this one step at a time.
Embedding the Content
As discussed above I am going to assume you already have a Unity WebGL build ready to go, if you haven't go do that first then come back. (Please come back 🙏)
From here how you put it in your theme is up to you (and how much freedom your theme provider gives you). We can use my side project "The Interview" as an example which uses a custom page template as described in the Ghost Documentation. You will notice I am following the page-slug
notation in my theme.
With your page template set up and being correctly routed to you now need to do two things:
- Move the Build and TemplateData folders into your asset folders. The exact location will vary depending on how you layout your theme. I keep mine in a Projects sub-folder. While you're in your file explorer head into the Build folder and change your
NameOfGame.json
file toNameOfGame.txt
...trust me you'll need this later. - Open the
index.html
file generated by Unity and paste the contents into your custom page template in your theme. Feel free to remove any content you don't think will be relevant for your page. I have removed the title and the option to full screen my project.
The only content you really need here are thelink
tag for the style sheet, the fourscript
tags to reference the relevant content and the divs that contains thewebgl-content
class and theunityContainer
id. - You need to update the links in your
link
andscript
tags accordingly because they will no longer be found in the same location as the Unity build has them sitting right now. - Again we can follow along with the Ghost Documentation and use the asset helper syntax to properly reference the new location of these files (again for me this is under a sub-folder called projects.
E.g. it might now look like{{asset "js/projects/interview/Build/UnityLoader.js"}}
- The last script tag is a little more complicated because we can't seem to use the asset helper from within JavaScript land so I had to create a reference relative to the assets folder.
E.g. it might now look likevar unityInstance = UnityLoader.instantiate("unityContainer", "/assets/js/projects/interview/Build/Interview.txt", {onProgress: UnityProgress});
Now here is something really important to note so I am going to bold the following. When changing the URL for this part to be relative to the assets folder also change the extension to .txt
from .json
to match the change we made in step 1.
We only need to do the step above because if we do not then we will get a 404 on the file even though its path is valid. It took a lot of Googling and I stumbled across the answer by accident but Ghost blacklists all json files from being served to prevent accidentally leaking configuration. With that in mind and knowing there is nothing sensitive in the file we can change the extension to ignore the blacklist.
With the above complete you should see your files embedded on your local install (which I always recommend you do when testing your themes). If you have, congratulations you are half way there!
Serving the Content Properly
Go ahead and upload your new theme if you haven't already. Check your site and revel in your skills as the Unity WebGL appears before you, really, really slowly. If you open the Developer Console for your given browser (normally F12, but Google it if you are unsure) you're likely to see the warning You can reduce your startup time if you configure your web server to host .unityweb files using gzip compression.
This is what we will fix now.
- As mentioned up front you will need to be able to go in and edit your nginx install. Depending on how you're self hosting (or who your host is) will depend how that works. If you're unsure hit me up on Twitter.
- If you are running a Digital Ocean 1-Click installer like I am you can find the file at
/etc/nginx/sites-enabled/your-site.conf
. In my particular case (because I run my site over https) I had to edit/etc/nginx/sites-enabled/scott.cab-ssl.conf
. Below the.well-known
block you can add the following code snippet.#Serve .unityweb files properly as being gzipped. You need to set the root to the theme folder or it fails? #Location regex from https://stackoverflow.com/questions/57006129/nginx-setup-for-unityweb location ~ .+\.unityweb$ { root /var/www/ghost/content/themes/your-theme-name; add_header Content-Encoding gzip; }
- Be careful to change the last part of your
root
property to match the name of your theme. - Once the file is saved restart nginx, for me using Ubuntu it's as simple as
sudo systemctl restart nginx
. - Check out your console after refreshing the page and you should be done.
One quick note here is that the default mime type applied to files that is does not know about on the 1-Click install for Digital Ocean is application/octet-stream
which is what we want to serve in this case. If your nginx configuration is different you can either edit the mime.types
file to set .unityweb
files to be of type application/octet-stream
or you can add the header Content-Type
in the location block described above if you like.
Conclusion
A few tricky steps but that's mostly just getting down to be familiar with how a Ghost theme is composed and where to look for files. Additionally the 1-Click setup on DO is done to take into account SSL an other factors which is why the default advice to add the location block by itself doesn't work without the added root
property.
In future if you want to showcase more of your work you will only need to copy across the appropriate assets and make a new page. The nginx configuration will handle all .unityweb
files site-wide as long as your theme name remains unchanged. If you do change the name of your theme you might want to go update nginx root just to take advantage of the gzip decompression.