@@ -93,11 +93,17 @@ This creates a new `DebugId` by hashing the contents of the JavaScript file.
9393
9494### Based on SourceMap Content-hash
9595
96- This creates a new ` DebugId ` by hashing the contents of the SourceMap file.
96+ This creates a new ` DebugId ` by hashing the contents of the SourceMap file. The reasoning for this is primarily
97+ motivated by a drawback of the previous option.
98+ It is possible that non-essential changes to the source file, such as whitespace or comments, will be completely
99+ removed by a minifier, and will result in an identical minified output file.
100+ These changes would however create different mappings in the SourceMap file, making it possible to resolve to the
101+ correct original source.
97102
98103** pros**
99104
100- - Generates a new ` DebugId ` for changes to source files that would otherwise not lead to changes in the JavaScript file.
105+ - Generates a new ` DebugId ` for changes to source files that would otherwise not lead to changes in the (minified) JavaScript file.
106+ - SourceMap processing will always resolve back to the original source code.
101107
102108** cons**
103109
@@ -147,13 +153,31 @@ It is therefore necessary to extract this `DebugId` through other means.
147153Current JavaScript stack traces include the absolute path (called ` abs_path ` ) of each stack frame. It should be possible
148154to load and inspect that file at runtime whenever an error happens.
149155
156+ An example of this might look like this:
157+
158+ ``` js
159+ // cached in the SDK:
160+ const RESOLVED_FRAMES = new Map ();
161+ async function attachDebugMeta (event ) {
162+ for (const { abs_path } of allStackFrames (event )) {
163+ if (! RESOLVED_FRAMES .has (abs_path)) {
164+ const rawSource = await fetch (abs_path).then ((res ) => res .text ());
165+ RESOLVED_FRAMES .set (abs_path, extractDebugIdFromSource (rawSource));
166+ }
167+ }
168+
169+ event .debug_meta = resolvedFramesToImages (RESOLVED_FRAMES );
170+ }
171+ ```
172+
150173** pros**
151174
152175- Does not require injecting any _ code_ into the JavaScript files.
153176
154177** cons**
155178
156- - Might incur some async fetching / IO when capturing an Error. Though any ` abs_path ` in the stack trace should be cached already.
179+ - Needs ` async ` code to resolve ` DebugId ` s, and might incur some async fetching / IO when capturing an Error.
180+ - Though any source referenced from the stack trace via ` abs_path ` is likely in the browser cache already.
157181
158182#### Add the ` DebugId ` to a global at load time
159183
@@ -162,7 +186,8 @@ the `DebugId` to a global map.
162186
163187An example snippet is here:
164188
165- ```
189+ <!-- prettier-ignore -->
190+ ``` js
166191! function (){try {var e= " undefined" != typeof window ? window : " undefined" != typeof global ? global : " undefined" != typeof self ? self : {},n= (new Error ).stack ;n&& (e ._sentryDebugIds = e ._sentryDebugIds || {},e ._sentryDebugIds [n]= " XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" )}catch (e){}}()
167192```
168193
@@ -175,12 +200,14 @@ Further post-processing at time of capturing an `Error` is required to extract t
175200
176201** cons**
177202
178- - It does however require parsing of the ` Error.stack ` at time of capturing the ` Error ` .
203+ - It does however require parsing of the ` Error.stack ` s in ` _sentryDebugIds ` at time of capturing the ` Error ` .
204+ - However this should be cached and only happen once.
179205
180206An alternative implementation might use the [ ` import.meta.url ` ] ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta )
181207property. This would avoid capturing and post-processing an ` Error.stack ` , but does require usage of ECMAScript Modules.
182208
183- ```
209+ <!-- prettier-ignore -->
210+ ``` js
184211((globalThis ._sentryDebugIds = globalThis ._sentryDebugIds || {})[import .meta.url]=" XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" );
185212` ` `
186213
@@ -214,8 +241,11 @@ In this example, assets are _fingerprinted_, and after being fully propagated
214241through a global CDN, they are starting to be referenced from the backend
215242service via HTML.
216243
217- This may work with unique content-hash based filenames, and even use _ fingerprinting_ and
218- [ Subresource Integrity (SRI)] ( https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity ) .
244+ _Fingerprinting_ in this case means creating a unique content-hash which is then
245+ used in various of ways:
246+
247+ - As part of the filename, to give each file a unique and stable filename.
248+ - Use the derived hash for [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
219249
220250An example may look like this, for a CDN-deployed and fingerprinted reference
221251to [katex](https://katex.org/docs/browser.html#starter-template):
@@ -232,7 +262,18 @@ to [katex](https://katex.org/docs/browser.html#starter-template):
232262Not only is the deployment pipeline very complex, it can also involve a variety of tools with varying degree of
233263integration between them.
234264The example ` < script> ` tag shown above might be generated as part of one integrated JS bundler tool, or it might be
235- generated by a Rust or python backend, based on supplied JSON file.
265+ generated by a Rust or python backend, based on a supplied JSON file, which might look like this:
266+
267+ ` ` ` json
268+ {
269+ " assets" : {
270+ " assert_id" : {
271+ " filename" : " my_asset.abcdefg.min.js" ,
272+ " integrity" : " sha384-VWXYZ"
273+ }
274+ }
275+ }
276+ ` ` `
236277
237278The checksums themselves might be directly output by a JS bundler tool, or they might be generated by a completely
238279different tool at another stage of the build pipeline.
@@ -272,13 +313,15 @@ In this scenario, injection happens at the time of `sentry-cli upload`, and will
272313
273314**cons**
274315
316+ - Violates expectations of file immutability and integrity.
275317- Does not work with bundlers that integrate fingerprinting.
276318- Does not work in build pipelines where ` sentry-cli upload` is not in the main deployment path.
277319
278320### Injection via bundler plugins
279321
280- Here, we would build ` DebugId ` injection right into the various JavaScript bundlers. This can happen with a third-party
281- plugin at first, and might move into the core bundler packages once there is enough community buy-in for ` DebugId ` s.
322+ Here, we would build ` DebugId` injection right into the various JavaScript bundlers.
323+ We should validate the core ideas using third-party plugins at first, and then strive for inclusion in the
324+ upstream bundlers directly.
282325
283326Each bundler is unique though, and has different hooks at different stages of its internal pipeline. Some bundlers
284327might not have the necessary hooks at the necessary stage at all.
@@ -358,5 +401,6 @@ It also has a `manifest.json`, which has more metadata per file, like the type o
358401
359402**cons**
360403
361- - Does not work well content-hash based ` DebugId ` s, as one ` DebugId ` can appear in a multitude of archives.
404+ - Does not work well with content-hash based ` DebugId` s, as one ` DebugId` can appear in a multitude of archives.
405+ Picking the one archive that covers all needed files is non-trivial.
362406- Feels like a workaround for inefficiencies in other parts of the processing pipeline when dealing with more smaller files.
0 commit comments