-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@sentry/esbuild-plugin
breaks Object.defineProperty
on module.exports
#669
Comments
@sentry/esbuild-plugin
breaks opentelemetry-lambda
's patching@sentry/esbuild-plugin
breaks Object.defineProperty
on module.exports
Hey @colinmcdonald22 thanks for reaching out and for the detailed rundown! You are right, with re-exporting all modules of a file within our plugin, the exports become immutable (this is automatically done, see evanw/esbuild#1079). So I think we're left with three options (not sure which ones are feasible in your case, this is based on the repro):
const originalApp = require("./dist/app");
const app = Object.create(Object.getPrototypeOf(originalApp));
// make a configurable copy here
Object.defineProperty(app, "handler", {
configurable: true,
writable: true,
value: originalApp.handler,
});
shimmer.wrap(app, "handler", function (original) {
return function () {
console.log("Wrapped start");
var returned = original.apply(this, arguments);
console.log("Wrapped end");
return returned;
};
});
app.handler();
// ...
const configurableExports = {};
Object.entries(OriginalModule).forEach(([key, value]) => {
Object.defineProperty(exports, key, {
enumerable: true,
configurable: true,
get: () => OriginalModule[key]
});
});
module.exports = configurableExports; ^ This feels a bit brittle tbh, wdyt @lforst ? |
Hi @chargome, thank you for your reply! Regarding your proposed solutions:
OpenTelemetry (and more specifically, OpenTelemetry-Lambda) loads via a Therefore, it's not replacing the Nodejs entrypoint, it's just running a small shim before it. Of course, from the "perspective" of a In order for that to work, I believe OpenTelemetry would have to actually take over the entrypoint. Instead of I believe, but might very well be incorrect, that the best way for a shim in this style (modifying a file from a
Of course, OpenTelemetry's approach of relying on mutable exports and shimming via a |
@colinmcdonald22 hmm you're right in the sense that we should not block you on doing this – I'll try to set some time aside this week to have a go at this, unless you would want to open a PR for this? |
@chargome this thread so far is just about the extent of my ESBuild / JavaScript knowledge unfortunately. Happy to spend some time playing with it, but definitely not confident I could resolve this |
Environment
@sentry/esbuild-plugin
:3.1.1
esbuild
:0.24.2
Steps to Reproduce
We're using https://github.com/open-telemetry/opentelemetry-lambda for tracing in our AWS Lambda functions, along with using Sentry (and
@sentry/esbuild-plugin
) for error tracking.Here's an example of how we're exporting our AWS Lambda handler:
OpenTelemtry-Lambda is using Shimmer to wrap our
export
'd Lambda handler function, to start an OpenTelemetry trace. Shimmer does this usingObject.defineProperty
, as seen here: https://github.com/othiym23/shimmer/blob/master/index.js#L14C3-L14C24When compiling this code using plain ESBuild, Shimmer is able to wrap the handler as expected. However, when compiling using ESBuild and
@sentry/esbuild-plugin
, theObject.defineProperty
call inside Shimmer throws an exception.I've created a small repository to reproduce the problem: https://github.com/colinmcdonald22/SentryBugRepro/tree/master
app.js
is a small Lambda handler.build.mjs
invokes ESBuild, optionally enabling@sentry/esbuild-plugin
based on theWITH_SENTRY
environment variableinvoke.js
simulates what OpenTelemetry-Lambda is doing when shimming our code.After cloning the repo and
pnpm install
'ing:pnpm run test
does the following:invoke.js
handler
function exported fromapp.js
This works as expected:
Wrapped start
/Wrapped end
are added ininvoke.js
to prove shimmer is working, andHello world
is from our app's handler inapp.js
Next, run
WITH_SENTRY=1 pnpm run test
. This is the same process as above, but with@sentry/esbuild-plugin
active.The
Object.defineProperty
inside Shimmer now throws a "Cannot redefine property". This only happens when@sentry/esbuild-plugin
is installed; it does not happen with plain ESBuild.The root of the issue seems to be that plain ESBuild generates exports that are able to be patched with
Object.defineProperty
, whereas ESBuild +@sentry/esbuild-plugin
generates exports that are not able to be patched.Although OpenTelemetry + Shimmer's approach is certainly brittle, I think it's reasonable to expect the Sentry ESBuild plugin doesn't change the underlying ESBuild behavior of exports being patchable.
A similar issue has been reported on OpenTelemetry before: aws-observability/aws-otel-lambda#99 (comment)
According to the comment I linked, code like this:
caused ESBuild to generate code that cannot be patched. However, changing it to this format:
causes ESBuild to generate
Object.defineProperty
-compatible code.I'm not familiar enough with how ESBuild functions to speculate why this makes a difference, however it seems like it might be relevant.
The text was updated successfully, but these errors were encountered: