Skip to content

Commit f577a47

Browse files
feat(webpack): Add sentry/webpack-plugin/webpack5 export for webpack 5.1+ and compatible environments (#715)
1 parent 95e5cca commit f577a47

File tree

7 files changed

+288
-200
lines changed

7 files changed

+288
-200
lines changed

packages/webpack-plugin/README_TEMPLATE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pnpm add @sentry/webpack-plugin --save-dev
3737
```js
3838
// webpack.config.js
3939
const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");
40+
// for webpack 5.1 and webpack compatible environments
41+
// const { sentryWebpackPlugin } = require("@sentry/webpack-plugin/webpack5");
4042

4143
module.exports = {
4244
// ... other config above ...

packages/webpack-plugin/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,18 @@
2323
"import": "./dist/esm/index.mjs",
2424
"require": "./dist/cjs/index.js",
2525
"types": "./dist/types/index.d.ts"
26+
},
27+
"./webpack5": {
28+
"import": "./dist/esm/webpack5.mjs",
29+
"require": "./dist/cjs/webpack5.js",
30+
"types": "./dist/types/webpack5.d.ts"
2631
}
2732
},
2833
"main": "dist/cjs/index.js",
2934
"module": "dist/esm/index.mjs",
3035
"types": "dist/types/index.d.ts",
3136
"scripts": {
32-
"build": "rimraf ./out && run-p build:rollup build:types",
37+
"build": "rimraf ./dist && run-p build:rollup build:types",
3338
"build:watch": "run-p build:rollup:watch build:types:watch",
3439
"build:rollup": "rollup --config rollup.config.js",
3540
"build:rollup:watch": "rollup --config rollup.config.js --watch --no-watch.clearScreen",

packages/webpack-plugin/rollup.config.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import babel from "@rollup/plugin-babel";
33
import packageJson from "./package.json";
44
import modulePackage from "module";
55

6-
const input = ["src/index.ts"];
6+
const input = ["src/index.ts", "src/webpack5.ts"];
77

88
const extensions = [".ts"];
99

@@ -33,13 +33,14 @@ export default {
3333
],
3434
output: [
3535
{
36-
file: packageJson.module,
36+
dir: "./dist/esm",
3737
format: "esm",
3838
exports: "named",
3939
sourcemap: true,
40+
entryFileNames: "[name].mjs",
4041
},
4142
{
42-
file: packageJson.main,
43+
dir: "./dist/cjs",
4344
format: "cjs",
4445
exports: "named",
4546
sourcemap: true,

packages/webpack-plugin/src/index.ts

Lines changed: 6 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,18 @@
1-
import {
2-
getDebugIdSnippet,
3-
Options,
4-
sentryUnpluginFactory,
5-
stringToUUID,
6-
SentrySDKBuildFlags,
7-
createComponentNameAnnotateHooks,
8-
Logger,
9-
} from "@sentry/bundler-plugin-core";
10-
import * as path from "path";
11-
import { UnpluginOptions } from "unplugin";
12-
import { v4 as uuidv4 } from "uuid";
1+
import { SentryWebpackPluginOptions, sentryWebpackUnpluginFactory } from "./webpack4and5";
132

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

18-
interface BannerPluginCallbackArg {
19-
chunk?: {
20-
hash?: string;
21-
contentHash?: {
22-
javascript?: string;
23-
};
24-
};
25-
}
7+
const BannerPlugin = webpack4or5?.BannerPlugin || webpack4or5?.default?.BannerPlugin;
268

27-
function webpackReleaseInjectionPlugin(injectionCode: string): UnpluginOptions {
28-
return {
29-
name: "sentry-webpack-release-injection-plugin",
30-
webpack(compiler) {
31-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
32-
// @ts-ignore webpack version compatibility shenanigans
33-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
34-
const BannerPlugin =
35-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
36-
// @ts-ignore webpack version compatibility shenanigans
37-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
38-
compiler?.webpack?.BannerPlugin ||
39-
webpack4or5?.BannerPlugin ||
40-
webpack4or5?.default?.BannerPlugin;
41-
compiler.options.plugins = compiler.options.plugins || [];
42-
compiler.options.plugins.push(
43-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
44-
new BannerPlugin({
45-
raw: true,
46-
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
47-
banner: injectionCode,
48-
})
49-
);
50-
},
51-
};
52-
}
9+
const DefinePlugin = webpack4or5?.DefinePlugin || webpack4or5?.default?.DefinePlugin;
5310

54-
function webpackComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions {
55-
return {
56-
name: "sentry-webpack-component-name-annotate-plugin",
57-
enforce: "pre",
58-
// Webpack needs this hook for loader logic, so the plugin is not run on unsupported file types
59-
transformInclude(id) {
60-
return id.endsWith(".tsx") || id.endsWith(".jsx");
61-
},
62-
transform: createComponentNameAnnotateHooks(ignoredComponents).transform,
63-
};
64-
}
65-
66-
function webpackBundleSizeOptimizationsPlugin(
67-
replacementValues: SentrySDKBuildFlags
68-
): UnpluginOptions {
69-
return {
70-
name: "sentry-webpack-bundle-size-optimizations-plugin",
71-
webpack(compiler) {
72-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
73-
// @ts-ignore webpack version compatibility shenanigans
74-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
75-
const DefinePlugin =
76-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
77-
// @ts-ignore webpack version compatibility shenanigans
78-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
79-
compiler?.webpack?.DefinePlugin ||
80-
webpack4or5?.DefinePlugin ||
81-
webpack4or5?.default?.DefinePlugin;
82-
compiler.options.plugins = compiler.options.plugins || [];
83-
compiler.options.plugins.push(
84-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
85-
new DefinePlugin({
86-
...replacementValues,
87-
})
88-
);
89-
},
90-
};
91-
}
92-
93-
function webpackDebugIdInjectionPlugin(): UnpluginOptions {
94-
return {
95-
name: "sentry-webpack-debug-id-injection-plugin",
96-
webpack(compiler) {
97-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
98-
// @ts-ignore webpack version compatibility shenanigans
99-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
100-
const BannerPlugin =
101-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
102-
// @ts-ignore webpack version compatibility shenanigans
103-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
104-
compiler?.webpack?.BannerPlugin ||
105-
webpack4or5?.BannerPlugin ||
106-
webpack4or5?.default?.BannerPlugin;
107-
compiler.options.plugins = compiler.options.plugins || [];
108-
compiler.options.plugins.push(
109-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
110-
new BannerPlugin({
111-
raw: true,
112-
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
113-
banner: (arg?: BannerPluginCallbackArg) => {
114-
const hash = arg?.chunk?.contentHash?.javascript ?? arg?.chunk?.hash;
115-
const debugId = hash ? stringToUUID(hash) : uuidv4();
116-
return getDebugIdSnippet(debugId);
117-
},
118-
})
119-
);
120-
},
121-
};
122-
}
123-
124-
function webpackDebugIdUploadPlugin(
125-
upload: (buildArtifacts: string[]) => Promise<void>,
126-
logger: Logger,
127-
forceExitOnBuildCompletion?: boolean
128-
): UnpluginOptions {
129-
const pluginName = "sentry-webpack-debug-id-upload-plugin";
130-
return {
131-
name: pluginName,
132-
webpack(compiler) {
133-
compiler.hooks.afterEmit.tapAsync(pluginName, (compilation, callback: () => void) => {
134-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
135-
const outputPath = (compilation.outputOptions.path as string | undefined) ?? path.resolve();
136-
const buildArtifacts = Object.keys(compilation.assets as Record<string, unknown>).map(
137-
(asset) => path.join(outputPath, asset)
138-
);
139-
void upload(buildArtifacts).then(() => {
140-
callback();
141-
});
142-
});
143-
144-
if (forceExitOnBuildCompletion && compiler.options.mode === "production") {
145-
compiler.hooks.done.tap(pluginName, () => {
146-
setTimeout(() => {
147-
logger.debug("Exiting process after debug file upload");
148-
process.exit(0);
149-
});
150-
});
151-
}
152-
},
153-
};
154-
}
155-
156-
function webpackModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions {
157-
return {
158-
name: "sentry-webpack-module-metadata-injection-plugin",
159-
webpack(compiler) {
160-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
161-
// @ts-ignore webpack version compatibility shenanigans
162-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
163-
const BannerPlugin =
164-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
165-
// @ts-ignore webpack version compatibility shenanigans
166-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
167-
compiler?.webpack?.BannerPlugin ||
168-
webpack4or5?.BannerPlugin ||
169-
webpack4or5?.default?.BannerPlugin;
170-
compiler.options.plugins = compiler.options.plugins || [];
171-
compiler.options.plugins.push(
172-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call
173-
new BannerPlugin({
174-
raw: true,
175-
include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/,
176-
banner: injectionCode,
177-
})
178-
);
179-
},
180-
};
181-
}
182-
183-
const sentryUnplugin = sentryUnpluginFactory({
184-
releaseInjectionPlugin: webpackReleaseInjectionPlugin,
185-
componentNameAnnotatePlugin: webpackComponentNameAnnotatePlugin,
186-
moduleMetadataInjectionPlugin: webpackModuleMetadataInjectionPlugin,
187-
debugIdInjectionPlugin: webpackDebugIdInjectionPlugin,
188-
debugIdUploadPlugin: webpackDebugIdUploadPlugin,
189-
bundleSizeOptimizationsPlugin: webpackBundleSizeOptimizationsPlugin,
11+
const sentryUnplugin = sentryWebpackUnpluginFactory({
12+
BannerPlugin,
13+
DefinePlugin,
19014
});
19115

192-
type SentryWebpackPluginOptions = Options & {
193-
_experiments?: Options["_experiments"] & {
194-
/**
195-
* If enabled, the webpack plugin will exit the build process after the build completes.
196-
* Use this with caution, as it will terminate the process.
197-
*
198-
* More information: https://github.com/getsentry/sentry-javascript-bundler-plugins/issues/345
199-
*
200-
* @default false
201-
*/
202-
forceExitOnBuildCompletion?: boolean;
203-
};
204-
};
205-
20616
// eslint-disable-next-line @typescript-eslint/no-explicit-any
20717
export const sentryWebpackPlugin: (options?: SentryWebpackPluginOptions) => any =
20818
sentryUnplugin.webpack;

0 commit comments

Comments
 (0)