Skip to content

Commit 69d85f6

Browse files
author
Luca Forstner
committed
feat(core): Import release injection code from each module
1 parent 97a2a2f commit 69d85f6

File tree

4 files changed

+70
-57
lines changed

4 files changed

+70
-57
lines changed

packages/bundler-plugin-core/package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@
1212
"files": [
1313
"dist"
1414
],
15-
"exports": {
16-
".": {
17-
"import": "./dist/esm/index.mjs",
18-
"require": "./dist/cjs/index.js"
19-
}
20-
},
2115
"main": "dist/cjs/index.js",
2216
"module": "dist/esm/index.mjs",
2317
"types": "dist/types/index.d.ts",

packages/bundler-plugin-core/rollup.config.js

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,48 @@ const input = ["src/index.ts"];
1010

1111
const extensions = [".js", ".ts"];
1212

13-
export default {
14-
input,
15-
external: [...Object.keys(packageJson.dependencies), ...modulePackage.builtinModules],
16-
plugins: [
17-
resolve({ extensions, preferBuiltins: true }),
18-
commonjs(),
19-
json(),
20-
replace({
21-
__PACKAGE_VERSION__: JSON.stringify(packageJson.version),
22-
}),
23-
babel({
24-
extensions,
25-
babelHelpers: "bundled",
26-
include: ["src/**/*"],
27-
}),
28-
],
29-
output: [
30-
{
31-
file: packageJson.module,
32-
format: "esm",
33-
exports: "named",
34-
sourcemap: true,
35-
},
36-
{
37-
file: packageJson.main,
13+
export default [
14+
{
15+
input,
16+
external: [...Object.keys(packageJson.dependencies), ...modulePackage.builtinModules],
17+
plugins: [
18+
resolve({ extensions, preferBuiltins: true }),
19+
commonjs(),
20+
json(),
21+
replace({
22+
preventAssignment: true,
23+
values: {
24+
__PACKAGE_VERSION__: JSON.stringify(packageJson.version),
25+
},
26+
}),
27+
babel({
28+
extensions,
29+
babelHelpers: "bundled",
30+
include: ["src/**/*"],
31+
}),
32+
],
33+
output: [
34+
{
35+
file: packageJson.module,
36+
format: "esm",
37+
exports: "named",
38+
sourcemap: true,
39+
},
40+
{
41+
file: packageJson.main,
42+
format: "cjs",
43+
exports: "named",
44+
sourcemap: true,
45+
},
46+
],
47+
},
48+
{
49+
input: "src/release-injection-file.ts",
50+
output: {
51+
file: "dist/release-injection-file.js",
3852
format: "cjs",
3953
exports: "named",
4054
sourcemap: true,
4155
},
42-
],
43-
};
56+
},
57+
];

packages/bundler-plugin-core/src/index.ts

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ const ALLOWED_TRANSFORMATION_FILE_ENDINGS = [".js", ".ts", ".jsx", ".tsx", ".mjs
3434
* - Sourcemaps upload
3535
*
3636
* Release injection:
37-
* Per default the sentry bundler plugin will inject a global `SENTRY_RELEASE` into
38-
* each JavaScript/TypeScript entrypoint. On a technical level this is done by identifying
39-
* entrypoints in the `resolveId` hook and prepending user code in the `transform` hook.
40-
* If a user wants to inject the release into a particular set of modules instead,
41-
* they can use the `releaseInjectionTargets` option.
37+
* Per default the sentry bundler plugin will inject a global `SENTRY_RELEASE` into each JavaScript/TypeScript module
38+
* that is part of the bundle. On a technical level this is done by appending an import (`import "sentry-release-injector;"`)
39+
* to all entrypoint files of the user code (see `transformInclude` and `transform` hooks). This import is then resolved
40+
* by the sentry plugin to a virtual module that sets the global variable (see `resolveId` and `load` hooks).
41+
* If a user wants to inject the release into a particular set of modules they can use the `releaseInjectionTargets` option.
4242
*
4343
* Source maps upload:
4444
*
@@ -102,8 +102,6 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
102102
let transaction: Transaction | undefined;
103103
let releaseInjectionSpan: Span | undefined;
104104

105-
const absolueEntrypointPaths = new Set<string>();
106-
107105
return {
108106
name: "sentry-plugin",
109107
enforce: "pre", // needed for Vite to call resolveId hook
@@ -164,11 +162,6 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
164162
*/
165163
resolveId(id, importer, { isEntry }) {
166164
logger.debug('Called "resolveId":', { id, importer, isEntry });
167-
168-
if (isEntry) {
169-
absolueEntrypointPaths.add(path.resolve(path.normalize(id)));
170-
}
171-
172165
return undefined;
173166
},
174167

@@ -187,6 +180,10 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
187180
// a windows style path to `releaseInjectionTargets`
188181
const normalizedId = path.normalize(id);
189182

183+
if (id.includes("release-injection-file")) {
184+
return true;
185+
}
186+
190187
if (internalOptions.releaseInjectionTargets) {
191188
// If there's an `releaseInjectionTargets` option transform (ie. inject the release varible) when the file path matches the option.
192189
if (typeof internalOptions.releaseInjectionTargets === "function") {
@@ -201,16 +198,14 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
201198
return normalizedId === normalizedEntry;
202199
}
203200
});
204-
} else if (absolueEntrypointPaths.has(normalizedId)) {
201+
} else {
205202
const pathIsOrdinary = !normalizedId.includes("?") && !normalizedId.includes("#");
206203

207204
const pathHasAllowedFileEnding = ALLOWED_TRANSFORMATION_FILE_ENDINGS.some(
208205
(allowedFileEnding) => normalizedId.endsWith(allowedFileEnding)
209206
);
210207

211208
return pathIsOrdinary && pathHasAllowedFileEnding;
212-
} else {
213-
return false;
214209
}
215210
},
216211

@@ -228,15 +223,22 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
228223
// The MagicString library allows us to generate sourcemaps for the changes we make to the user code.
229224
const ms = new MagicString(code);
230225

231-
ms.prepend(
232-
generateGlobalInjectorCode({
233-
release: await releaseNamePromise,
234-
injectReleasesMap: internalOptions.injectReleasesMap,
235-
injectBuildInformation: internalOptions._experiments.injectBuildInformation || false,
236-
org: internalOptions.org,
237-
project: internalOptions.project,
238-
})
239-
);
226+
if (code.includes("_sentry_release_injection_file")) {
227+
// Appending instead of prepending has less probability of mucking with user's source maps.
228+
ms.append(
229+
generateGlobalInjectorCode({
230+
release: await releaseNamePromise,
231+
injectReleasesMap: internalOptions.injectReleasesMap,
232+
injectBuildInformation: internalOptions._experiments.injectBuildInformation || false,
233+
org: internalOptions.org,
234+
project: internalOptions.project,
235+
})
236+
);
237+
} else {
238+
// Appending instead of prepending has less probability of mucking with user's source maps.
239+
// Luckily import statements get hoisted to the top anyways.
240+
ms.append(`;\nimport "@sentry/bundler-plugin-core/dist/release-injection-file";`);
241+
}
240242

241243
if (unpluginMetaContext.framework === "esbuild") {
242244
// esbuild + unplugin is buggy at the moment when we return an object with a `map` (sourcemap) property.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// This const is used for nothing except to make this file identifiable via its content.
2+
// We search for "_sentry_release_injection_file" in the plugin.
3+
export const _sentry_release_injection_file = true;

0 commit comments

Comments
 (0)