Repository: webpack/webpack (JavaScript)

Issue:
mangled exports breaks with destructuring assignment of JSON imports
<!-- Please don't delete this template because we'll close your issue -->
<!-- Before creating an issue please make sure you are using the latest version of webpack. -->

# Bug report

<!-- Please ask questions on StackOverflow or the GitHub Discussions. -->
<!-- https://github.com/webpack/webpack/discussions -->
<!-- https://stackoverflow.com/questions/ask?tags=webpack -->
<!-- Issues which contain questions or support requests will be closed. -->

**What is the current behavior?**

As of 5.90.2 (including 5.91.0), destructuring assignment on a JSON import does not work because the property names have been changed (using default settings). Setting `optimization.mangleExports` to `false` fixes this, but it worked fine in 5.90.1 and it works fine accessing properties with dot notation in 5.90.2+. 

Essentially the following:
```
import data from './data.json';

// this works ...
console.log(data.foo.bar)

// ...but this does not
const { bar } = data.foo;
```

**If the current behavior is a bug, please provide the steps to reproduce.**

https://github.com/ikydd-bbc/spike-webpack-minify-bug

<!-- A great way to do this is to provide your configuration via a GitHub repository -->
<!-- The most helpful is a minimal reproduction with instructions on how to reproduce -->
<!-- Repositories with too many files or large `webpack.config.js` files are not suitable -->
<!-- Please only add small code snippets directly into this issue -->
<!-- https://gist.github.com is a good place for longer code snippets -->
<!-- If your issue is caused by a plugin or loader, please create an issue on the loader/plugin repository instead -->

**What is the expected behavior?**

Destructuring of JSON imports should work as they did previously in 5.90.1. We should be able to import a JSON file using the default export and then use destructuring assignment to pick out whatever properties we choose. 

<!-- "It should work" is not a helpful explanation -->
<!-- Explain exactly how it should behave -->

**Other relevant information:**
webpack version:  5.90.2 + 
Node.js version: 18.19.0
Operating System: OSX
Additional tools:



Hints:
Thank you for the issue, do you want to send a pr?
> Thank you for the issue, do you want to send a pr?

Unfortunately I have no experience working with webpack internals or the details of project goals, so while I might be curious and have a dig to see what's what I couldn't commit to trying to fix this.
/cc @ahabhgk  What do you think? I don't like named export with JSON at all, because it volates a spec - there is no named export with JSON files, only `default` (should we output a warning on it? with `futureDefaults: true`), maybe we should disable mangle at all for JSON modules?
I think there is already have a warning for named export with JSON https://github.com/webpack/webpack/blob/7090328ba33f8887db2dcf41767ba72f7bfb90bd/lib/json/JsonParser.js#L62-L63

What about disable named export with JSON in next major and when `futureDefaults: true`?

I will take a look and try to fix this bug in the next few days
@ikydd-bbc Just intresting, why you used named export for JSON? Legacy code?
@alexander-akait 
The use case shown is not really a named export from JSON though, is it?
It uses a default import and then destructures the already imported default.

> ```
> import data from './data.json';
> 
> // this works ...
> console.log(data.foo.bar)
> 
> // ...but this does not
> const { bar } = data.foo;
> ```
@alopix Oh, I see, my mistake, sometimes the eyes are wrong :smile: We will look at this soon

Patch:
diff --git a/lib/DefinePlugin.js b/lib/DefinePlugin.js
--- a/lib/DefinePlugin.js
+++ b/lib/DefinePlugin.js
@@ -27,6 +27,7 @@ const createHash = require("./util/createHash");
 /** @typedef {import("./NormalModule")} NormalModule */
 /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
 /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
+/** @typedef {import("./javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
 /** @typedef {import("./javascript/JavascriptParser").Range} Range */
 /** @typedef {import("./logging/Logger").Logger} Logger */
 
@@ -114,6 +115,15 @@ class RuntimeValue {
 	}
 }
 
+/**
+ * @param {Set<DestructuringAssignmentProperty> | undefined} properties properties
+ * @returns {Set<string> | undefined} used keys
+ */
+function getObjKeys(properties) {
+	if (!properties) return undefined;
+	return new Set([...properties].map(p => p.id));
+}
+
 /**
  * @param {any[]|{[k: string]: any}} obj obj
  * @param {JavascriptParser} parser Parser
@@ -491,7 +501,7 @@ class DefinePlugin {
 									runtimeTemplate,
 									logger,
 									!parser.isAsiPosition(/** @type {Range} */ (expr.range)[0]),
-									parser.destructuringAssignmentPropertiesFor(expr)
+									null
 								);
 
 								if (parser.scope.inShorthand) {
@@ -597,7 +607,7 @@ class DefinePlugin {
 								runtimeTemplate,
 								logger,
 								!parser.isAsiPosition(/** @type {Range} */ (expr.range)[0]),
-								parser.destructuringAssignmentPropertiesFor(expr)
+								getObjKeys(parser.destructuringAssignmentPropertiesFor(expr))
 							);
 
 							if (parser.scope.inShorthand) {
diff --git a/lib/dependencies/HarmonyImportDependencyParserPlugin.js b/lib/dependencies/HarmonyImportDependencyParserPlugin.js
--- a/lib/dependencies/HarmonyImportDependencyParserPlugin.js
+++ b/lib/dependencies/HarmonyImportDependencyParserPlugin.js
@@ -29,6 +29,7 @@ const HarmonyImportSpecifierDependency = require("./HarmonyImportSpecifierDepend
 /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
 /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
 /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
+/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
 /** @typedef {import("../javascript/JavascriptParser").Range} Range */
 /** @typedef {import("../optimize/InnerGraph").InnerGraph} InnerGraph */
 /** @typedef {import("../optimize/InnerGraph").TopLevelSymbol} TopLevelSymbol */
diff --git a/lib/dependencies/HarmonyImportSpecifierDependency.js b/lib/dependencies/HarmonyImportSpecifierDependency.js
--- a/lib/dependencies/HarmonyImportSpecifierDependency.js
+++ b/lib/dependencies/HarmonyImportSpecifierDependency.js
@@ -6,6 +6,7 @@
 "use strict";
 
 const Dependency = require("../Dependency");
+const Template = require("../Template");
 const {
 	getDependencyUsedByExportsCondition
 } = require("../optimize/InnerGraph");
@@ -28,6 +29,7 @@ const HarmonyImportDependency = require("./HarmonyImportDependency");
 /** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
 /** @typedef {import("../WebpackError")} WebpackError */
 /** @typedef {import("../javascript/JavascriptParser").Attributes} Attributes */
+/** @typedef {import("../javascript/JavascriptParser").DestructuringAssignmentProperty} DestructuringAssignmentProperty */
 /** @typedef {import("../javascript/JavascriptParser").Range} Range */
 /** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
 /** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
@@ -46,8 +48,8 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 	 * @param {string} name name
 	 * @param {Range} range range
 	 * @param {TODO} exportPresenceMode export presence mode
-	 * @param {Attributes=} attributes assertions
-	 * @param {Range[]=} idRanges ranges for members of ids; the two arrays are right-aligned
+	 * @param {Attributes | undefined} attributes assertions
+	 * @param {Range[] | undefined} idRanges ranges for members of ids; the two arrays are right-aligned
 	 */
 	constructor(
 		request,
@@ -73,7 +75,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 		this.asiSafe = undefined;
 		/** @type {Set<string> | boolean | undefined} */
 		this.usedByExports = undefined;
-		/** @type {Set<string> | undefined} */
+		/** @type {Set<DestructuringAssignmentProperty> | undefined} */
 		this.referencedPropertiesInDestructuring = undefined;
 	}
 
@@ -144,8 +146,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 	 */
 	getReferencedExports(moduleGraph, runtime) {
 		let ids = this.getIds(moduleGraph);
-		if (ids.length === 0)
-			return this._getReferencedExportsInDestructuring(moduleGraph);
+		if (ids.length === 0) return this._getReferencedExportsInDestructuring();
 		let namespaceObjectAsContext = this.namespaceObjectAsContext;
 		if (ids[0] === "default") {
 			const selfModule = moduleGraph.getParentModule(this);
@@ -162,7 +163,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 				case "default-only":
 				case "default-with-named":
 					if (ids.length === 1)
-						return this._getReferencedExportsInDestructuring(moduleGraph);
+						return this._getReferencedExportsInDestructuring();
 					ids = ids.slice(1);
 					namespaceObjectAsContext = true;
 					break;
@@ -180,31 +181,19 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
 			ids = ids.slice(0, -1);
 		}
 
-		return this._getReferencedExportsInDestructuring(moduleGraph, ids);
+		return this._getReferencedExportsInDestructuring(ids);
 	}
 
 	/**
-	 * @param {ModuleGraph} moduleGraph module graph
 	 * @param {string[]=} ids ids
-	 * @returns {(string[] | ReferencedExport)[]} referenced exports
+	 * @returns {string[][]} referenced exports
 	 */
-	_getReferencedExportsInDestructuring(moduleGraph, ids) {
+	_getReferencedExportsInDestructuring(ids) {
 		if (this.referencedPropertiesInDestructuring) {
-			/** @type {ReferencedExport[]} */
+			/** @type {string[][]} */
 			const refs = [];
-			const importedModule = moduleGraph.getModule(this);
-			const canMangle =
-				Array.isArray(ids) &&
-				ids.length > 0 &&
-				!moduleGraph
-					.getExportsInfo(importedModule)
-					.getExportInfo(ids[0])
-					.isReexport();
-			for (const key of this.referencedPropertiesInDestructuring) {
-				refs.push({
-					name: ids ? ids.concat([key]) : [key],
-					canMangle
-				});
+			for (const { id } of this.referencedPropertiesInDestructuring) {
+				refs.push(ids ? ids.concat([id]) : [id]);
 			}
 			return refs;
 		} else {
@@ -336,16 +325,11 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
 		// Skip rendering depending when dependency is conditional
 		if (connection && !connection.isTargetActive(runtime)) return;
 
+		const ids = dep.getIds(moduleGraph);
 		const {
 			trimmedRange: [trimmedRangeStart, trimmedRangeEnd],
 			trimmedIds
-		} = getTrimmedIdsAndRange(
-			dep.getIds(moduleGraph),
-			dep.range,
-			dep.idRanges,
-			moduleGraph,
-			dep
-		);
+		} = getTrimmedIdsAndRange(ids, dep.range, dep.idRanges, moduleGraph, dep);
 
 		const exportExpr = this._getCodeForIds(
 			dep,
@@ -358,6 +342,33 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
 		} else {
 			source.replace(trimmedRangeStart, trimmedRangeEnd - 1, exportExpr);
 		}
+
+		if (dep.referencedPropertiesInDestructuring) {
+			for (let {
+				id,
+				shorthand,
+				range
+			} of dep.referencedPropertiesInDestructuring) {
+				const concatedIds = ids.concat([id]);
+				if (concatedIds[0] === "default") concatedIds.shift();
+				const module = moduleGraph.getModule(dep);
+				const used = moduleGraph
+					.getExportsInfo(module)
+					.getUsedName(concatedIds, runtime);
+				if (!used) return;
+				const newName = used[used.length - 1];
+				const name = concatedIds[concatedIds.length - 1];
+				if (newName === name) continue;
+
+				const comment = Template.toNormalComment(name) + " ";
+				const key = comment + JSON.stringify(newName);
+				source.replace(
+					range[0],
+					range[1] - 1,
+					shorthand ? `${key}: ${name}` : `${key}`
+				);
+			}
+		}
 	}
 
 	/**
diff --git a/lib/dependencies/ImportMetaPlugin.js b/lib/dependencies/ImportMetaPlugin.js
--- a/lib/dependencies/ImportMetaPlugin.js
+++ b/lib/dependencies/ImportMetaPlugin.js
@@ -131,7 +131,7 @@ class ImportMetaPlugin {
 							}
 
 							let str = "";
-							for (const prop of referencedPropertiesInDestructuring) {
+							for (const { id: prop } of referencedPropertiesInDestructuring) {
 								switch (prop) {
 									case "url":
 										str += `url: ${importMetaUrl()},`;
diff --git a/lib/dependencies/ImportParserPlugin.js b/lib/dependencies/ImportParserPlugin.js
--- a/lib/dependencies/ImportParserPlugin.js
+++ b/lib/dependencies/ImportParserPlugin.js
@@ -256,7 +256,9 @@ class ImportParserPlugin {
 						)
 					);
 				}
-				exports = exportsFromEnumerable(referencedPropertiesInDestructuring);
+				exports = exportsFromEnumerable(
+					[...referencedPropertiesInDestructuring].map(({ id }) => id)
+				);
 			}
 
 			if (param.isString()) {
diff --git a/lib/javascript/JavascriptParser.js b/lib/javascript/JavascriptParser.js
--- a/lib/javascript/JavascriptParser.js
+++ b/lib/javascript/JavascriptParser.js
@@ -147,6 +147,13 @@ class VariableInfo {
 
 /** @typedef {[number, number]} Range */
 
+/**
+ * @typedef {Object} DestructuringAssignmentProperty
+ * @property {string} id
+ * @property {Range | undefined=} range
+ * @property {boolean | string} shorthand
+ */
+
 /**
  * Helper function for joining two ranges into a single range. This is useful
  * when working with AST nodes, as it allows you to combine the ranges of child nodes
@@ -437,7 +444,7 @@ class JavascriptParser extends Parser {
 		this.statementPath = undefined;
 		/** @type {Statement | ModuleDeclaration | Expression | undefined} */
 		this.prevStatement = undefined;
-		/** @type {WeakMap<Expression, Set<string>> | undefined} */
+		/** @type {WeakMap<Expression, Set<DestructuringAssignmentProperty>> | undefined} */
 		this.destructuringAssignmentProperties = undefined;
 		this.currentTagData = undefined;
 		this.magicCommentContext = vm.createContext(undefined, {
@@ -1701,7 +1708,7 @@ class JavascriptParser extends Parser {
 
 	/**
 	 * @param {Expression} node node
-	 * @returns {Set<string>|undefined} destructured identifiers
+	 * @returns {Set<DestructuringAssignmentProperty> | undefined} destructured identifiers
 	 */
 	destructuringAssignmentPropertiesFor(node) {
 		if (!this.destructuringAssignmentProperties) return undefined;
@@ -2332,7 +2339,7 @@ class JavascriptParser extends Parser {
 		// check multiple assignments
 		if (this.destructuringAssignmentProperties.has(expression)) {
 			const set =
-				/** @type {Set<string>} */
+				/** @type {Set<DestructuringAssignmentProperty>} */
 				(this.destructuringAssignmentProperties.get(expression));
 			this.destructuringAssignmentProperties.delete(expression);
 			for (const id of set) keys.add(id);
@@ -2627,30 +2634,43 @@ class JavascriptParser extends Parser {
 
 	/**
 	 * @param {ObjectPattern} objectPattern object pattern
-	 * @returns {Set<string> | undefined} set of names or undefined if not all keys are identifiers
+	 * @returns {Set<DestructuringAssignmentProperty> | undefined} set of names or undefined if not all keys are identifiers
 	 */
 	_preWalkObjectPattern(objectPattern) {
-		const ids = new Set();
+		/** @type {Set<DestructuringAssignmentProperty>} */
+		const props = new Set();
 		const properties = objectPattern.properties;
 		for (let i = 0; i < properties.length; i++) {
 			const property = properties[i];
 			if (property.type !== "Property") return;
+			if (property.shorthand && property.value.type === "Identifier") {
+				this.scope.inShorthand = property.value.name;
+			}
 			const key = property.key;
 			if (key.type === "Identifier") {
-				ids.add(key.name);
+				props.add({
+					id: key.name,
+					range: key.range,
+					shorthand: this.scope.inShorthand
+				});
 			} else {
 				const id = this.evaluateExpression(/** @type {TODO} */ (key));
 				const str = id.asString();
 				if (str) {
-					ids.add(str);
+					props.add({
+						id: str,
+						range: key.range,
+						shorthand: this.scope.inShorthand
+					});
 				} else {
 					// could not evaluate key
 					return;
 				}
 			}
+			this.scope.inShorthand = false;
 		}
 
-		return ids;
+		return props;
 	}
 
 	/**
diff --git a/types.d.ts b/types.d.ts
--- a/types.d.ts
+++ b/types.d.ts
@@ -3301,6 +3301,17 @@ declare abstract class DependencyTemplates {
 	getHash(): string;
 	clone(): DependencyTemplates;
 }
+
+/**
+ * Helper function for joining two ranges into a single range. This is useful
+ * when working with AST nodes, as it allows you to combine the ranges of child nodes
+ * to create the range of the _parent node_.
+ */
+declare interface DestructuringAssignmentProperty {
+	id: string;
+	range?: [number, number];
+	shorthand: string | boolean;
+}
 declare class DeterministicChunkIdsPlugin {
 	constructor(options?: DeterministicChunkIdsPluginOptions);
 	options: DeterministicChunkIdsPluginOptions;
@@ -5946,12 +5957,15 @@ declare class JavascriptParser extends Parser {
 		| ExportNamedDeclaration
 		| ExportDefaultDeclaration
 		| ExportAllDeclaration;
-	destructuringAssignmentProperties?: WeakMap<Expression, Set<string>>;
+	destructuringAssignmentProperties?: WeakMap<
+		Expression,
+		Set<DestructuringAssignmentProperty>
+	>;
 	currentTagData: any;
 	magicCommentContext: Context;
 	destructuringAssignmentPropertiesFor(
 		node: Expression
-	): undefined | Set<string>;
+	): undefined | Set<DestructuringAssignmentProperty>;
 	getRenameIdentifier(
 		expr: Expression
 	): undefined | string | VariableInfoInterface;


Test patch:
diff --git a/test/configCases/mangle/exports-info-can-mangle/index.js b/test/configCases/mangle/exports-info-can-mangle/index.js
--- a/test/configCases/mangle/exports-info-can-mangle/index.js
+++ b/test/configCases/mangle/exports-info-can-mangle/index.js
@@ -8,7 +8,7 @@ it("__webpack_exports_info__.xxx.canMangle should be correct", () => {
 
 	const { bbb, bbbCanMangle } = b;
 	expect(bbb).toBe("bbb");
-	expect(bbbCanMangle).toBe(false);
+	expect(bbbCanMangle).toBe(true);
 	
 	expect(caCanMangle).toBe(true);
 	expect(cbCanMangle).toBe(true);
diff --git a/test/configCases/mangle/mangle-with-destructuring-assignment/data.json b/test/configCases/mangle/mangle-with-destructuring-assignment/data.json
new file mode 100644
--- /dev/null
+++ b/test/configCases/mangle/mangle-with-destructuring-assignment/data.json
@@ -0,0 +1,19 @@
+{
+  "obj": {
+    "arr": [
+      {
+        "prop1": 1,
+        "prop2": 2
+      },
+      {
+        "prop3": 3,
+        "prop4": 4
+      },
+      {
+        "prop5": 5,
+        "prop6": 6
+      }
+    ]
+  },
+  "foo": "foo"
+}
diff --git a/test/configCases/mangle/mangle-with-destructuring-assignment/index.js b/test/configCases/mangle/mangle-with-destructuring-assignment/index.js
--- a/test/configCases/mangle/mangle-with-destructuring-assignment/index.js
+++ b/test/configCases/mangle/mangle-with-destructuring-assignment/index.js
@@ -1,11 +1,14 @@
 import * as module from "./module";
 import { obj3, obj3CanMangle, obj4, obj4CanMangle } from "./reexport?side-effects" // enable side effects to ensure reexport is not skipped
+import data from "./data.json";
+import data2 from "./data.json?2";
+import path from "path";
 
-it("should not mangle export when destructuring module", () => {
+it("should mangle export when destructuring module", () => {
 	const { obj: { a, b }, objCanMangle } = module
 	expect(a).toBe("a");
 	expect(b).toBe("b");
-	expect(objCanMangle).toBe(false)
+	expect(objCanMangle).toBe(true)
 });
 
 it("should mangle export when destructuring module's property", () => {
@@ -21,17 +24,65 @@ it("should mangle export when using module dot property", () => {
 	expect(module.aaaCanMangle).toBe(true)
 });
 
-it("should not mangle export when destructuring module's property is a module", () => {
+it("should mangle export when destructuring module's property is a module", () => {
 	const { aaa, bbb } = obj3;
 	expect(aaa).toBe("a");
 	expect(bbb).toBe("b");
-	expect(obj3CanMangle).toBe(false)
+	expect(obj3CanMangle).toBe(true)
 });
 
-it("should not mangle export when destructuring module's nested property is a module", () => {
+it("should not mangle export when destructuring module's nested property is a module (used in unknown way)", () => {
 	const { nested: { obj5, obj5CanMangle } } = obj4;
 	expect(obj5.aaa).toBe("a");
 	expect(obj5.bbb).toBe("b");
 	expect(obj4CanMangle).toBe(true);
-	expect(obj5CanMangle).toBe(false)
+	expect(obj5CanMangle).toBe(false); // obj5 is used in unknown way
+});
+
+it("should mangle when destructuring json", async () => {
+	const { obj: {
+		"arr": [
+			{ prop1: p1 = 0 }
+		]
+	} } = data;
+	expect(p1).toBe(1);
+
+	const values = [];
+	({
+		foo: values[0],
+		obj: {
+			["a" + "r" + "r"]: {
+				length: values[1],
+			}
+		}
+	} = data);
+	expect(values[0]).toBe("foo");
+	expect(values[1]).toBe(3);
+
+	const generatedJson = __non_webpack_require__(path.resolve(__dirname, "data.json.js"));
+	expect(generatedJson).toEqual({
+		"W": {
+			"arr": [
+				{ "prop1": 1, "prop2": 2 },
+				{ "prop3": 3, "prop4": 4 },
+				{ "prop5": 5, "prop6": 6 }
+			]
+		},
+		"p": "foo"
+	});
+});
+
+it("should mangle when destructuring json 2", async () => {
+	const { prop1, prop2 } = data2.obj.arr[0];
+	expect(prop1).toBe(1);
+	expect(prop2).toBe(2);
+
+	const generatedJson = __non_webpack_require__(path.resolve(__dirname, "data.json_2.js"));
+	expect(generatedJson).toEqual({
+		"W": {
+			"Q": [
+				{ "X": 1, "Q": 2 },
+			],
+		}
+	});
 });
diff --git a/test/configCases/mangle/mangle-with-destructuring-assignment/webpack.config.js b/test/configCases/mangle/mangle-with-destructuring-assignment/webpack.config.js
--- a/test/configCases/mangle/mangle-with-destructuring-assignment/webpack.config.js
+++ b/test/configCases/mangle/mangle-with-destructuring-assignment/webpack.config.js
@@ -1,3 +1,5 @@
+// const { getRuntimeKey } = require("../../../../lib/util/runtime");
+
 /** @type {import("../../../../").Configuration} */
 module.exports = {
 	module: {
@@ -11,6 +13,37 @@ module.exports = {
 	optimization: {
 		mangleExports: true,
 		usedExports: true,
-		providedExports: true
-	}
+		providedExports: true,
+		concatenateModules: false
+	},
+	plugins: [
+		function getJsonCodeGeneratedSource(compiler) {
+			compiler.hooks.compilation.tap(
+				getJsonCodeGeneratedSource.name,
+				compilation => {
+					compilation.hooks.processAssets.tap(
+						getJsonCodeGeneratedSource.name,
+						() => {
+							for (const module of compilation.modules) {
+								if (module.type === "json") {
+									const { sources } = compilation.codeGenerationResults.get(
+										module,
+										"main"
+									);
+									const source = sources.get("javascript");
+									const file = compilation.getAssetPath("[name].js", {
+										filename:
+											module
+												.readableIdentifier(compilation.requestShortener)
+												.replace(/[?#]/g, "_") + ".js"
+									});
+									compilation.emitAsset(file, source);
+								}
+							}
+						}
+					);
+				}
+			);
+		}
+	]
 };