🕸 Immutable Web Apps
Immutable Web Apps is a philosophy born from the Docker mindset of build it once, but deploy it many times. Deploying a Docker Image means providing any required environment variables needed for the code in that image to function properly. That mindset can also be applied to deploying web applications.
Separating the configuration from the business logic provides a much more stable artifact for testing. This means the assets for our business logic are built once for all environments, yielding our staging environment business logic being identical to our production environment. Minimizing our changes between staging and production will also limit where a particular defect could be occurring.
This can be accomplished by utilizing the globalThis or window objects in the browser to store namespaced configuration for our deployable assets. This gives us the “environment” equivalent to our Docker deployments.
The other major benefit here is caching. Immutable build artifacts mean that we can deliver our code to the browser with extremely long cache headers because the artifacts will never change. This yields huge benefits for returning users as well as rollbacks.
For a deeper dive on Immutable Web Apps we have an in-depth blog post covering all the details.
🚀 Simplifying immutable deployments
Now that we know about the IWA philosophy and a bit about npm, let’s bring these two things together to make deploying our apps as simple as we can.
If you’re unfamiliar with npm, the documentation is a great place to start learning!
The IWA philosophy means that we have well versioned artifacts that our
index.html file will rely upon during deployment. Luckily for us there are services out there that can take an npm package and make it available for use in your applications! Unpkg hosts all public npm packages in a “ready for script tag” manner. This means that if I want to use a specific version of react, I could simply use the following script tag:
<script src="https://firstname.lastname@example.org/umd/react.production.min.js" integrity="sha384-bDWFfmoLfqL0ZuPgUiUz3ekiv8NyiuJrrk1wGblri8Nut8UVD6mj7vXhjnenE9vy"></script>
index.html file for our application!
🔐Aside on the integrity attribute
integrity attribute is there to ensure that the contents of the referenced script cannot be changed. This is a part of our “immutability” guarantee to ourselves. If the script were somehow manipulated for this specific version then the integrity check would start failing saving our customers from potentially malicious code being executed in their browsers. For more on the
integrity attribute, you can check out the MDN article. You can get the integrity value for unpkg by adding
?meta to the url for any asset. Ex: https://email@example.com/umd/react.production.min.js?meta
⎌ Caching for rapid rollbacks
Imagine a scenario where a critical defect is not found until the middle of a release. Now we need to rollback our code as quickly as we can to avoid customer interruption.
This scenario is where the IWA philosophy really shines. All of our build artifacts from the previous version are cached locally on the majority of our customer’s browsers. Rolling back our deployment is as simple as replacing the
index.html file with the previous version (hopefully through a simple
git revert) and suddenly everything goes back to functional!
🏉 How we tackle this at Meltwater
As a SaaS company we like to be as in control of our downstream dependencies as we can. This includes the hosting of our build artifacts.
At Meltwater we have created our own version of Unpkg to manage all deployments of our internal build artifacts. We’ve named our system mpkg, and it is still 100% backed by npm.
Each time a new package version is deployed to npm, mpkg is notified about that package being deployed and mpkg will ensure that requested build artifacts are made available at a well versioned, heavily cached, and highly available endpoint.
You may be asking yourself why we built our own solution. Simply put, we needed to have control over the uptime of the system. An added benefit is that we were able to add some additional features that Unpkg doesn’t have. We are able to limit which files from a deployed project are made available via the web. As an example, our
package.json files are not available. Ex: https://firstname.lastname@example.org/package.json
💫 The more you know
I hope we have shown you a nice way to separate the creation of build artifacts from the deployment of your application. The stability of this approach has proven to be a huge asset to many of the teams here at Meltwater, and we hope you will find it useful too!