Skip to content
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

feat(webpack): Add debug ID injection to the webpack plugin #198

Merged
merged 4 commits into from Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/bundler-plugin-core/package.json
Expand Up @@ -42,7 +42,8 @@
"find-up": "5.0.0",
"glob": "9.3.2",
"magic-string": "0.27.0",
"unplugin": "1.0.1"
"unplugin": "1.0.1",
"webpack-sources": "^3.2.3"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: should we hard pin? Also this doesn't change yarn.lock?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. Added. The yarn lock didn't change because unplugin itself depended on the exact same version.

},
"devDependencies": {
"@babel/core": "7.18.5",
Expand Down
4 changes: 2 additions & 2 deletions packages/bundler-plugin-core/src/debug-id.ts
Expand Up @@ -9,9 +9,9 @@ import { stringToUUID } from "./utils";
const DEBUG_ID_INJECTOR_SNIPPET =
';!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]="__SENTRY_DEBUG_ID__",e._sentryDebugIdIdentifier="sentry-dbid-__SENTRY_DEBUG_ID__")}catch(e){}}();';

export function injectDebugIdSnippetIntoChunk(code: string) {
export function injectDebugIdSnippetIntoChunk(code: string, filename?: string) {
const debugId = stringToUUID(code); // generate a deterministic debug ID
const ms = new MagicString(code);
const ms = new MagicString(code, { filename });

const codeToInject = DEBUG_ID_INJECTOR_SNIPPET.replace(/__SENTRY_DEBUG_ID__/g, debugId);

Expand Down
52 changes: 52 additions & 0 deletions packages/bundler-plugin-core/src/index.ts
Expand Up @@ -30,6 +30,8 @@ import util from "util";
import { getDependencies, getPackageJson, parseMajorVersion } from "./utils";
import { glob } from "glob";
import { injectDebugIdSnippetIntoChunk, prepareBundleForDebugIdUpload } from "./debug-id";
import { SourceMapSource } from "webpack-sources";
import type { sources } from "webpack";

const ALLOWED_TRANSFORMATION_FILE_ENDINGS = [".js", ".ts", ".jsx", ".tsx", ".mjs"];

Expand Down Expand Up @@ -389,6 +391,56 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
}
},
},
webpack(compiler) {
if (options._experiments?.debugIdUpload) {
compiler.hooks.compilation.tap("sentry-plugin", (compilation) => {
compilation.hooks.optimizeChunkAssets.tap("sentry-plugin", (chunks) => {
chunks.forEach((chunk) => {
const fileNames = chunk.files;
fileNames.forEach((fileName) => {
const source = compilation.assets[fileName];

if (!source) {
logger.warn(
"Unable to access compilation assets. If you see this warning, it is likely a bug in the Sentry webpack plugin. Feel free to open an issue at https://github.com/getsentry/sentry-javascript-bundler-plugins with reproduction steps."
);
return;
}

compilation.updateAsset(fileName, () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to cache here? So we only inject once?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the cache inspired by webpack/webpack#15454

const originalCode = source.source().toString();

// The source map type is very annoying :(
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
const originalSourceMap = source.map() as any;

const { code: newCode, map: newSourceMap } = injectDebugIdSnippetIntoChunk(
originalCode,
fileName
);

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
newSourceMap.sources = originalSourceMap.sources as string[];

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
newSourceMap.sourcesContent = originalSourceMap.sourcesContent as string[];

return new SourceMapSource(
newCode,
fileName,
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
originalSourceMap,
originalCode,
newSourceMap,
false
) as sources.Source;
});
});
});
});
});
}
},
};
});

Expand Down