Comments (6)
In case it helps anyone else facing this issue, I was able to successfully turn this Sentry esbuild plugin config:
sentryEsbuildPlugin({
disable: !sentryEnabled,
org: "org",
project: "project",
release: {
name: `project@${await getVersion(commitTag)}-${channel}`,
inject: false,
setCommits: undefined,
},
telemetry: false,
})
Into this code running after esbuild finishes using the Sentry CLI:
import { $ } from "execa";
import { removeSourcemaps } from "./build-support";
// Handle creating Sentry releases and uploading sourcemaps.
//
// Documentation referenced while putting this together:
//
// * https://docs.sentry.io/product/cli/releases/
// * https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/cli/
if (sentryEnabled && metafile) {
// Remove CSS sourcemaps, we don't want Sentry doing anything with them
await removeSourcemaps(metafile, ".css.map");
const sentryEnv = { SENTRY_ORG: "org", SENTRY_PROJECT: "project" };
const shellConfig: CommonOptions = {
env: sentryEnv,
stdio: "inherit",
verbose: true,
};
const releaseName = `project@${await getVersion(commitTag)}-${channel}`;
if (hasSentryAuthToken) {
const pipelineUrl = process.env.CI_PIPELINE_URL;
await $(shellConfig)`sentry-cli releases new ${releaseName} ${
pipelineUrl ? ["--url", pipelineUrl] : []
}`;
}
await $(shellConfig)`sentry-cli sourcemaps inject ${dist}`;
if (hasSentryAuthToken) {
const jobUrl = process.env.CI_JOB_URL ?? "";
await $(
shellConfig,
)`sentry-cli sourcemaps upload --strict --note ${jobUrl} --release ${releaseName} ${dist}`;
await $(shellConfig)`sentry-cli releases finalize ${releaseName}`;
}
}
Build determinism is working well with this setup.
from sentry-javascript-bundler-plugins.
The workaround I've implemented right now is pulling the sentry debug IDs out of the build artifacts from our CI system and writing them to a file
That's pretty novel. Cool!
Thanks for providing the workaround. Hopefully, people will find it useful. I'll keep this issue in the backlog.
from sentry-javascript-bundler-plugins.
Unfortunately, due to limitations of the esbuilds plugin system we currently cannot make it deterministic - unless we modify files after the fact. This is possible but a major PITA because it also would require us to rewrite any related sourcemaps.
(I just thought of a hack where we maybe only insert a placeholder and then after the build is done replace the placeholder with an actual id, based on the files content. That should also keep the source maps intact. 🤔)
We won't tackle this right now and probably also not in the medium term future. If you got other ideas, let us know! Also, feel free to contribute to the package yourself! We don't see too much usage of the esbuild plugin, especially relative to vite and webpack, so I cannot justify working on this right now (even though I would like to see it succeed!).
from sentry-javascript-bundler-plugins.
As a workaround you can also use the legacy process (which doesn't inject anything) or Sentry CLI, which should be deterministic when injecting.
from sentry-javascript-bundler-plugins.
Unfortunately, due to limitations of the esbuilds plugin system we currently cannot make it deterministic - unless we modify files after the fact. This is possible but a major PITA because it also would require us to rewrite any related sourcemaps.
Oof, gotcha.
Also, feel free to contribute to the package yourself! We don't see too much usage of the esbuild plugin, especially relative to vite and webpack, so I cannot justify working on this right now (even though I would like to see it succeed!).
Understandable 🙂 if I find the time I'll see if I can contribute something 👍.
As a workaround you can also use the legacy process (which doesn't inject anything) or Sentry CLI, which should be deterministic when injecting.
The workaround I've implemented right now is pulling the sentry debug IDs out of the build artifacts from our CI system and writing them to a file:
# Get the Sentry debug IDs from our CI build output and store them for later
# use
rg "sentry-dbid-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" \
$(dist) -o -N --no-heading > sentry_debug_ids.txt
and then in our build system when being built for AMO review, I take those debug IDs and inject them back into the build output after bundling is finished:
import { $ } from "execa";
import { readFile } from "fs/promises";
import { fileExists } from "./build-support";
// TODO: remove this when https://github.com/getsentry/sentry-javascript-bundler-plugins/issues/500
// is fixed
export async function replaceSentryDebugIds() {
// This file contains multiple lines. Each line is of the format:
// dist/firefox/...:sentry-dbid-{uuid}
const sentryDebugIdTxt = await readFile("sentry_debug_ids.txt", "utf-8");
console.log("sentry_debug_ids.txt contents: \n\n" + sentryDebugIdTxt);
return Promise.all(
sentryDebugIdTxt
.trim()
.split("\n")
.map((filepathAndDebugId) => filepathAndDebugId.split(":", 2))
.map(([filepath, debugId]) => [
filepath,
debugId.replace("sentry-dbid-", ""),
])
.map(async ([filepath, debugId]) => {
const exists = await fileExists(filepath);
if (exists) {
// The safest way to find the Sentry debug ID is where it's
// prefixed by "sentry-dbid-", but it's also present in the
// file without that prefix.
//
// We find its exact value and then replace that.
const newIdInFile =
await $`rg sentry-dbid-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} ${filepath} -o -N --no-heading --no-filename`;
const newIdPrefixStripped = newIdInFile.stdout.replace(
"sentry-dbid-",
"",
);
console.log(
`Replacing ${newIdPrefixStripped} in ${filepath} with ${debugId}`,
);
// Replace Sentry debug IDs in the build output with the
// value from our build in CI.
return $`sed -i s/${newIdPrefixStripped}/${debugId}/g ${filepath}`;
} else {
console.warn(
`File at ${filepath} did not exist, unable to replace Sentry debug ID`,
);
return;
}
}),
);
}
This has been working well so far for our needs.
from sentry-javascript-bundler-plugins.
Actually, the above workaround isn't quite enough, because the randomly generated Sentry debug IDs end up in the source code before esbuild does minification, affecting esbuild's character frequency analysis: evanw/esbuild#1846 (comment)
For larger bundled outputs this isn't an issue and doesn't affect character frequency enough to cause esbuild's name generation to change (since there are already so many characters in the file). For smaller bundled outputs, however (we have an entrypoint that's < 20 LoC), the random UUID Sentry adds to the source code is very significant and has a large impact on character frequency. This causes esbuild to generate different names in the minified output, and even though we fix the debug ID in the output after it's generated, we can't fix the generated names 😞.
I'll have to give the CLI a shot.
from sentry-javascript-bundler-plugins.
Related Issues (20)
- Inject release SHA only to one output JS file HOT 2
- Sourcemap upload successful, artifacts show in UI, no sourcemaps in Sentry HOT 4
- Setting `cleanArtifacts: true` fails with a 403 HOT 7
- esbuild-plugin is missing a name HOT 7
- @sentry/vite-plugin inclusion in vite.config.js causes it to skip .env.production HOT 5
- @sentry/vite-plugin regex used while inserting debugId matches till the wrong index, throws a syntax error HOT 2
- Unclear on how to urlPrefix my maps. HOT 6
- Using the "filesToDeleteAfterUpload" plugin setting breaks source maps with esbuild plugin HOT 3
- Proxy for uploading sourcemaps? HOT 3
- reactComponentAnnotation. I use an unintended value for a prop. HOT 1
- Sentry Vite Plugin throws error while building the app: TypeError: Converting circular structure to JSON HOT 2
- error: release not found HOT 6
- sentry-vite + CDN sourcemaps not working HOT 30
- Cannot read properties of undefined (reading "silent") HOT 2
- Should inject banner code after `use strict` HOT 1
- Sourcemap upload not working for `.mjs` files HOT 2
- esbuild plugin: You are attempting to use this endpoint too frequently HOT 4
- sentry-webpack-plugin + electron(-forge) breaks universal builds HOT 1
- Webpack plugin causes Typescript build errors when React component annotation is enabled HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sentry-javascript-bundler-plugins.