| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | "use strict"; | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | class OccurrenceOrderPlugin { | 
					
						
							|  |  |  | 	constructor(preferEntry) { | 
					
						
							|  |  |  | 		if(preferEntry !== undefined && typeof preferEntry !== "boolean") { | 
					
						
							|  |  |  | 			throw new Error("Argument should be a boolean.\nFor more info on this plugin, see https://webpack.github.io/docs/list-of-plugins.html"); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.preferEntry = preferEntry; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	apply(compiler) { | 
					
						
							|  |  |  | 		const preferEntry = this.preferEntry; | 
					
						
							|  |  |  | 		compiler.plugin("compilation", (compilation) => { | 
					
						
							|  |  |  | 			compilation.plugin("optimize-module-order", (modules) => { | 
					
						
							|  |  |  | 				function entryChunks(m) { | 
					
						
							|  |  |  | 					return m.chunks.map((c) => { | 
					
						
							|  |  |  | 						const sum = (c.isInitial() ? 1 : 0) + (c.entryModule === m ? 1 : 0); | 
					
						
							|  |  |  | 						return sum; | 
					
						
							|  |  |  | 					}).reduce((a, b) => { | 
					
						
							|  |  |  | 						return a + b; | 
					
						
							|  |  |  | 					}, 0); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 				function occursInEntry(m) { | 
					
						
							|  |  |  | 					if(typeof m.__OccurenceOrderPlugin_occursInEntry === "number") return m.__OccurenceOrderPlugin_occursInEntry; | 
					
						
							|  |  |  | 					const result = m.reasons.map((r) => { | 
					
						
							|  |  |  | 						if(!r.module) return 0; | 
					
						
							|  |  |  | 						return entryChunks(r.module); | 
					
						
							|  |  |  | 					}).reduce((a, b) => { | 
					
						
							|  |  |  | 						return a + b; | 
					
						
							|  |  |  | 					}, 0) + entryChunks(m); | 
					
						
							|  |  |  | 					return m.__OccurenceOrderPlugin_occursInEntry = result; | 
					
						
							| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-07-13 06:20:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 				function occurs(m) { | 
					
						
							|  |  |  | 					if(typeof m.__OccurenceOrderPlugin_occurs === "number") return m.__OccurenceOrderPlugin_occurs; | 
					
						
							|  |  |  | 					const result = m.reasons.map((r) => { | 
					
						
							|  |  |  | 						if(!r.module) return 0; | 
					
						
							|  |  |  | 						return r.module.chunks.length; | 
					
						
							|  |  |  | 					}).reduce((a, b) => { | 
					
						
							|  |  |  | 						return a + b; | 
					
						
							|  |  |  | 					}, 0) + m.chunks.length + m.chunks.filter((c) => { | 
					
						
							| 
									
										
										
										
											2017-01-18 05:26:38 +08:00
										 |  |  | 						return c.entryModule === m; | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 					}).length; | 
					
						
							|  |  |  | 					return m.__OccurenceOrderPlugin_occurs = result; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				modules.sort((a, b) => { | 
					
						
							|  |  |  | 					if(preferEntry) { | 
					
						
							|  |  |  | 						const aEntryOccurs = occursInEntry(a); | 
					
						
							|  |  |  | 						const bEntryOccurs = occursInEntry(b); | 
					
						
							|  |  |  | 						if(aEntryOccurs > bEntryOccurs) return -1; | 
					
						
							|  |  |  | 						if(aEntryOccurs < bEntryOccurs) return 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					const aOccurs = occurs(a); | 
					
						
							|  |  |  | 					const bOccurs = occurs(b); | 
					
						
							|  |  |  | 					if(aOccurs > bOccurs) return -1; | 
					
						
							|  |  |  | 					if(aOccurs < bOccurs) return 1; | 
					
						
							| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | 					if(a.identifier() > b.identifier()) return 1; | 
					
						
							|  |  |  | 					if(a.identifier() < b.identifier()) return -1; | 
					
						
							|  |  |  | 					return 0; | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 				// TODO refactor to Map
 | 
					
						
							|  |  |  | 				modules.forEach((m) => { | 
					
						
							|  |  |  | 					m.__OccurenceOrderPlugin_occursInEntry = undefined; | 
					
						
							|  |  |  | 					m.__OccurenceOrderPlugin_occurs = undefined; | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 			compilation.plugin("optimize-chunk-order", (chunks) => { | 
					
						
							|  |  |  | 				function occursInEntry(c) { | 
					
						
							|  |  |  | 					if(typeof c.__OccurenceOrderPlugin_occursInEntry === "number") return c.__OccurenceOrderPlugin_occursInEntry; | 
					
						
							|  |  |  | 					const result = c.parents.filter((p) => { | 
					
						
							|  |  |  | 						return p.isInitial(); | 
					
						
							|  |  |  | 					}).length; | 
					
						
							|  |  |  | 					return c.__OccurenceOrderPlugin_occursInEntry = result; | 
					
						
							| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				function occurs(c) { | 
					
						
							|  |  |  | 					return c.blocks.length; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				chunks.forEach((c) => { | 
					
						
							|  |  |  | 					c.modules.sort((a, b) => { | 
					
						
							|  |  |  | 						if(a.identifier() > b.identifier()) return 1; | 
					
						
							|  |  |  | 						if(a.identifier() < b.identifier()) return -1; | 
					
						
							|  |  |  | 						return 0; | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				chunks.sort((a, b) => { | 
					
						
							|  |  |  | 					const aEntryOccurs = occursInEntry(a); | 
					
						
							|  |  |  | 					const bEntryOccurs = occursInEntry(b); | 
					
						
							|  |  |  | 					if(aEntryOccurs > bEntryOccurs) return -1; | 
					
						
							|  |  |  | 					if(aEntryOccurs < bEntryOccurs) return 1; | 
					
						
							|  |  |  | 					const aOccurs = occurs(a); | 
					
						
							|  |  |  | 					const bOccurs = occurs(b); | 
					
						
							|  |  |  | 					if(aOccurs > bOccurs) return -1; | 
					
						
							|  |  |  | 					if(aOccurs < bOccurs) return 1; | 
					
						
							|  |  |  | 					if(a.modules.length > b.modules.length) return -1; | 
					
						
							|  |  |  | 					if(a.modules.length < b.modules.length) return 1; | 
					
						
							|  |  |  | 					for(let i = 0; i < a.modules.length; i++) { | 
					
						
							|  |  |  | 						if(a.modules[i].identifier() > b.modules[i].identifier()) return -1; | 
					
						
							|  |  |  | 						if(a.modules[i].identifier() < b.modules[i].identifier()) return 1; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return 0; | 
					
						
							|  |  |  | 				}); | 
					
						
							|  |  |  | 				// TODO refactor to Map
 | 
					
						
							|  |  |  | 				chunks.forEach((c) => { | 
					
						
							|  |  |  | 					c.__OccurenceOrderPlugin_occursInEntry = undefined; | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2016-12-05 06:47:19 +08:00
										 |  |  | 			}); | 
					
						
							| 
									
										
										
										
											2014-02-25 15:51:40 +08:00
										 |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2017-01-06 01:47:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = OccurrenceOrderPlugin; |