Deploying web applications can be extremely challenging. Even if your application only relies on a single API endpoint, many mistakes can still make it to production just by having to rebuild your javascript and CSS artifacts for each environment. That’s where Immutable Web Apps and npm can step in to help out! Let’s dive into why Meltwater uses a CDN to host private meltwater npm packages as static assets, and how this increases the stability of our deployments.
🕸 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://unpkg.com/react@16.7.0/umd/react.production.min.js" integrity="sha384-bDWFfmoLfqL0ZuPgUiUz3ekiv8NyiuJrrk1wGblri8Nut8UVD6mj7vXhjnenE9vy"></script>
This allows us to load any javascript or CSS that is packed into any npm package! The value of this is that we can now isolate the build and publishing of our build artifacts from the publishing of the index.html
file for our application!
🔐Aside on the integrity attribute
The 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://unpkg.com/react@16.7.0/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://unpkg.com/react@16.7.0/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!