| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | const validateOptions = require("schema-utils"); | 
					
						
							|  |  |  | const schema = require("../../schemas/plugins/container/OverridablesPlugin.json"); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | const ModuleNotFoundError = require("../ModuleNotFoundError"); | 
					
						
							|  |  |  | const RuntimeGlobals = require("../RuntimeGlobals"); | 
					
						
							| 
									
										
										
										
											2020-02-29 00:29:24 +08:00
										 |  |  | const { | 
					
						
							|  |  |  | 	toConstantDependency, | 
					
						
							|  |  |  | 	evaluateToString | 
					
						
							|  |  |  | } = require("../javascript/JavascriptParserHelpers"); | 
					
						
							|  |  |  | const LazySet = require("../util/LazySet"); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | const OverridableModule = require("./OverridableModule"); | 
					
						
							|  |  |  | const OverridableOriginalDependency = require("./OverridableOriginalDependency"); | 
					
						
							|  |  |  | const OverridablesRuntimeModule = require("./OverridablesRuntimeModule"); | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | const { parseOptions } = require("./options"); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-29 00:29:24 +08:00
										 |  |  | /** @typedef {import("enhanced-resolve").ResolveContext} ResolveContext */ | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | /** @typedef {import("../../declarations/plugins/container/OverridablesPlugin").OverridablesConfig} OverridablesConfig */ | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | /** @typedef {import("../../declarations/plugins/container/OverridablesPlugin").OverridablesPluginOptions} OverridablesPluginOptions */ | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | /** @typedef {import("./OverridableModule").OverridableOptions} OverridableOptions */ | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | const PLUGIN_NAME = "OverridablesPlugin"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | class OverridablesPlugin { | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {OverridablesPluginOptions} options options | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 	constructor(options) { | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 		if (typeof options !== "string") { | 
					
						
							|  |  |  | 			validateOptions(schema, options, { name: "Overridables Plugin" }); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 		this._overridables = parseOptions( | 
					
						
							|  |  |  | 			options.overridables, | 
					
						
							|  |  |  | 			item => ({ | 
					
						
							|  |  |  | 				import: Array.isArray(item) ? item : [item] | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 			item => ({ | 
					
						
							|  |  |  | 				import: Array.isArray(item.import) ? item.import : [item.import] | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 	 * Apply the plugin | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							|  |  |  | 		compiler.hooks.thisCompilation.tap( | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 			PLUGIN_NAME, | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 			(compilation, { normalModuleFactory }) => { | 
					
						
							|  |  |  | 				compilation.dependencyFactories.set( | 
					
						
							|  |  |  | 					OverridableOriginalDependency, | 
					
						
							| 
									
										
										
										
											2020-04-17 08:41:51 +08:00
										 |  |  | 					normalModuleFactory | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 				/** @type {Map<string, OverridableOptions>} */ | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 				const resolvedOverridables = new Map(); | 
					
						
							| 
									
										
										
										
											2020-02-29 00:29:24 +08:00
										 |  |  | 				const resolveContext = { | 
					
						
							|  |  |  | 					/** @type {LazySet<string>} */ | 
					
						
							|  |  |  | 					fileDependencies: new LazySet(), | 
					
						
							|  |  |  | 					/** @type {LazySet<string>} */ | 
					
						
							|  |  |  | 					contextDependencies: new LazySet(), | 
					
						
							|  |  |  | 					/** @type {LazySet<string>} */ | 
					
						
							|  |  |  | 					missingDependencies: new LazySet() | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-06-01 20:13:17 +08:00
										 |  |  | 				const resolver = compilation.resolverFactory.get( | 
					
						
							|  |  |  | 					"normal", | 
					
						
							|  |  |  | 					undefined, | 
					
						
							|  |  |  | 					"esm" | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * @param {string} request imported request | 
					
						
							|  |  |  | 				 * @param {string} name overridable name | 
					
						
							|  |  |  | 				 * @param {OverridablesConfig} config config | 
					
						
							|  |  |  | 				 * @returns {Promise<void>} promise | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				const resolveOverridable = (request, name, config) => { | 
					
						
							|  |  |  | 					return new Promise(resolve => { | 
					
						
							|  |  |  | 						resolver.resolve( | 
					
						
							|  |  |  | 							{}, | 
					
						
							|  |  |  | 							compiler.context, | 
					
						
							|  |  |  | 							request, | 
					
						
							|  |  |  | 							resolveContext, | 
					
						
							|  |  |  | 							(err, result) => { | 
					
						
							|  |  |  | 								if (err) { | 
					
						
							|  |  |  | 									compilation.errors.push( | 
					
						
							|  |  |  | 										new ModuleNotFoundError(null, err, { | 
					
						
							|  |  |  | 											name: `overridable ${name}` | 
					
						
							|  |  |  | 										}) | 
					
						
							|  |  |  | 									); | 
					
						
							|  |  |  | 									return resolve(); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 								} | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 								resolvedOverridables.set(result, { | 
					
						
							|  |  |  | 									name | 
					
						
							|  |  |  | 								}); | 
					
						
							|  |  |  | 								resolve(); | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 				const promise = Promise.all( | 
					
						
							|  |  |  | 					this._overridables.map(([name, config]) => { | 
					
						
							|  |  |  | 						return Promise.all( | 
					
						
							|  |  |  | 							config.import.map(request => | 
					
						
							|  |  |  | 								resolveOverridable(request, name, config) | 
					
						
							|  |  |  | 							) | 
					
						
							|  |  |  | 						); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2020-02-29 00:29:24 +08:00
										 |  |  | 				).then(() => { | 
					
						
							|  |  |  | 					compilation.contextDependencies.addAll( | 
					
						
							|  |  |  | 						resolveContext.contextDependencies | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 					compilation.fileDependencies.addAll(resolveContext.fileDependencies); | 
					
						
							|  |  |  | 					compilation.missingDependencies.addAll( | 
					
						
							|  |  |  | 						resolveContext.missingDependencies | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 				normalModuleFactory.hooks.afterResolve.tapAsync( | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 					PLUGIN_NAME, | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 					(resolveData, callback) => { | 
					
						
							|  |  |  | 						// wait for resolving to be complete
 | 
					
						
							|  |  |  | 						promise.then(() => callback()); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.module.tap( | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 					PLUGIN_NAME, | 
					
						
							| 
									
										
										
										
											2020-04-17 08:41:51 +08:00
										 |  |  | 					(module, createData, resolveData) => { | 
					
						
							|  |  |  | 						if ( | 
					
						
							|  |  |  | 							resolveData.dependencies[0] instanceof | 
					
						
							|  |  |  | 							OverridableOriginalDependency | 
					
						
							|  |  |  | 						) { | 
					
						
							|  |  |  | 							return; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 						const options = resolvedOverridables.get(createData.resource); | 
					
						
							|  |  |  | 						if (options !== undefined) { | 
					
						
							| 
									
										
										
										
											2020-04-17 08:41:51 +08:00
										 |  |  | 							return new OverridableModule( | 
					
						
							|  |  |  | 								resolveData.context, | 
					
						
							|  |  |  | 								resolveData.request, | 
					
						
							| 
									
										
										
										
											2020-05-14 21:50:35 +08:00
										 |  |  | 								options | 
					
						
							| 
									
										
										
										
											2020-04-17 08:41:51 +08:00
										 |  |  | 							); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2020-05-02 03:40:00 +08:00
										 |  |  | 				compilation.hooks.additionalTreeRuntimeRequirements.tap( | 
					
						
							|  |  |  | 					PLUGIN_NAME, | 
					
						
							|  |  |  | 					(chunk, set) => { | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 						set.add(RuntimeGlobals.module); | 
					
						
							| 
									
										
										
										
											2020-02-25 04:12:45 +08:00
										 |  |  | 						set.add(RuntimeGlobals.moduleFactories); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 						set.add(RuntimeGlobals.hasOwnProperty); | 
					
						
							|  |  |  | 						compilation.addRuntimeModule( | 
					
						
							|  |  |  | 							chunk, | 
					
						
							| 
									
										
										
										
											2020-05-02 03:40:00 +08:00
										 |  |  | 							new OverridablesRuntimeModule(set) | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 						); | 
					
						
							| 
									
										
										
										
											2020-05-02 03:40:00 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2020-02-29 00:22:37 +08:00
										 |  |  | 				const handler = parser => { | 
					
						
							|  |  |  | 					parser.hooks.expression | 
					
						
							|  |  |  | 						.for("__webpack_override__") | 
					
						
							|  |  |  | 						.tap( | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 							PLUGIN_NAME, | 
					
						
							| 
									
										
										
										
											2020-02-29 00:22:37 +08:00
										 |  |  | 							toConstantDependency( | 
					
						
							|  |  |  | 								parser, | 
					
						
							|  |  |  | 								`Object.assign.bind(Object, ${RuntimeGlobals.overrides})`, | 
					
						
							|  |  |  | 								[RuntimeGlobals.overrides] | 
					
						
							|  |  |  | 							) | 
					
						
							|  |  |  | 						); | 
					
						
							|  |  |  | 					parser.hooks.evaluateTypeof | 
					
						
							|  |  |  | 						.for("__webpack_override__") | 
					
						
							| 
									
										
										
										
											2020-04-30 19:39:58 +08:00
										 |  |  | 						.tap(PLUGIN_NAME, evaluateToString("function")); | 
					
						
							| 
									
										
										
										
											2020-02-29 00:22:37 +08:00
										 |  |  | 				}; | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/auto") | 
					
						
							|  |  |  | 					.tap("APIPlugin", handler); | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/dynamic") | 
					
						
							|  |  |  | 					.tap("APIPlugin", handler); | 
					
						
							|  |  |  | 				normalModuleFactory.hooks.parser | 
					
						
							|  |  |  | 					.for("javascript/esm") | 
					
						
							|  |  |  | 					.tap("APIPlugin", handler); | 
					
						
							| 
									
										
										
										
											2020-02-20 17:52:47 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = OverridablesPlugin; |