Skip to content

Commit 89b6e47

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

File tree

8 files changed

+330
-199
lines changed

8 files changed

+330
-199
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: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,25 @@
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",
34-
"build:rollup": "rollup --config rollup.config.js",
35-
"build:rollup:watch": "rollup --config rollup.config.js --watch --no-watch.clearScreen",
39+
"build:rollup": "run-p build:rollup:default build:rollup:webpack5",
40+
"build:rollup:default": "rollup --config rollup.config.default.js",
41+
"build:rollup:webpack5": "rollup --config rollup.config.webpack5.js",
42+
"build:rollup:watch": "run-p build:rollup:default:watch build:rollup:webpack5:watch",
43+
"build:rollup:default:watch": "rollup --config rollup.config.default.js --watch --no-watch.clearScreen",
44+
"build:rollup:webpack5:watch": "rollup --config rollup.config.webpack5.js --watch --no-watch.clearScreen",
3645
"build:types": "tsc --project types.tsconfig.json",
3746
"build:types:watch": "tsc --project types.tsconfig.json --watch --preserveWatchOutput",
3847
"check:types": "run-p check:types:src check:types:test",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import resolve from "@rollup/plugin-node-resolve";
2+
import babel from "@rollup/plugin-babel";
3+
import packageJson from "./package.json";
4+
import modulePackage from "module";
5+
6+
const input = ["src/webpack5.ts"];
7+
8+
const extensions = [".ts"];
9+
10+
export default {
11+
input,
12+
external: [...Object.keys(packageJson.dependencies), ...modulePackage.builtinModules, "webpack"],
13+
onwarn: (warning) => {
14+
if (warning.code === "CIRCULAR_DEPENDENCY") {
15+
// Circular dependencies are usually not a big deal for us so let's just warn about them
16+
console.warn(warning.message);
17+
return;
18+
}
19+
// Warnings are usually high-consequence for us so let's throw to catch them
20+
throw new Error(warning.message);
21+
},
22+
plugins: [
23+
resolve({
24+
extensions,
25+
rootDir: "./src",
26+
preferBuiltins: true,
27+
}),
28+
babel({
29+
extensions,
30+
babelHelpers: "bundled",
31+
include: ["src/**/*"],
32+
}),
33+
],
34+
output: [
35+
{
36+
file: packageJson.exports["./webpack5"].import,
37+
format: "esm",
38+
exports: "named",
39+
sourcemap: true,
40+
},
41+
{
42+
file: packageJson.exports["./webpack5"].require,
43+
format: "cjs",
44+
exports: "named",
45+
sourcemap: true,
46+
},
47+
],
48+
};

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 "./plugin";
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)