sst icon indicating copy to clipboard operation
sst copied to clipboard

CLI: Add built-in support for generating source maps

Open jayair opened this issue 3 years ago • 4 comments

It'll be good if the CLI automatically dumps the source maps for use by other tools like Sentry. One idea could be to specify this at the app level for all functions?

Requested by Sam on Slack.

jayair avatar Jan 04 '22 17:01 jayair

I'll drop my esbuild plugin here, in case it helps! This works 100% with Sentry, but I imagine this directory structure works with most error logging services, as it's pretty basic.

config/esbuild.js
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable max-len */
const fs = require('fs');
const path = require('path');

const sourceMapsOutDir = './.build/sourcemaps';
const srcDir = 'src';

module.exports = [
  {
    name: 'create-sourcemaps',
    setup(build) {
      build.onEnd(({ metafile }) => {
        if (metafile.outputs) {
          const files = Object.entries(metafile.outputs);
          let sourceMapPath;
          let sourcePath;
          let partialPath;

          for (const file of files) {
            if (/\.map$/.test(file[0])) {
              sourceMapPath = file[0];
            } else {
              sourcePath = file[0];
              partialPath = path.parse(file[1].entryPoint).dir;
            }
          }

          if (
            partialPath !== srcDir &&
            !new RegExp(`^${srcDir}/`).test(partialPath)
          ) {
            return;
          }

          if (!sourceMapPath) return;

          const destDir = `${sourceMapsOutDir}/${partialPath}`;

          fs.mkdirSync(destDir, { recursive: true });
          fs.copyFileSync(
            sourceMapPath,
            `${destDir}/${path.parse(sourceMapPath).base}`
          );
          fs.copyFileSync(
            sourcePath,
            `${destDir}/${path.parse(sourcePath).base}`
          );
        }
      });
    },
  },
];

This is also an important bit, but because it's specific to Sentry, maybe this just gets added to a FAQ page or something later on:

const lambdaPathPattern = /^(?:async\s+)?\/var\/task\//;

Sentry.AWSLambda.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.STAGE !== 'prod' ? 'development' : 'production',
  integrations: [
    new RewriteFrames({
      iteratee: frame => {
        if (lambdaPathPattern.test(frame.filename!)) {
          frame.filename = frame.filename!.replace(
            lambdaPathPattern,
            'app:///'
          );
        }

        return frame;
      },
    }),
  ],
});

The filename has to be rewritten in that exact way in order for Sentry to match up the incoming error with the source maps.

ffxsam avatar Jan 04 '22 18:01 ffxsam

@ffxsam I tried your plugin, but it crashed SST as written when I tried to run any of the funcs. Have you updated it since this post? Thanks!

mikestopcontinues avatar Aug 11 '22 14:08 mikestopcontinues

Hey @mikestopcontinues! Nope, literally no changes since my post. What's the crash look like?

Also, make sure you've enabled source map generation which is no longer on by default in the latest SST.

app.setDefaultFunctionProps(stack => ({
  bundle: { sourcemap: true },
}));

ffxsam avatar Aug 11 '22 16:08 ffxsam

Thanks @ffxsam. I don't know what was going on last time I tried, but it works now. :)

mikestopcontinues avatar Aug 13 '22 01:08 mikestopcontinues