honeybadger-io / honeybadger-js

Universal JavaScript library for reporting errors to Honeybadger.io :zap:
https://www.honeybadger.io/for/javascript/
MIT License
108 stars 62 forks source link

Source map not linked on Heroku with esbuild-plugin #1349

Closed jeremysmithco closed 4 months ago

jeremysmithco commented 4 months ago

Hey there! We're trying to get source maps working on a Rails app deployed to Heroku using the @honeybadger-io/esbuild-plugin package. Source maps are being uploaded during the Heroku build step, and are showing up under the "Stored source maps" tab, but JS errors are still showing the message: "No source map is available for this stack trace."

What are the steps to reproduce this issue?

  1. Add @honeybadger-io/esbuild-plugin to project.

  2. Update esbuild.config.mjs:

import * as esbuild from "esbuild"
import path from "path"
import rails from "esbuild-rails"
import { honeybadgerSourceMapPlugin } from "@honeybadger-io/esbuild-plugin"

const hbPluginOptions = {
  apiKey: `${process.env.HONEYBADGER_API_KEY_JS}`,
  assetsUrl: `${process.env.BASE_URL}/assets`,
  revision: process.env.SOURCE_VERSION,
  environment: process.env.HONEYBADGER_ENV,
}

const config = {
  entryPoints: ["application.js"],
  bundle: true,
  outdir: path.join(process.cwd(), "app/assets/builds"),
  absWorkingDir: path.join(process.cwd(), "app/javascript"),
  define: {
    "global": 'window',
  },
  loader: {
    '.png': 'file',
    '.css': 'empty',
  },
  minify: true,
  plugins: [rails(), honeybadgerSourceMapPlugin(hbPluginOptions)],
  sourcemap: "external",
}

if (process.argv.includes("--watch")) {
  let context = await esbuild.context({...config, logLevel: 'info'})
  context.watch()
} else {
  esbuild.build(config)
}
  1. Update JS snippet in head to include revision:
<script src="//js.honeybadger.io/v6.9/honeybadger.min.js" type="text/javascript"></script>
<script type="text/javascript">
  Honeybadger.configure({
    apiKey: "<%= ENV['HONEYBADGER_API_KEY_JS'] %>",
    environment: "<%= ENV['HONEYBADGER_ENV'] %>",
    revision: "<%= ENV['HEROKU_SLUG_COMMIT'] %>",
  });
</script>
  1. Set BASE_URL env var to different URLs (in our case with different root domains):

Staging: https://staging.app.co Production: https://app.ourapp.com

What happens?

  1. We deploy the app to staging after CI passes. The build log shows:
-----> Build
       Running build (yarn)
       yarn run v1.22.22
       $ node esbuild.config.mjs
       Successfully uploaded application.js.map to Honeybadger
       1 sourcemap file(s) successfully uploaded to Honeybadger
       Done in 2.40s.
  1. We check the "Stored source maps" tab and it shows the JS asset URL with the proper commit hash for the Revision: https://staging.app.co/assets/application.js Note: it does not show the fingerprinted asset, e.g. https://staging.app.co/assets/application-897f96e5dd08c439b4a643bde674cba9d369018f08f7b390f4efb91200d6949b.js

  2. We hit a special endpoint on our app that intentionally produces a JS error, which we can see in the dev tools console.

  3. We check the error reported in Honeybadger, and the following message shows up under the backtrace: "No source map is available for this stack trace."

What were you expecting to happen?

We were expecting this would link JS errors to the source map. It's possible we may have missed something, but I can't see what it might be.

Thanks for your help!

subzero10 commented 4 months ago

Hey @jeremysmithco, are you using Sprockets in your pipeline?

We check the "Stored source maps" tab and it shows the JS asset URL with the proper commit hash for the Revision: https://staging.app.co/assets/application.js Note: it does not show the fingerprinted asset, e.g. https://staging.app.co/assets/application-897f96e5dd08c439b4a643bde674cba9d369018f08f7b390f4efb91200d6949b.js

I think I reproduced your issue with a fresh rails app and it seems that the issue is because of Sprockets. After esbuild is complete, Sprockets does some post-processing and adds the digest to the file. I was going to suggest to try config.assets.digest = false in your config but unfortunately this option doesn't work as I was hoping. There are some workarounds here and here to skip the digest if you want to try them out.

Another option would be to explore extending Sprockets either with an exporter or post processor to upload the generated files to Honeybadger, since it can create source maps as well.

I will close this issue because I don't see what we can do from the esbuild plugin to help with this, but feel free to write here if you have any other thoughts!

jeremysmithco commented 4 months ago

Hey, thanks @subzero10! :) Yes, we are using Sprockets. And for whatever reason, it hadn't occurred to me that this was uploading the source map after the esbuild build step, but before Sprockets did post-processing and digesting. I'm now looking for a way to use esbuild digests instead of Sprockets, so we'll see how that goes. Appreciate the help!

subzero10 commented 3 months ago

If not too much trouble, I'd like to know how you solve this, when you solve it :) It may be beneficial to share with our community!

jeremysmithco commented 3 months ago

@subzero10 Hey, I'd be happy to! We may need to move this to the backlog though, so it might be a while. 👍

jeremysmithco commented 1 month ago

@subzero10 It's been a minute, but just wanted to follow up and share how we ended up getting source map uploads working with Rails and Sprockets: https://railsinspire.com/samples/18