| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-06 02:41:45 +08:00
										 |  |  | const { validate } = require("schema-utils"); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | const schema = require("../../schemas/plugins/sharing/ProvideSharedPlugin.json"); | 
					
						
							| 
									
										
										
										
											2020-05-27 17:53:59 +08:00
										 |  |  | const WebpackError = require("../WebpackError"); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | const { parseOptions } = require("../container/options"); | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | const ProvideForSharedDependency = require("./ProvideForSharedDependency"); | 
					
						
							|  |  |  | const ProvideSharedDependency = require("./ProvideSharedDependency"); | 
					
						
							|  |  |  | const ProvideSharedModuleFactory = require("./ProvideSharedModuleFactory"); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */ | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | /** @typedef {import("../Compilation")} Compilation */ | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | /** @typedef {import("../Compiler")} Compiler */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} ProvideOptions | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  |  * @property {string} shareKey | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  |  * @property {string} shareScope | 
					
						
							| 
									
										
										
										
											2020-07-02 17:06:42 +08:00
										 |  |  |  * @property {string | undefined | false} version | 
					
						
							| 
									
										
										
										
											2020-05-26 23:11:21 +08:00
										 |  |  |  * @property {boolean} eager | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-02 17:06:42 +08:00
										 |  |  | /** @typedef {Map<string, { config: ProvideOptions, version: string | undefined | false }>} ResolvedProvideMap */ | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | class ProvideSharedPlugin { | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {ProvideSharedPluginOptions} options options | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	constructor(options) { | 
					
						
							| 
									
										
										
										
											2020-10-06 02:41:45 +08:00
										 |  |  | 		validate(schema, options, { name: "Provide Shared Plugin" }); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** @type {[string, ProvideOptions][]} */ | 
					
						
							|  |  |  | 		this._provides = parseOptions( | 
					
						
							|  |  |  | 			options.provides, | 
					
						
							|  |  |  | 			item => { | 
					
						
							|  |  |  | 				if (Array.isArray(item)) | 
					
						
							| 
									
										
										
										
											2020-05-26 23:26:28 +08:00
										 |  |  | 					throw new Error("Unexpected array of provides"); | 
					
						
							| 
									
										
										
										
											2020-05-26 23:11:21 +08:00
										 |  |  | 				/** @type {ProvideOptions} */ | 
					
						
							|  |  |  | 				const result = { | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 					shareKey: item, | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 					version: undefined, | 
					
						
							| 
									
										
										
										
											2020-05-26 23:11:21 +08:00
										 |  |  | 					shareScope: options.shareScope || "default", | 
					
						
							|  |  |  | 					eager: false | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-05-26 23:11:21 +08:00
										 |  |  | 				return result; | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			item => ({ | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 				shareKey: item.shareKey, | 
					
						
							| 
									
										
										
										
											2020-07-02 17:06:42 +08:00
										 |  |  | 				version: item.version, | 
					
						
							| 
									
										
										
										
											2020-05-26 23:11:21 +08:00
										 |  |  | 				shareScope: item.shareScope || options.shareScope || "default", | 
					
						
							|  |  |  | 				eager: !!item.eager | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 		this._provides.sort(([a], [b]) => { | 
					
						
							|  |  |  | 			if (a < b) return -1; | 
					
						
							|  |  |  | 			if (b < a) return 1; | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * Apply the plugin | 
					
						
							|  |  |  | 	 * @param {Compiler} compiler the compiler instance | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 		/** @type {WeakMap<Compilation, ResolvedProvideMap>} */ | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 		const compilationData = new WeakMap(); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 		compiler.hooks.compilation.tap( | 
					
						
							|  |  |  | 			"ProvideSharedPlugin", | 
					
						
							|  |  |  | 			(compilation, { normalModuleFactory }) => { | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 				/** @type {ResolvedProvideMap} */ | 
					
						
							|  |  |  | 				const resolvedProvideMap = new Map(); | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 				/** @type {Map<string, ProvideOptions>} */ | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 				const matchProvides = new Map(); | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 				/** @type {Map<string, ProvideOptions>} */ | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 				const prefixMatchProvides = new Map(); | 
					
						
							|  |  |  | 				for (const [request, config] of this._provides) { | 
					
						
							|  |  |  | 					if (/^(\/|[A-Za-z]:\\|\\\\|\.\.?(\/|$))/.test(request)) { | 
					
						
							|  |  |  | 						// relative request
 | 
					
						
							|  |  |  | 						resolvedProvideMap.set(request, { | 
					
						
							|  |  |  | 							config, | 
					
						
							|  |  |  | 							version: config.version | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					} else if (/^(\/|[A-Za-z]:\\|\\\\)/.test(request)) { | 
					
						
							|  |  |  | 						// absolute path
 | 
					
						
							|  |  |  | 						resolvedProvideMap.set(request, { | 
					
						
							|  |  |  | 							config, | 
					
						
							|  |  |  | 							version: config.version | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 					} else if (request.endsWith("/")) { | 
					
						
							|  |  |  | 						// module request prefix
 | 
					
						
							|  |  |  | 						prefixMatchProvides.set(request, config); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						// module request
 | 
					
						
							|  |  |  | 						matchProvides.set(request, config); | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				compilationData.set(compilation, resolvedProvideMap); | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:36 +08:00
										 |  |  | 				const provideSharedModule = ( | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | 					key, | 
					
						
							|  |  |  | 					config, | 
					
						
							|  |  |  | 					resource, | 
					
						
							|  |  |  | 					resourceResolveData | 
					
						
							|  |  |  | 				) => { | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 					let version = config.version; | 
					
						
							|  |  |  | 					if (version === undefined) { | 
					
						
							|  |  |  | 						let details = ""; | 
					
						
							|  |  |  | 						if (!resourceResolveData) { | 
					
						
							|  |  |  | 							details = `No resolve data provided from resolver.`; | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							const descriptionFileData = | 
					
						
							|  |  |  | 								resourceResolveData.descriptionFileData; | 
					
						
							|  |  |  | 							if (!descriptionFileData) { | 
					
						
							|  |  |  | 								details = | 
					
						
							|  |  |  | 									"No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config."; | 
					
						
							|  |  |  | 							} else if (!descriptionFileData.version) { | 
					
						
							|  |  |  | 								details = | 
					
						
							|  |  |  | 									"No version in description file (usually package.json). Add version to description file, or manually specify version in shared config."; | 
					
						
							|  |  |  | 							} else { | 
					
						
							| 
									
										
										
										
											2020-07-02 17:06:42 +08:00
										 |  |  | 								version = descriptionFileData.version; | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						if (!version) { | 
					
						
							|  |  |  | 							const error = new WebpackError( | 
					
						
							|  |  |  | 								`No version specified and unable to automatically determine one. ${details}` | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 							error.file = `shared module ${key} -> ${resource}`; | 
					
						
							|  |  |  | 							compilation.warnings.push(error); | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 					resolvedProvideMap.set(resource, { | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 						config, | 
					
						
							|  |  |  | 						version | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 				normalModuleFactory.hooks.module.tap( | 
					
						
							|  |  |  | 					"ProvideSharedPlugin", | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:10 +08:00
										 |  |  | 					(module, { resource, resourceResolveData }, resolveData) => { | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 						if (resolvedProvideMap.has(resource)) { | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 							return module; | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:10 +08:00
										 |  |  | 						const { request } = resolveData; | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 							const config = matchProvides.get(request); | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 							if (config !== undefined) { | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:36 +08:00
										 |  |  | 								provideSharedModule( | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | 									request, | 
					
						
							|  |  |  | 									config, | 
					
						
							|  |  |  | 									resource, | 
					
						
							|  |  |  | 									resourceResolveData | 
					
						
							|  |  |  | 								); | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:10 +08:00
										 |  |  | 								resolveData.cacheable = false; | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 							} | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 						for (const [prefix, config] of prefixMatchProvides) { | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 							if (request.startsWith(prefix)) { | 
					
						
							|  |  |  | 								const remainder = request.slice(prefix.length); | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:36 +08:00
										 |  |  | 								provideSharedModule( | 
					
						
							| 
									
										
										
										
											2020-06-13 21:17:28 +08:00
										 |  |  | 									resource, | 
					
						
							|  |  |  | 									{ | 
					
						
							|  |  |  | 										...config, | 
					
						
							|  |  |  | 										shareKey: config.shareKey + remainder | 
					
						
							|  |  |  | 									}, | 
					
						
							|  |  |  | 									resource, | 
					
						
							|  |  |  | 									resourceResolveData | 
					
						
							| 
									
										
										
										
											2020-05-27 17:53:59 +08:00
										 |  |  | 								); | 
					
						
							| 
									
										
										
										
											2020-06-24 20:09:10 +08:00
										 |  |  | 								resolveData.cacheable = false; | 
					
						
							| 
									
										
										
										
											2020-05-27 17:53:59 +08:00
										 |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 						return module; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 		compiler.hooks.finishMake.tapPromise("ProvideSharedPlugin", compilation => { | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 			const resolvedProvideMap = compilationData.get(compilation); | 
					
						
							|  |  |  | 			if (!resolvedProvideMap) return Promise.resolve(); | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 			return Promise.all( | 
					
						
							|  |  |  | 				Array.from( | 
					
						
							| 
									
										
										
										
											2020-06-15 22:20:34 +08:00
										 |  |  | 					resolvedProvideMap, | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 					([resource, { config, version }]) => | 
					
						
							|  |  |  | 						new Promise((resolve, reject) => { | 
					
						
							|  |  |  | 							compilation.addInclude( | 
					
						
							|  |  |  | 								compiler.context, | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | 								new ProvideSharedDependency( | 
					
						
							| 
									
										
										
										
											2020-06-10 22:30:08 +08:00
										 |  |  | 									config.shareScope, | 
					
						
							|  |  |  | 									config.shareKey, | 
					
						
							|  |  |  | 									version || false, | 
					
						
							|  |  |  | 									resource, | 
					
						
							|  |  |  | 									config.eager | 
					
						
							|  |  |  | 								), | 
					
						
							|  |  |  | 								{ | 
					
						
							|  |  |  | 									name: undefined | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 								err => { | 
					
						
							|  |  |  | 									if (err) return reject(err); | 
					
						
							|  |  |  | 									resolve(); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							); | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 			).then(() => {}); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		compiler.hooks.compilation.tap( | 
					
						
							|  |  |  | 			"ProvideSharedPlugin", | 
					
						
							|  |  |  | 			(compilation, { normalModuleFactory }) => { | 
					
						
							|  |  |  | 				compilation.dependencyFactories.set( | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | 					ProvideForSharedDependency, | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 					normalModuleFactory | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				compilation.dependencyFactories.set( | 
					
						
							| 
									
										
										
										
											2020-06-18 21:11:29 +08:00
										 |  |  | 					ProvideSharedDependency, | 
					
						
							|  |  |  | 					new ProvideSharedModuleFactory() | 
					
						
							| 
									
										
										
										
											2020-05-23 22:08:51 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = ProvideSharedPlugin; |