Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/webpack-plugin/README_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pnpm add @sentry/webpack-plugin --save-dev
```js
// webpack.config.js
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
// for webpack 5.1 and webpack compatible environments
// const { sentryWebpackPlugin } = require("@sentry/webpack-plugin/webpack5");

module.exports = {
// ... other config above ...
Expand Down
7 changes: 6 additions & 1 deletion packages/webpack-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@
"import": "./dist/esm/index.mjs",
"require": "./dist/cjs/index.js",
"types": "./dist/types/index.d.ts"
},
"./webpack5": {
"import": "./dist/esm/webpack5.mjs",
"require": "./dist/cjs/webpack5.js",
"types": "./dist/types/webpack5.d.ts"
}
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.mjs",
"types": "dist/types/index.d.ts",
"scripts": {
"build": "rimraf ./out && run-p build:rollup build:types",
"build": "rimraf ./dist && run-p build:rollup build:types",
"build:watch": "run-p build:rollup:watch build:types:watch",
"build:rollup": "rollup --config rollup.config.js",
"build:rollup:watch": "rollup --config rollup.config.js --watch --no-watch.clearScreen",
Expand Down
7 changes: 4 additions & 3 deletions packages/webpack-plugin/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import babel from "@rollup/plugin-babel";
import packageJson from "./package.json";
import modulePackage from "module";

const input = ["src/index.ts"];
const input = ["src/index.ts", "src/webpack5.ts"];

const extensions = [".ts"];

Expand Down Expand Up @@ -33,13 +33,14 @@ export default {
],
output: [
{
file: packageJson.module,
dir: "./dist/esm",
format: "esm",
exports: "named",
sourcemap: true,
entryFileNames: "[name].mjs",
},
{
file: packageJson.main,
dir: "./dist/cjs",
format: "cjs",
exports: "named",
sourcemap: true,
Expand Down
202 changes: 6 additions & 196 deletions packages/webpack-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,208 +1,18 @@
import {
getDebugIdSnippet,
Options,
sentryUnpluginFactory,
stringToUUID,
SentrySDKBuildFlags,
createComponentNameAnnotateHooks,
Logger,
} from "@sentry/bundler-plugin-core";
import * as path from "path";
import { UnpluginOptions } from "unplugin";
import { v4 as uuidv4 } from "uuid";
import { SentryWebpackPluginOptions, sentryWebpackUnpluginFactory } from "./webpack4and5";

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack is a peer dep
import * as webpack4or5 from "webpack";

interface BannerPluginCallbackArg {
chunk?: {
hash?: string;
contentHash?: {
javascript?: string;
};
};
}
const BannerPlugin = webpack4or5?.BannerPlugin || webpack4or5?.default?.BannerPlugin;

function webpackReleaseInjectionPlugin(injectionCode: string): UnpluginOptions {
return {
name: "sentry-webpack-release-injection-plugin",
webpack(compiler) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const BannerPlugin =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
compiler?.webpack?.BannerPlugin ||
webpack4or5?.BannerPlugin ||
webpack4or5?.default?.BannerPlugin;
compiler.options.plugins = compiler.options.plugins || [];
compiler.options.plugins.push(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
new BannerPlugin({
raw: true,
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
banner: injectionCode,
})
);
},
};
}
const DefinePlugin = webpack4or5?.DefinePlugin || webpack4or5?.default?.DefinePlugin;

function webpackComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions {
return {
name: "sentry-webpack-component-name-annotate-plugin",
enforce: "pre",
// Webpack needs this hook for loader logic, so the plugin is not run on unsupported file types
transformInclude(id) {
return id.endsWith(".tsx") || id.endsWith(".jsx");
},
transform: createComponentNameAnnotateHooks(ignoredComponents).transform,
};
}

function webpackBundleSizeOptimizationsPlugin(
replacementValues: SentrySDKBuildFlags
): UnpluginOptions {
return {
name: "sentry-webpack-bundle-size-optimizations-plugin",
webpack(compiler) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const DefinePlugin =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
compiler?.webpack?.DefinePlugin ||
webpack4or5?.DefinePlugin ||
webpack4or5?.default?.DefinePlugin;
compiler.options.plugins = compiler.options.plugins || [];
compiler.options.plugins.push(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
new DefinePlugin({
...replacementValues,
})
);
},
};
}

function webpackDebugIdInjectionPlugin(): UnpluginOptions {
return {
name: "sentry-webpack-debug-id-injection-plugin",
webpack(compiler) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const BannerPlugin =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
compiler?.webpack?.BannerPlugin ||
webpack4or5?.BannerPlugin ||
webpack4or5?.default?.BannerPlugin;
compiler.options.plugins = compiler.options.plugins || [];
compiler.options.plugins.push(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
new BannerPlugin({
raw: true,
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
banner: (arg?: BannerPluginCallbackArg) => {
const hash = arg?.chunk?.contentHash?.javascript ?? arg?.chunk?.hash;
const debugId = hash ? stringToUUID(hash) : uuidv4();
return getDebugIdSnippet(debugId);
},
})
);
},
};
}

function webpackDebugIdUploadPlugin(
upload: (buildArtifacts: string[]) => Promise<void>,
logger: Logger,
forceExitOnBuildCompletion?: boolean
): UnpluginOptions {
const pluginName = "sentry-webpack-debug-id-upload-plugin";
return {
name: pluginName,
webpack(compiler) {
compiler.hooks.afterEmit.tapAsync(pluginName, (compilation, callback: () => void) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
const outputPath = (compilation.outputOptions.path as string | undefined) ?? path.resolve();
const buildArtifacts = Object.keys(compilation.assets as Record<string, unknown>).map(
(asset) => path.join(outputPath, asset)
);
void upload(buildArtifacts).then(() => {
callback();
});
});

if (forceExitOnBuildCompletion && compiler.options.mode === "production") {
compiler.hooks.done.tap(pluginName, () => {
setTimeout(() => {
logger.debug("Exiting process after debug file upload");
process.exit(0);
});
});
}
},
};
}

function webpackModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions {
return {
name: "sentry-webpack-module-metadata-injection-plugin",
webpack(compiler) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
const BannerPlugin =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore webpack version compatibility shenanigans
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
compiler?.webpack?.BannerPlugin ||
webpack4or5?.BannerPlugin ||
webpack4or5?.default?.BannerPlugin;
compiler.options.plugins = compiler.options.plugins || [];
compiler.options.plugins.push(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
new BannerPlugin({
raw: true,
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
banner: injectionCode,
})
);
},
};
}

const sentryUnplugin = sentryUnpluginFactory({
releaseInjectionPlugin: webpackReleaseInjectionPlugin,
componentNameAnnotatePlugin: webpackComponentNameAnnotatePlugin,
moduleMetadataInjectionPlugin: webpackModuleMetadataInjectionPlugin,
debugIdInjectionPlugin: webpackDebugIdInjectionPlugin,
debugIdUploadPlugin: webpackDebugIdUploadPlugin,
bundleSizeOptimizationsPlugin: webpackBundleSizeOptimizationsPlugin,
const sentryUnplugin = sentryWebpackUnpluginFactory({
BannerPlugin,
DefinePlugin,
});

type SentryWebpackPluginOptions = Options & {
_experiments?: Options["_experiments"] & {
/**
* If enabled, the webpack plugin will exit the build process after the build completes.
* Use this with caution, as it will terminate the process.
*
* More information: https://github.com/getsentry/sentry-javascript-bundler-plugins/issues/345
*
* @default false
*/
forceExitOnBuildCompletion?: boolean;
};
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const sentryWebpackPlugin: (options?: SentryWebpackPluginOptions) => any =
sentryUnplugin.webpack;
Expand Down
Loading
Loading