Deploy private source maps with Netlify

Thibaut Tiberghien
Mar 10 · 4 min read

Source maps are great, they let you ship minified, optimised code to your users while enabling you to map things back to your original source code in error logs and while debugging. You will typically use a build system to generate your minifed code along with the source maps and deploy them together on your host. You can also use this build step to “uglify” your code in order to protect valuable intellectual property present in your frontend code. When that happens, you can no longer afford to deploy the source maps publicly. This post details how I deployed our source maps with team-only access.


Private hosting of source maps

We chose to deploy our source maps on Google Cloud Storage, in a bucket configured for access to authenticated users from our domain only. This is really convenient as we are using G Suite for our emails and can therefore leverage an authentication system that’s already in place. To do this, set permissions using Access Control Lists (ACLs) on your bucket.

For example, head to Permissions for your bucket, then Add members, enter yourdomain.com as the member and add the role Storage Object Viewer to let anyone in your organization access source maps when their browser is logged in.


Pointing the source maps to your bucket

Source maps are automatically fetched by the browser whenever needed, to do this the browser relies on an address indicated at the end of the minified file. It usually looks like this:

//# sourceMappingURL=index.e0d98431.js.map

By default, most build systems will co-locate source maps with the minified files and link them using their relative path. We will need to change the URL to the one of the bucket we created.

Here, your mileage may vary depending on the tools you use, but the concept remain the same. We use React for our frontend code, with create-react-app for an easy setup. We had to modify the Webpack configuration to use the SourceMapDevToolPlugin to set a custom URL. We use react-app-rewired to modify the Webpack configuration without ejecting.

From there, your build will inject the new URL at the end of the minified file:

//# sourceMappingURL=https://storage.cloud.google.com/<bucket-name>/index.e0d98431.js.map

Deploying the source maps with Netlify

We use Netlify to deploy and host our frontend code behind their Application Delivery Network (ADN). We previously built the code and let Netlify handle the rest. Our build script was something like:

“build”: “react-app-rewired build”

Now we call a shell script that handles the build and upload the source maps:

“build”: “./build.sh”

You may be using another Continuous Integration (CI) tool like TravisCI but the concept will be exactly the same.

  1. Build your code as usual
  2. You must install the GCloud SDK (which includes gsutil, the cloud storage CLI) in a non-interactive fashion by getting it from archived versions. This also ensures you use a fix version of the SDK and future updates don’t break your CI pipeline.
  3. You must authenticate to Google Cloud. They recommend using a service account for CI jobs. See how to create one from the docs. This will generate a JSON file which you need to provide during your deploy job. As we do not want to put this file in the repository for security reasons, I suggest storing its content as en environment variable in Netlify (or the CI tool you use) and building the file from the environment variable. (that’s what $GCLOUD_KEY_FILE is all about)
  4. From there the hardest is done. Use gsutil to upload the source maps and do not forget to delete them from the build folder before letting Netlify deploy that folder.

BONUS: Upload code and source maps to Sentry

If you’re using Sentry as error reporting solution, you may also want to upload both the minified code and private source maps to Sentry to get the best error stack traces you can. To do that, we’ll simply add a section to create a Sentry “release” in our build.sh file. Below are the extras to add right before deleting the source maps.

Notes:

  1. The name of the release is your choice, I use the short SHA of the commit ${COMMIT_REF::7} but you can use anything, just make sure to adapt it in every sentry-cli command.
  2. $SENTRY_ENV is an environment variable I use to name my release (dev, staging, prod). It is set by branch in the netlify.toml file as described in the docs.
  3. upload-sourcemaps will look for .js and .js.map file in the provided directory, here build/static/js/ where our JS assets are bundled by webpack. The rewrite and url-prefix options ensure that sentry uses its own uploaded artifacts instead of trying to get the one from cloud storage.

Hope this has been a useful post. Happy devops ;).

Thibaut Tiberghien

Written by

Executive Technology Leader | Web Products | SMEs, Startups

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade