I'm working with the guys at Thundra to evaluate t...
# sst
r
I'm working with the guys at Thundra to evaluate their APM product as a replacement for Epsagon. When wrapping a lambda using their library SST deploy errors out with the following:
Copy code
> node_modules/jest-pnp-resolver/index.js:46:4: error: Cannot assign to "defaultResolver" because it is a constant
    46 │     defaultResolver = getDefaultResolver();
       ╵     ~~~~~~~~~~~~~~~
   node_modules/jest-pnp-resolver/index.js:13:18: note: "defaultResolver" was declared a constant here
    13 │   const {basedir, defaultResolver, extensions} = options;
       ╵                   ~~~~~~~~~~~~~~~

 > node_modules/fsevents/fsevents.js:13:23: error: No loader is configured for ".node" files: node_modules/fsevents/fsevents.node
    13 │ const Native = require("./fsevents.node");
       ╵                        ~~~~~~~~~~~~~~~~~

 > node_modules/jest-pnp-resolver/getDefaultResolver.js:8:32: error: Could not resolve "jest-resolve/build/default_resolver" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
    8 │       defaultResolver = require(`jest-resolve/build/default_resolver`...
      ╵                                 ^

 > node_modules/jest-config/build/vendor/jsonlint.js:909:22: error: Could not resolve "file" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
    909 │     var cwd = require('file').path(require('file').cwd());
        ╵                       ~~~~~~
Is there anything that I can go back to the team with in terms of things they could change to make it work?
t
Can I see how you're wrapping the lambda
r
sure
Copy code
import { lambdaWrapper } from '@thundra/core';

export const handler: SQSHandler = lambdaWrapper(async (event) => {
...})
same way as we did with epsagon
t
I genuinely have no idea. Can't imagine what would need jest-config
This error is coming from esbuild not being able to find these things. Is their library not compatible with esbuild?
m
This is interesting, I was debugging an issue recently and I see jest all over the place in compiled lambda code. Almost like dev dependencies are getting wrapped up in production builds
r
(Serkan's their founder and CTO)
t
@Mike McCall interesting - do you think I could reproduce this with a standard bundle?
r
From Serkan
Copy code
The issue above might be related our Jest integration.
We are also able to instrument tests written in Jest
so there is optional dependency to jest in our agent
so maybe somehow it confuses SST during build
m
@thdxr It's worth a shot I haven't tried with a fresh sst app.
But I think the dependencies might come from installed packages, in my case it was graphql
r
@Serkan Özal has joined in 🙂
Does SST ignore dev dependencies from the bundle during build?
s
Hi all,
Jest
is listed in our dev dependencies and we also require
jest-runner
,
jest-environment-node
and
jest-environment-jsdom
in our agent optionally to instrument tests written in Jest. Might this error be related with that?
t
SST starts at your entry point and attempts to bundle everything it discovers. Only exceptions are what you list in
bundle.externalModules
And
aws-sdk
since that's always available in lambda
If you try to mark those as external does it work?
s
@Ross Coundon 👆
r
Just trying
So, I set
Copy code
bundle: {
      externalModules: ['aws-sdk', 'jest', 'jest-runner', 'jest-environment-node', 'jest-environment-jsdom'],
    },
and the error looks to be the same
Copy code
Building Lambda function src/main/handler/statsQueue.handler
 > node_modules/jest-pnp-resolver/index.js:46:4: error: Cannot assign to "defaultResolver" because it is a constant
    46 │     defaultResolver = getDefaultResolver();
       ╵     ~~~~~~~~~~~~~~~
   node_modules/jest-pnp-resolver/index.js:13:18: note: "defaultResolver" was declared a constant here
    13 │   const {basedir, defaultResolver, extensions} = options;
       ╵                   ~~~~~~~~~~~~~~~

 > node_modules/jest-pnp-resolver/getDefaultResolver.js:8:32: error: Could not resolve "jest-resolve/build/default_resolver" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
    8 │       defaultResolver = require(`jest-resolve/build/default_resolver`...
      ╵                                 ^

 > node_modules/fsevents/fsevents.js:13:23: error: No loader is configured for ".node" files: node_modules/fsevents/fsevents.node
    13 │ const Native = require("./fsevents.node");
       ╵                        ~~~~~~~~~~~~~~~~~

 > node_modules/jest-config/build/vendor/jsonlint.js:909:22: error: Could not resolve "file" (mark it as external to exclude it from the bundle, or surround it with try/catch to handle the failure at run-time)
    909 │     var cwd = require('file').path(require('file').cwd());
        ╵                       ~~~~~~


There was a problem transpiling the Lambda handler.
Expanded the externals to
Copy code
externalModules: [
        'aws-sdk',
        'jest',
        'jest-runner',
        'jest-resolve',
        'jest-pnp-resolver',
        'jest-environment-node',
        'jest-environment-jsdom',
        'jest-config',
      ],
and only 1 error remains
Copy code
node_modules/fsevents/fsevents.js:13:23: error: No loader is configured for ".node" files: node_modules/fsevents/fsevents.node
    13 │ const Native = require("./fsevents.node");
       ╵                        ~~~~~~~~~~~~~~~~~
Added fsevents and error gone
deploying now
s
Perfect @Ross Coundon 👏
t
Creating truly optional dependencies is tricky in node. Here's an example from kysely where he makes
pg
an optional dep: https://github.com/koskimas/kysely/blob/master/src/dialect/postgres/postgres-driver.ts#L90
r
Love the comment
s
Hi all, we have resolved this issue by providing our es build plugin: https://github.com/thundra-io/thundra-esbuild-plugin
Basically, we instruments the JS and TS files during bundling to be used later on production for enabling TTD (Time Travel Debugger)
I think, after our latest approach (layer + NODE_OPTIONS), configuring external modules should not be required at all (as Thundra package is not there during build anymore) for Thundra integration, right @Ross Coundon? https://docs.serverless-stack.com/monitoring-your-app-in-prod#thundra
r
I haven't tried removing the externals, I'll give it a go in a bit
Yes, just confirmed it works with the externals removed 😄
s
Ok thx 👍