diff --git a/examples/reexport-components/README.md b/examples/reexport-components/README.md
index 2cc1e4bd3..857b8221f 100644
--- a/examples/reexport-components/README.md
+++ b/examples/reexport-components/README.md
@@ -26,7 +26,7 @@ export default Dashboard;
 ```javascript
 import { Button, Dialog } from "../components";
 
-const Dashboard = () => {
+const Login = () => {
 	return (
 		<>
 			
@@ -34,7 +34,7 @@ const Dashboard = () => {
 		>
 	);
 };
-export default Dashboard;
+export default Login;
 ```
 
 # components/index.js
@@ -193,11 +193,11 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _components__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../components */ "./components/Dialog.js");
 
 
-const Dashboard = () => {
+const Login = () => {
   return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(_components__WEBPACK_IMPORTED_MODULE_0__.default, null), /*#__PURE__*/React.createElement(_components__WEBPACK_IMPORTED_MODULE_1__.default, null));
 };
 
-/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Dashboard);
+/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Login);
 
 /***/ })
 
@@ -213,8 +213,8 @@ const Dashboard = () => {
 ## Unoptimized
 
 ```
-asset output.js 10.7 KiB [emitted] (name: main)
-asset pages_Login_js.output.js 2.85 KiB [emitted]
+asset output.js 10.8 KiB [emitted] (name: main)
+asset pages_Login_js.output.js 2.84 KiB [emitted]
 asset pages_Dashboard_js.output.js 2.8 KiB [emitted]
 chunk (runtime: main) output.js (main) 208 bytes (javascript) 5.42 KiB (runtime) [entry] [rendered]
   > ./example.js main
@@ -231,15 +231,15 @@ chunk (runtime: main) pages_Dashboard_js.output.js 513 bytes [rendered]
     [exports: default]
     context element ./Dashboard ./pages/ lazy ^\.\/.*$ namespace object ./Dashboard
     context element ./Dashboard.js ./pages/ lazy ^\.\/.*$ namespace object ./Dashboard.js
-chunk (runtime: main) pages_Login_js.output.js 512 bytes [rendered]
+chunk (runtime: main) pages_Login_js.output.js 504 bytes [rendered]
   > ./Login ./pages/ lazy ^\.\/.*$ namespace object ./Login
   > ./Login.js ./pages/ lazy ^\.\/.*$ namespace object ./Login.js
   dependent modules 247 bytes [dependent] 2 modules
-  ./pages/Login.js 265 bytes [optional] [built] [code generated]
+  ./pages/Login.js 257 bytes [optional] [built] [code generated]
     [exports: default]
     context element ./Login ./pages/ lazy ^\.\/.*$ namespace object ./Login
     context element ./Login.js ./pages/ lazy ^\.\/.*$ namespace object ./Login.js
-webpack 5.7.0 compiled successfully
+webpack 5.8.0 compiled successfully
 ```
 
 ## Production mode
@@ -263,13 +263,13 @@ chunk (runtime: main) pages_Dashboard_js.output.js 513 bytes [rendered]
     [exports: default]
     context element ./Dashboard ./pages/ lazy ^\.\/.*$ namespace object ./Dashboard
     context element ./Dashboard.js ./pages/ lazy ^\.\/.*$ namespace object ./Dashboard.js
-chunk (runtime: main) pages_Login_js.output.js 512 bytes [rendered]
+chunk (runtime: main) pages_Login_js.output.js 504 bytes [rendered]
   > ./Login ./pages/ lazy ^\.\/.*$ namespace object ./Login
   > ./Login.js ./pages/ lazy ^\.\/.*$ namespace object ./Login.js
   dependent modules 115 bytes [dependent] 1 module
-  ./pages/Login.js + 1 modules 397 bytes [optional] [built] [code generated]
+  ./pages/Login.js + 1 modules 389 bytes [optional] [built] [code generated]
     [exports: default]
     context element ./Login ./pages/ lazy ^\.\/.*$ namespace object ./Login
     context element ./Login.js ./pages/ lazy ^\.\/.*$ namespace object ./Login.js
-webpack 5.7.0 compiled successfully
+webpack 5.8.0 compiled successfully
 ```
diff --git a/examples/reexport-components/components/package.json b/examples/reexport-components/components/package.json
deleted file mode 100644
index a43829151..000000000
--- a/examples/reexport-components/components/package.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "sideEffects": false
-}
diff --git a/examples/reexport-components/pages/Login.js b/examples/reexport-components/pages/Login.js
index e1b5b2cab..d622c35ad 100644
--- a/examples/reexport-components/pages/Login.js
+++ b/examples/reexport-components/pages/Login.js
@@ -1,6 +1,6 @@
 import { Button, Dialog } from "../components";
 
-const Dashboard = () => {
+const Login = () => {
 	return (
 		<>
 			
@@ -8,4 +8,4 @@ const Dashboard = () => {
 		>
 	);
 };
-export default Dashboard;
+export default Login;
diff --git a/lib/NormalModule.js b/lib/NormalModule.js
index 70025f243..190eb87c3 100644
--- a/lib/NormalModule.js
+++ b/lib/NormalModule.js
@@ -26,6 +26,7 @@ const ModuleWarning = require("./ModuleWarning");
 const RuntimeGlobals = require("./RuntimeGlobals");
 const UnhandledSchemeError = require("./UnhandledSchemeError");
 const WebpackError = require("./WebpackError");
+const formatLocation = require("./formatLocation");
 const LazySet = require("./util/LazySet");
 const { getScheme } = require("./util/URLAbsoluteSpecifier");
 const {
@@ -248,6 +249,7 @@ class NormalModule extends Module {
 		this._lastSuccessfulBuildMeta = {};
 		this._forceBuild = true;
 		this._isEvaluatingSideEffects = false;
+		this._addedSideEffectsBailout = new WeakSet();
 	}
 
 	/**
@@ -877,6 +879,17 @@ class NormalModule extends Module {
 			for (const dep of this.dependencies) {
 				const state = dep.getModuleEvaluationSideEffectsState(moduleGraph);
 				if (state === true) {
+					if (!this._addedSideEffectsBailout.has(moduleGraph)) {
+						this._addedSideEffectsBailout.add(moduleGraph);
+						moduleGraph
+							.getOptimizationBailout(this)
+							.push(
+								() =>
+									`Dependency (${
+										dep.type
+									}) with side effects at ${formatLocation(dep.loc)}`
+							);
+					}
 					this._isEvaluatingSideEffects = false;
 					return true;
 				} else if (state !== ModuleGraphConnection.CIRCULAR_CONNECTION) {
diff --git a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js
index 71f508af2..67b40677c 100644
--- a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js
+++ b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js
@@ -370,6 +370,14 @@ class HarmonyExportImportedSpecifierDependency extends HarmonyImportDependency {
 		};
 	}
 
+	/**
+	 * @param {ModuleGraph} moduleGraph the module graph
+	 * @returns {ConnectionState} how this dependency connects the module to referencing modules
+	 */
+	getModuleEvaluationSideEffectsState(moduleGraph) {
+		return false;
+	}
+
 	/**
 	 * Returns list of exports referenced by this dependency
 	 * @param {ModuleGraph} moduleGraph module graph
diff --git a/lib/dependencies/HarmonyImportSpecifierDependency.js b/lib/dependencies/HarmonyImportSpecifierDependency.js
index 3b17e58b3..3a0a6d877 100644
--- a/lib/dependencies/HarmonyImportSpecifierDependency.js
+++ b/lib/dependencies/HarmonyImportSpecifierDependency.js
@@ -88,6 +88,14 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 			this.checkUsedByExports(moduleGraph, runtime);
 	}
 
+	/**
+	 * @param {ModuleGraph} moduleGraph the module graph
+	 * @returns {ConnectionState} how this dependency connects the module to referencing modules
+	 */
+	getModuleEvaluationSideEffectsState(moduleGraph) {
+		return false;
+	}
+
 	checkUsedByExports(moduleGraph, runtime) {
 		if (this.usedByExports === false) return false;
 		if (this.usedByExports !== true && this.usedByExports !== undefined) {
diff --git a/lib/optimize/SideEffectsFlagPlugin.js b/lib/optimize/SideEffectsFlagPlugin.js
index dc06e66cd..10e168b52 100644
--- a/lib/optimize/SideEffectsFlagPlugin.js
+++ b/lib/optimize/SideEffectsFlagPlugin.js
@@ -9,6 +9,7 @@ const glob2regexp = require("glob-to-regexp");
 const { STAGE_DEFAULT } = require("../OptimizationStages");
 const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency");
 const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency");
+const formatLocation = require("../formatLocation");
 
 /** @typedef {import("../Compiler")} Compiler */
 /** @typedef {import("../Dependency")} Dependency */
@@ -67,223 +68,242 @@ class SideEffectsFlagPlugin {
 			cache = new Map();
 			globToRegexpCache.set(compiler.root, cache);
 		}
-		compiler.hooks.normalModuleFactory.tap("SideEffectsFlagPlugin", nmf => {
-			nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {
-				const resolveData = data.resourceResolveData;
-				if (
-					resolveData &&
-					resolveData.descriptionFileData &&
-					resolveData.relativePath
-				) {
-					const sideEffects = resolveData.descriptionFileData.sideEffects;
-					const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(
-						resolveData.relativePath,
-						sideEffects,
-						cache
-					);
-					if (!hasSideEffects) {
-						if (module.factoryMeta === undefined) {
-							module.factoryMeta = {};
-						}
-						module.factoryMeta.sideEffectFree = true;
-					}
-				}
-
-				return module;
-			});
-			nmf.hooks.module.tap("SideEffectsFlagPlugin", (module, data) => {
-				if (data.settings.sideEffects === false) {
-					if (module.factoryMeta === undefined) {
-						module.factoryMeta = {};
-					}
-					module.factoryMeta.sideEffectFree = true;
-				} else if (data.settings.sideEffects === true) {
-					if (module.factoryMeta !== undefined) {
-						module.factoryMeta.sideEffectFree = false;
-					}
-				}
-				return module;
-			});
-			if (this._analyseSource) {
-				/**
-				 * @param {JavascriptParser} parser the parser
-				 * @returns {void}
-				 */
-				const parserHandler = parser => {
-					let hasSideEffects = false;
-					parser.hooks.program.tap("SideEffectsFlagPlugin", () => {
-						hasSideEffects = false;
-					});
-					parser.hooks.statement.tap(
-						{ name: "SideEffectsFlagPlugin", stage: -100 },
-						statement => {
-							if (hasSideEffects) return;
-							if (parser.scope.topLevelScope !== true) return;
-							switch (statement.type) {
-								case "ExpressionStatement":
-									if (
-										!parser.isPure(statement.expression, statement.range[0])
-									) {
-										hasSideEffects = true;
-									}
-									break;
-								case "IfStatement":
-								case "WhileStatement":
-								case "DoWhileStatement":
-									if (!parser.isPure(statement.test, statement.range[0])) {
-										hasSideEffects = true;
-									}
-									// statement hook will be called for child statements too
-									break;
-								case "ForStatement":
-									if (
-										!parser.isPure(statement.init, statement.range[0]) ||
-										!parser.isPure(
-											statement.test,
-											statement.init
-												? statement.init.range[1]
-												: statement.range[0]
-										) ||
-										!parser.isPure(
-											statement.update,
-											statement.test
-												? statement.test.range[1]
-												: statement.init
-												? statement.init.range[1]
-												: statement.range[0]
-										)
-									) {
-										hasSideEffects = true;
-									}
-									// statement hook will be called for child statements too
-									break;
-								case "SwitchStatement":
-									if (
-										!parser.isPure(statement.discriminant, statement.range[0])
-									) {
-										hasSideEffects = true;
-									}
-									// statement hook will be called for child statements too
-									break;
-								case "VariableDeclaration":
-								case "ClassDeclaration":
-								case "FunctionDeclaration":
-									if (!parser.isPure(statement, statement.range[0])) {
-										hasSideEffects = true;
-									}
-									break;
-								case "ExportDefaultDeclaration":
-									if (
-										!parser.isPure(statement.declaration, statement.range[0])
-									) {
-										hasSideEffects = true;
-									}
-									break;
-								case "ExportNamedDeclaration":
-									if (statement.source) {
-										hasSideEffects = true;
-									}
-									break;
-								case "LabeledStatement":
-								case "BlockStatement":
-									// statement hook will be called for child statements too
-									break;
-								case "EmptyStatement":
-									break;
-								case "ImportDeclaration":
-									// imports will be handled by the dependencies
-									break;
-								default:
-									hasSideEffects = true;
-									break;
+		compiler.hooks.compilation.tap(
+			"SideEffectsFlagPlugin",
+			(compilation, { normalModuleFactory }) => {
+				const moduleGraph = compilation.moduleGraph;
+				normalModuleFactory.hooks.module.tap(
+					"SideEffectsFlagPlugin",
+					(module, data) => {
+						const resolveData = data.resourceResolveData;
+						if (
+							resolveData &&
+							resolveData.descriptionFileData &&
+							resolveData.relativePath
+						) {
+							const sideEffects = resolveData.descriptionFileData.sideEffects;
+							const hasSideEffects = SideEffectsFlagPlugin.moduleHasSideEffects(
+								resolveData.relativePath,
+								sideEffects,
+								cache
+							);
+							if (!hasSideEffects) {
+								if (module.factoryMeta === undefined) {
+									module.factoryMeta = {};
+								}
+								module.factoryMeta.sideEffectFree = true;
 							}
 						}
-					);
-					parser.hooks.finish.tap("SideEffectsFlagPlugin", () => {
-						if (!hasSideEffects) {
-							parser.state.module.buildMeta.sideEffectFree = true;
+
+						return module;
+					}
+				);
+				normalModuleFactory.hooks.module.tap(
+					"SideEffectsFlagPlugin",
+					(module, data) => {
+						if (data.settings.sideEffects === false) {
+							if (module.factoryMeta === undefined) {
+								module.factoryMeta = {};
+							}
+							module.factoryMeta.sideEffectFree = true;
+						} else if (data.settings.sideEffects === true) {
+							if (module.factoryMeta !== undefined) {
+								module.factoryMeta.sideEffectFree = false;
+							}
 						}
-					});
-				};
-				for (const key of [
-					"javascript/auto",
-					"javascript/esm",
-					"javascript/dynamic"
-				]) {
-					nmf.hooks.parser.for(key).tap("SideEffectsFlagPlugin", parserHandler);
+						return module;
+					}
+				);
+				if (this._analyseSource) {
+					/**
+					 * @param {JavascriptParser} parser the parser
+					 * @returns {void}
+					 */
+					const parserHandler = parser => {
+						let sideEffectsStatement;
+						parser.hooks.program.tap("SideEffectsFlagPlugin", () => {
+							sideEffectsStatement = undefined;
+						});
+						parser.hooks.statement.tap(
+							{ name: "SideEffectsFlagPlugin", stage: -100 },
+							statement => {
+								if (sideEffectsStatement) return;
+								if (parser.scope.topLevelScope !== true) return;
+								switch (statement.type) {
+									case "ExpressionStatement":
+										if (
+											!parser.isPure(statement.expression, statement.range[0])
+										) {
+											sideEffectsStatement = statement;
+										}
+										break;
+									case "IfStatement":
+									case "WhileStatement":
+									case "DoWhileStatement":
+										if (!parser.isPure(statement.test, statement.range[0])) {
+											sideEffectsStatement = statement;
+										}
+										// statement hook will be called for child statements too
+										break;
+									case "ForStatement":
+										if (
+											!parser.isPure(statement.init, statement.range[0]) ||
+											!parser.isPure(
+												statement.test,
+												statement.init
+													? statement.init.range[1]
+													: statement.range[0]
+											) ||
+											!parser.isPure(
+												statement.update,
+												statement.test
+													? statement.test.range[1]
+													: statement.init
+													? statement.init.range[1]
+													: statement.range[0]
+											)
+										) {
+											sideEffectsStatement = statement;
+										}
+										// statement hook will be called for child statements too
+										break;
+									case "SwitchStatement":
+										if (
+											!parser.isPure(statement.discriminant, statement.range[0])
+										) {
+											sideEffectsStatement = statement;
+										}
+										// statement hook will be called for child statements too
+										break;
+									case "VariableDeclaration":
+									case "ClassDeclaration":
+									case "FunctionDeclaration":
+										if (!parser.isPure(statement, statement.range[0])) {
+											sideEffectsStatement = statement;
+										}
+										break;
+									case "ExportNamedDeclaration":
+									case "ExportDefaultDeclaration":
+										if (
+											!parser.isPure(statement.declaration, statement.range[0])
+										) {
+											sideEffectsStatement = statement;
+										}
+										break;
+									case "LabeledStatement":
+									case "BlockStatement":
+										// statement hook will be called for child statements too
+										break;
+									case "EmptyStatement":
+										break;
+									case "ExportAllDeclaration":
+									case "ImportDeclaration":
+										// imports will be handled by the dependencies
+										break;
+									default:
+										sideEffectsStatement = statement;
+										break;
+								}
+							}
+						);
+						parser.hooks.finish.tap("SideEffectsFlagPlugin", () => {
+							if (sideEffectsStatement === undefined) {
+								parser.state.module.buildMeta.sideEffectFree = true;
+							} else {
+								const { loc, type } = sideEffectsStatement;
+								moduleGraph
+									.getOptimizationBailout(parser.state.module)
+									.push(
+										() =>
+											`Statement (${type}) with side effects in source code at ${formatLocation(
+												loc
+											)}`
+									);
+							}
+						});
+					};
+					for (const key of [
+						"javascript/auto",
+						"javascript/esm",
+						"javascript/dynamic"
+					]) {
+						normalModuleFactory.hooks.parser
+							.for(key)
+							.tap("SideEffectsFlagPlugin", parserHandler);
+					}
 				}
-			}
-		});
-		compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => {
-			const moduleGraph = compilation.moduleGraph;
-			compilation.hooks.optimizeDependencies.tap(
-				{
-					name: "SideEffectsFlagPlugin",
-					stage: STAGE_DEFAULT
-				},
-				modules => {
-					const logger = compilation.getLogger("webpack.SideEffectsFlagPlugin");
+				compilation.hooks.optimizeDependencies.tap(
+					{
+						name: "SideEffectsFlagPlugin",
+						stage: STAGE_DEFAULT
+					},
+					modules => {
+						const logger = compilation.getLogger(
+							"webpack.SideEffectsFlagPlugin"
+						);
 
-					logger.time("update dependencies");
-					for (const module of modules) {
-						if (module.getSideEffectsConnectionState(moduleGraph) === false) {
-							const exportsInfo = moduleGraph.getExportsInfo(module);
-							for (const connection of moduleGraph.getIncomingConnections(
-								module
-							)) {
-								const dep = connection.dependency;
-								let isReexport;
-								if (
-									(isReexport =
-										dep instanceof HarmonyExportImportedSpecifierDependency) ||
-									(dep instanceof HarmonyImportSpecifierDependency &&
-										!dep.namespaceObjectAsContext)
-								) {
-									// TODO improve for export *
-									if (isReexport && dep.name) {
-										const exportInfo = moduleGraph.getExportInfo(
-											connection.originModule,
-											dep.name
-										);
-										exportInfo.moveTarget(
-											moduleGraph,
-											({ module }) =>
-												module.getSideEffectsConnectionState(moduleGraph) ===
-												false
-										);
-									}
-									// TODO improve for nested imports
-									const ids = dep.getIds(moduleGraph);
-									if (ids.length > 0) {
-										const exportInfo = exportsInfo.getExportInfo(ids[0]);
-										const target = exportInfo.moveTarget(
-											moduleGraph,
-											({ module }) =>
-												module.getSideEffectsConnectionState(moduleGraph) ===
-												false
-										);
-										if (!target) continue;
+						logger.time("update dependencies");
+						for (const module of modules) {
+							if (module.getSideEffectsConnectionState(moduleGraph) === false) {
+								const exportsInfo = moduleGraph.getExportsInfo(module);
+								for (const connection of moduleGraph.getIncomingConnections(
+									module
+								)) {
+									const dep = connection.dependency;
+									let isReexport;
+									if (
+										(isReexport =
+											dep instanceof
+											HarmonyExportImportedSpecifierDependency) ||
+										(dep instanceof HarmonyImportSpecifierDependency &&
+											!dep.namespaceObjectAsContext)
+									) {
+										// TODO improve for export *
+										if (isReexport && dep.name) {
+											const exportInfo = moduleGraph.getExportInfo(
+												connection.originModule,
+												dep.name
+											);
+											exportInfo.moveTarget(
+												moduleGraph,
+												({ module }) =>
+													module.getSideEffectsConnectionState(moduleGraph) ===
+													false
+											);
+										}
+										// TODO improve for nested imports
+										const ids = dep.getIds(moduleGraph);
+										if (ids.length > 0) {
+											const exportInfo = exportsInfo.getExportInfo(ids[0]);
+											const target = exportInfo.moveTarget(
+												moduleGraph,
+												({ module }) =>
+													module.getSideEffectsConnectionState(moduleGraph) ===
+													false
+											);
+											if (!target) continue;
 
-										moduleGraph.updateModule(dep, target.module);
-										moduleGraph.addExplanation(
-											dep,
-											"(skipped side-effect-free modules)"
-										);
-										dep.setIds(
-											moduleGraph,
-											target.export
-												? [...target.export, ...ids.slice(1)]
-												: ids.slice(1)
-										);
+											moduleGraph.updateModule(dep, target.module);
+											moduleGraph.addExplanation(
+												dep,
+												"(skipped side-effect-free modules)"
+											);
+											dep.setIds(
+												moduleGraph,
+												target.export
+													? [...target.export, ...ids.slice(1)]
+													: ids.slice(1)
+											);
+										}
 									}
 								}
 							}
 						}
+						logger.timeEnd("update dependencies");
 					}
-					logger.timeEnd("update dependencies");
-				}
-			);
-		});
+				);
+			}
+		);
 	}
 
 	static moduleHasSideEffects(moduleName, flagValue, cache) {
diff --git a/test/cases/side-effects/empty-modules/referenced.js b/test/cases/side-effects/empty-modules/referenced.js
index a0bbc72ac..78ab18199 100644
--- a/test/cases/side-effects/empty-modules/referenced.js
+++ b/test/cases/side-effects/empty-modules/referenced.js
@@ -1,3 +1,8 @@
 import "./module";
 import "./cjs";
-import "./pure";
+import { unusedExport } from "./pure";
+export { unusedExport } from "./pure";
+
+export function unused() {
+	return unusedExport;
+}