| 
									
										
										
										
											2013-01-31 09:33:11 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2014-06-18 04:46:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | const ContextElementDependency = require("./dependencies/ContextElementDependency"); | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | const { join } = require("./util/fs"); | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-17 06:33:17 +08:00
										 |  |  | /** @typedef {import("./Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | /** @typedef {import("./ContextModule").ContextModuleOptions} ContextModuleOptions */ | 
					
						
							| 
									
										
										
										
											2025-08-28 18:34:30 +08:00
										 |  |  | /** @typedef {import("./ContextModuleFactory").BeforeContextResolveData} BeforeContextResolveData */ | 
					
						
							|  |  |  | /** @typedef {import("./ContextModuleFactory").AfterContextResolveData} AfterContextResolveData */ | 
					
						
							| 
									
										
										
										
											2024-03-12 00:33:52 +08:00
										 |  |  | /** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */ | 
					
						
							| 
									
										
										
										
											2023-06-17 06:33:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | /** @typedef {Record<string, string>} NewContentCreateContextMap */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 20:03:37 +08:00
										 |  |  | const PLUGIN_NAME = "ContextReplacementPlugin"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | class ContextReplacementPlugin { | 
					
						
							| 
									
										
										
										
											2023-06-17 06:33:17 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {RegExp} resourceRegExp A regular expression that determines which files will be selected | 
					
						
							| 
									
										
										
										
											2025-08-28 18:34:30 +08:00
										 |  |  | 	 * @param {(string | ((context: BeforeContextResolveData | AfterContextResolveData) => void) | RegExp | boolean)=} newContentResource A new resource to replace the match | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 	 * @param {(boolean | NewContentCreateContextMap | RegExp)=} newContentRecursive If true, all subdirectories are searched for matches | 
					
						
							| 
									
										
										
										
											2024-08-15 02:38:08 +08:00
										 |  |  | 	 * @param {RegExp=} newContentRegExp A regular expression that determines which files will be selected | 
					
						
							| 
									
										
										
										
											2023-06-17 06:33:17 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	constructor( | 
					
						
							|  |  |  | 		resourceRegExp, | 
					
						
							|  |  |  | 		newContentResource, | 
					
						
							|  |  |  | 		newContentRecursive, | 
					
						
							|  |  |  | 		newContentRegExp | 
					
						
							|  |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 		this.resourceRegExp = resourceRegExp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		// new webpack.ContextReplacementPlugin(/selector/, (context) => { /* Logic */ });
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (typeof newContentResource === "function") { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			this.newContentCallback = newContentResource; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// new ContextReplacementPlugin(/selector/, './folder', { './request': './request' });
 | 
					
						
							|  |  |  | 		else if ( | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			typeof newContentResource === "string" && | 
					
						
							|  |  |  | 			typeof newContentRecursive === "object" | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			this.newContentResource = newContentResource; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 			/** | 
					
						
							|  |  |  | 			 * @param {InputFileSystem} fs input file system | 
					
						
							|  |  |  | 			 * @param {(err: null | Error, newContentRecursive: NewContentCreateContextMap) => void} callback callback | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			this.newContentCreateContextMap = (fs, callback) => { | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 				callback( | 
					
						
							|  |  |  | 					null, | 
					
						
							|  |  |  | 					/** @type {NewContentCreateContextMap} */ (newContentRecursive) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// new ContextReplacementPlugin(/selector/, './folder', (context) => { /* Logic */ });
 | 
					
						
							|  |  |  | 		else if ( | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			typeof newContentResource === "string" && | 
					
						
							|  |  |  | 			typeof newContentRecursive === "function" | 
					
						
							|  |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			this.newContentResource = newContentResource; | 
					
						
							|  |  |  | 			this.newContentCreateContextMap = newContentRecursive; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 			// new webpack.ContextReplacementPlugin(/selector/, false, /reg-exp/);
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (typeof newContentResource !== "string") { | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 				newContentRegExp = /** @type {RegExp} */ (newContentRecursive); | 
					
						
							|  |  |  | 				newContentRecursive = /** @type {boolean} */ (newContentResource); | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 				newContentResource = undefined; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 			// new webpack.ContextReplacementPlugin(/selector/, /de|fr|hu/);
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (typeof newContentRecursive !== "boolean") { | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 				newContentRegExp = /** @type {RegExp} */ (newContentRecursive); | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 				newContentRecursive = undefined; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 			// new webpack.ContextReplacementPlugin(/selector/, './folder', false, /selector/);
 | 
					
						
							|  |  |  | 			this.newContentResource = | 
					
						
							|  |  |  | 				/** @type {string | undefined} */ | 
					
						
							|  |  |  | 				(newContentResource); | 
					
						
							|  |  |  | 			this.newContentRecursive = | 
					
						
							|  |  |  | 				/** @type {boolean | undefined} */ | 
					
						
							|  |  |  | 				(newContentRecursive); | 
					
						
							|  |  |  | 			this.newContentRegExp = | 
					
						
							|  |  |  | 				/** @type {RegExp | undefined} */ | 
					
						
							|  |  |  | 				(newContentRegExp); | 
					
						
							| 
									
										
										
										
											2014-10-23 16:58:26 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-18 04:38:17 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-17 06:33:17 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * Apply the plugin | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 	apply(compiler) { | 
					
						
							|  |  |  | 		const resourceRegExp = this.resourceRegExp; | 
					
						
							|  |  |  | 		const newContentCallback = this.newContentCallback; | 
					
						
							|  |  |  | 		const newContentResource = this.newContentResource; | 
					
						
							|  |  |  | 		const newContentRecursive = this.newContentRecursive; | 
					
						
							|  |  |  | 		const newContentRegExp = this.newContentRegExp; | 
					
						
							|  |  |  | 		const newContentCreateContextMap = this.newContentCreateContextMap; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 		compiler.hooks.contextModuleFactory.tap(PLUGIN_NAME, (cmf) => { | 
					
						
							|  |  |  | 			cmf.hooks.beforeResolve.tap(PLUGIN_NAME, (result) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (!result) return; | 
					
						
							|  |  |  | 				if (resourceRegExp.test(result.request)) { | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentResource !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						result.request = newContentResource; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentRecursive !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						result.recursive = newContentRecursive; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentRegExp !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						result.regExp = newContentRegExp; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (typeof newContentCallback === "function") { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						newContentCallback(result); | 
					
						
							|  |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						for (const d of result.dependencies) { | 
					
						
							|  |  |  | 							if (d.critical) d.critical = false; | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-10-23 16:58:26 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-12-14 21:38:53 +08:00
										 |  |  | 				return result; | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 			cmf.hooks.afterResolve.tap(PLUGIN_NAME, (result) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 				if (!result) return; | 
					
						
							| 
									
										
										
										
											2025-09-09 23:41:52 +08:00
										 |  |  | 				const isMatchResourceRegExp = () => { | 
					
						
							|  |  |  | 					if (Array.isArray(result.resource)) { | 
					
						
							|  |  |  | 						return result.resource.some((item) => resourceRegExp.test(item)); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					return resourceRegExp.test(result.resource); | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 				if (isMatchResourceRegExp()) { | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentResource !== undefined) { | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | 						if ( | 
					
						
							|  |  |  | 							newContentResource.startsWith("/") || | 
					
						
							|  |  |  | 							(newContentResource.length > 1 && newContentResource[1] === ":") | 
					
						
							|  |  |  | 						) { | 
					
						
							|  |  |  | 							result.resource = newContentResource; | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2025-09-09 23:41:52 +08:00
										 |  |  | 							const rootPath = | 
					
						
							|  |  |  | 								typeof result.resource === "string" | 
					
						
							|  |  |  | 									? result.resource | 
					
						
							|  |  |  | 									: /** @type {string} */ | 
					
						
							|  |  |  | 										(result.resource.find((item) => resourceRegExp.test(item))); | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | 							result.resource = join( | 
					
						
							| 
									
										
										
										
											2025-05-23 21:39:55 +08:00
										 |  |  | 								/** @type {InputFileSystem} */ | 
					
						
							|  |  |  | 								(compiler.inputFileSystem), | 
					
						
							| 
									
										
										
										
											2025-09-09 23:41:52 +08:00
										 |  |  | 								rootPath, | 
					
						
							| 
									
										
										
										
											2019-06-11 19:09:42 +08:00
										 |  |  | 								newContentResource | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentRecursive !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						result.recursive = newContentRecursive; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-08-17 05:49:30 +08:00
										 |  |  | 					if (newContentRegExp !== undefined) { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						result.regExp = newContentRegExp; | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (typeof newContentCreateContextMap === "function") { | 
					
						
							| 
									
										
										
										
											2021-05-11 15:31:46 +08:00
										 |  |  | 						result.resolveDependencies = | 
					
						
							|  |  |  | 							createResolveDependenciesFromContextMap( | 
					
						
							|  |  |  | 								newContentCreateContextMap | 
					
						
							|  |  |  | 							); | 
					
						
							| 
									
										
										
										
											2018-05-29 20:50:40 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 					if (typeof newContentCallback === "function") { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						const origResource = result.resource; | 
					
						
							|  |  |  | 						newContentCallback(result); | 
					
						
							| 
									
										
										
										
											2025-09-09 23:41:52 +08:00
										 |  |  | 						if (result.resource !== origResource) { | 
					
						
							|  |  |  | 							const newResource = Array.isArray(result.resource) | 
					
						
							|  |  |  | 								? result.resource | 
					
						
							|  |  |  | 								: [result.resource]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							for (let i = 0; i < newResource.length; i++) { | 
					
						
							|  |  |  | 								if ( | 
					
						
							|  |  |  | 									!newResource[i].startsWith("/") && | 
					
						
							|  |  |  | 									(newResource[i].length <= 1 || newResource[i][1] !== ":") | 
					
						
							|  |  |  | 								) { | 
					
						
							|  |  |  | 									// When the function changed it to an relative path
 | 
					
						
							|  |  |  | 									newResource[i] = join( | 
					
						
							|  |  |  | 										/** @type {InputFileSystem} */ | 
					
						
							|  |  |  | 										(compiler.inputFileSystem), | 
					
						
							|  |  |  | 										origResource[i], | 
					
						
							|  |  |  | 										newResource[i] | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							result.resource = newResource; | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 						for (const d of result.dependencies) { | 
					
						
							|  |  |  | 							if (d.critical) d.critical = false; | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2014-10-23 16:58:26 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-12-14 21:38:53 +08:00
										 |  |  | 				return result; | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2013-01-31 09:33:11 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-07 02:56:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {(fs: InputFileSystem, callback: (err: null | Error, map: NewContentCreateContextMap) => void) => void} createContextMap create context map function | 
					
						
							|  |  |  |  * @returns {(fs: InputFileSystem, options: ContextModuleOptions, callback: (err: null | Error, dependencies?: ContextElementDependency[]) => void) => void} resolve resolve dependencies from context map function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const createResolveDependenciesFromContextMap = | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	(createContextMap) => (fs, options, callback) => { | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 		createContextMap(fs, (err, map) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			if (err) return callback(err); | 
					
						
							| 
									
										
										
										
											2024-07-31 11:31:11 +08:00
										 |  |  | 			const dependencies = Object.keys(map).map( | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 				(key) => | 
					
						
							| 
									
										
										
										
											2024-07-31 11:31:11 +08:00
										 |  |  | 					new ContextElementDependency( | 
					
						
							|  |  |  | 						map[key] + options.resourceQuery + options.resourceFragment, | 
					
						
							|  |  |  | 						key, | 
					
						
							| 
									
										
										
										
											2025-03-11 08:28:01 +08:00
										 |  |  | 						options.typePrefix, | 
					
						
							| 
									
										
										
										
											2025-04-26 01:43:01 +08:00
										 |  |  | 						/** @type {string} */ | 
					
						
							|  |  |  | 						(options.category), | 
					
						
							| 
									
										
										
										
											2024-07-31 11:31:11 +08:00
										 |  |  | 						options.referencedExports | 
					
						
							|  |  |  | 					) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2016-01-07 02:56:17 +08:00
										 |  |  | 			callback(null, dependencies); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-01-11 17:51:58 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2017-03-11 01:27:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | module.exports = ContextReplacementPlugin; |