Commit fd85225
fix(bundler-plugins): Preserve directive prologues during bundle injection (#24221)
Bundler plugins inject Sentry code into generated bundles. In some
outputs the injection could be placed before directive prologues such as
`"use strict"`, causing JavaScript to stop recognizing them as
directives.
I found this issue to affect some production cases - I don't have access
to their sources so I can't fully say how the original code was authored
and what exactly made it lose the strict mode, but the generated output
looked like this:
```js
try{!function(){var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?
globalThis:"undefined"!=typeof self?self:{},t=(new e.Error).stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="612bd636-5fcc-473a-bdd0-20460245872c",e._sentryDebugIdIdentifier="sentry-dbid-612bd636-5fcc-473a-bdd0-
20460245872c")}()}catch(e){}"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[120],{67232:function(e,t,n){var r,l=n(41498),a=n(90413),o={usingClientEntryPoint:!1,Events:null,Dispatcher:{current:null}};function i(e){var
t="https://react.dev/errors/"+e;if(1<arguments.length){t+="?args[]="+encodeURIComponent(arguments[1]);
```
Given the sentry code was injected before the strict mode directive,
that changed the meaning of `arguments[1]` at this position in the app
code:
```js
function aW(e, t) {
if (null !== (t = null !== (t = t.updateQueue) ? t.lastEffect : null)) {
var n = (t = t.next);
do {
if ((n.tag & e) === e) {
var r = n.create,
l = n.inst;
/* arguments[1] no longer refer to the original argument */
r = r();
l.destroy = r;
}
n = n.next;
} while (n !== t);
}
}
```
That's because in the sloppy mode the assignment to `t` before the
`arguments[1]` reference changes the `arguments` content too 🫠 . You can
test it out using this isolated sample:
```js
function test(foo) {
foo = 2;
console.log(arguments[0]); // 2
}
test(1);
function testStrict(foo) {
"use strict";
foo = 2;
console.log(arguments[0]); // 1
}
testStrict(1);
```
This PR:
- adds a bunch of tests for edge cases and for source mapping behavior
(the latter was already working OK but didn't quite have the coverage)
- replaces simple regex with a more spec-compliant tiny scanner so the
proper injection point can be found
- in Webpack `BannePlugin` can only prepend/append text, as far as I
know, it can't just inject into an arbitrary position. So it was
replaced with a compilation hook and ReplaceSource plugin. That allows
for a fine-grained control at the asset level
- in the case of Rollup, this PR only slightly changes the insertion
point calculation - but it doesn't replace the overall mechanism/hooks
used
- esbuild has not required any fixes because `inject` API handles this
for us
---
AI disclosure: I have steered it a bunch myself and I understand each
line of code added. I ensured (using my own judgement) that all of this
matches the project's style and goal but ofc I have much less context on
that than the maintainers here. That said, I can address any PR feedback
thrown my way.
---------
Co-authored-by: OpenAI Codex <codex@openai.com>
Co-authored-by: Tim Fish <tim@timfish.uk>1 parent 2bff2ea commit fd85225
36 files changed
Lines changed: 739 additions & 311 deletions
File tree
- dev-packages/bundler-plugin-integration-tests/fixtures
- esbuild
- src
- webpack5
- packages
- bundler-plugins
- src
- core
- esbuild
- rollup
- webpack
- test
- core
- rollup
- vite
- webpack
- nextjs
- src/config/loaders
- test/config
- __snapshots__
Lines changed: 55 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
Lines changed: 32 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
Lines changed: 12 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
Lines changed: 14 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
Lines changed: 1 addition & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
Lines changed: 1 addition & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
Lines changed: 1 addition & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
Lines changed: 1 addition & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
Lines changed: 2 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
13 | 12 | | |
14 | 13 | | |
15 | 14 | | |
16 | 15 | | |
17 | | - | |
| 16 | + | |
18 | 17 | | |
19 | 18 | | |
20 | 19 | | |
| |||
Lines changed: 1 addition & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
10 | 9 | | |
11 | 10 | | |
12 | 11 | | |
| |||
0 commit comments