5
5
"use strict" ;
6
6
7
7
const identifierUtils = require ( "../util/identifier" ) ;
8
+ const intersect = require ( "../util/SetHelpers" ) . intersect ;
8
9
const validateOptions = require ( "schema-utils" ) ;
9
10
const schema = require ( "../../schemas/plugins/optimize/AggressiveSplittingPlugin.json" ) ;
10
11
@@ -20,16 +21,6 @@ const isNotAEntryModule = entryModule => {
20
21
} ;
21
22
} ;
22
23
23
- const copyWithReason = obj => {
24
- const newObj = { } ;
25
- Object . keys ( obj ) . forEach ( key => {
26
- newObj [ key ] = obj [ key ] ;
27
- } ) ;
28
- if ( ! newObj . reasons || ! newObj . reasons . includes ( "aggressive-splitted" ) )
29
- newObj . reasons = ( newObj . reasons || [ ] ) . concat ( "aggressive-splitted" ) ;
30
- return newObj ;
31
- } ;
32
-
33
24
class AggressiveSplittingPlugin {
34
25
constructor ( options ) {
35
26
validateOptions ( schema , options || { } , "Aggressive Splitting Plugin" ) ;
@@ -39,10 +30,17 @@ class AggressiveSplittingPlugin {
39
30
if ( typeof this . options . maxSize !== "number" ) this . options . maxSize = 50 * 1024 ;
40
31
if ( typeof this . options . chunkOverhead !== "number" ) this . options . chunkOverhead = 0 ;
41
32
if ( typeof this . options . entryChunkMultiplicator !== "number" ) this . options . entryChunkMultiplicator = 1 ;
33
+
34
+ this . usedSplitsMap = new WeakMap ( ) ;
35
+ this . fromAggressiveSplittingSet = new WeakSet ( ) ;
36
+ this . aggressiveSplittingInvalidSet = new WeakSet ( ) ;
37
+ this . fromAggressiveSplittingIndexMap = new WeakMap ( ) ;
42
38
}
43
39
apply ( compiler ) {
44
40
compiler . hooks . thisCompilation . tap ( "AggressiveSplittingPlugin" , ( compilation ) => {
45
41
compilation . hooks . optimizeChunksAdvanced . tap ( "AggressiveSplittingPlugin" , ( chunks ) => {
42
+ for ( const chunk of chunks )
43
+ console . log ( `${ chunk . debugId } =\n${ Array . from ( chunk . modulesIterable , m => ` * ${ m . resource } ` ) . join ( "\n" ) } ` ) ;
46
44
// Precompute stuff
47
45
const nameToModuleMap = new Map ( ) ;
48
46
compilation . modules . forEach ( m => {
@@ -51,18 +49,44 @@ class AggressiveSplittingPlugin {
51
49
} ) ;
52
50
53
51
const savedSplits = compilation . records && compilation . records . aggressiveSplits || [ ] ;
54
- const usedSplits = compilation . _aggressiveSplittingSplits ?
55
- savedSplits . concat ( compilation . _aggressiveSplittingSplits ) : savedSplits ;
52
+ let storedSplits = this . usedSplitsMap . get ( compilation ) ;
53
+ const usedSplits = storedSplits ?
54
+ savedSplits . concat ( storedSplits ) : savedSplits ;
56
55
57
56
const minSize = this . options . minSize ;
58
57
const maxSize = this . options . maxSize ;
59
58
// 1. try to restore to recorded splitting
60
59
for ( let j = 0 ; j < usedSplits . length ; j ++ ) {
61
60
const splitData = usedSplits [ j ] ;
62
61
const selectedModules = splitData . modules . map ( name => nameToModuleMap . get ( name ) ) ;
62
+ console . log ( "Try to split" , splitData ) ;
63
63
64
64
// Does the modules exist at all?
65
- if ( selectedModules . every ( Boolean ) ) {
65
+ if ( ! selectedModules . every ( Boolean ) ) continue ;
66
+ console . log ( "modules ok" ) ;
67
+
68
+ const selectedChunks = intersect ( selectedModules . map ( m => new Set ( m . chunksIterable ) ) ) ;
69
+
70
+ // No relevant chunks found
71
+ if ( selectedChunks . size === 0 ) continue ;
72
+
73
+ // The found chunk is already the split or similar
74
+ if ( selectedChunks . size === 1 && Array . from ( selectedChunks ) [ 0 ] . getNumberOfModules ( ) === selectedModules . length ) continue ;
75
+
76
+ // split the chunk into two parts
77
+ const newChunk = compilation . addChunk ( ) ;
78
+ for ( const chunk of selectedChunks ) {
79
+ selectedModules . forEach ( moveModuleBetween ( chunk , newChunk ) ) ;
80
+ chunk . split ( newChunk ) ;
81
+ chunk . name = null ;
82
+ }
83
+ this . fromAggressiveSplittingSet . add ( newChunk ) ;
84
+ if ( j < savedSplits . length )
85
+ this . fromAggressiveSplittingIndexMap . set ( newChunk , j ) ;
86
+ if ( splitData . id !== null && splitData . id !== undefined ) {
87
+ console . log ( `AggressiveSplittingPlugin assign id ${ splitData . id } ` ) ;
88
+ newChunk . id = splitData . id ;
89
+ }
66
90
67
91
// Find all chunks containing all modules in the split
68
92
for ( let i = 0 ; i < chunks . length ; i ++ ) {
@@ -75,26 +99,48 @@ class AggressiveSplittingPlugin {
75
99
// Check if all modules are in the chunk
76
100
if ( selectedModules . every ( m => chunk . containsModule ( m ) ) ) {
77
101
78
- // Is chunk identical to the split or do we need to split it?
79
- if ( chunk . getNumberOfModules ( ) > splitData . modules . length ) {
80
- // split the chunk into two parts
81
- const newChunk = compilation . addChunk ( ) ;
82
- selectedModules . forEach ( moveModuleBetween ( chunk , newChunk ) ) ;
83
- chunk . split ( newChunk ) ;
84
- chunk . name = null ;
85
- newChunk . _fromAggressiveSplitting = true ;
86
- if ( j < savedSplits . length )
87
- newChunk . _fromAggressiveSplittingIndex = j ;
88
- if ( splitData . id !== null && splitData . id !== undefined ) {
89
- newChunk . id = splitData . id ;
102
+ console . log ( "found chunk " + chunk . debugId ) ;
103
+
104
+ const existingSplit = this . xxx . get ( splitData ) ;
105
+
106
+ // Did we already create a chunk for this split?
107
+ if ( existingSplit !== undefined ) {
108
+ console . log ( "use existing split" ) ;
109
+ // Is chunk identical to the split or do we need to split it?
110
+ if ( chunk . getNumberOfModules ( ) > splitData . modules . length ) {
111
+ selectedModules . forEach ( moveModuleBetween ( chunk , existingSplit ) ) ;
112
+ chunk . split ( existingSplit ) ;
113
+ chunk . name = null ;
114
+ } else {
115
+ if ( existingSplit . integrate ( chunk , "aggressive-splitting" ) )
116
+ chunks . splice ( i -- , 1 ) ;
90
117
}
91
- return true ;
92
- } else { // chunk is identical to the split
93
- if ( j < savedSplits . length )
94
- chunk . _fromAggressiveSplittingIndex = j ;
95
- chunk . name = null ;
96
- if ( splitData . id !== null && splitData . id !== undefined ) {
97
- chunk . id = splitData . id ;
118
+ } else {
119
+ // Is chunk identical to the split or do we need to split it?
120
+ if ( chunk . getNumberOfModules ( ) > splitData . modules . length ) {
121
+ // split the chunk into two parts
122
+ const newChunk = compilation . addChunk ( ) ;
123
+ selectedModules . forEach ( moveModuleBetween ( chunk , newChunk ) ) ;
124
+ chunk . split ( newChunk ) ;
125
+ chunk . name = null ;
126
+ this . xxx . set ( splitData , newChunk ) ;
127
+ this . fromAggressiveSplittingSet . add ( newChunk ) ;
128
+ if ( j < savedSplits . length )
129
+ this . fromAggressiveSplittingIndexMap . set ( newChunk , j ) ;
130
+ if ( splitData . id !== null && splitData . id !== undefined ) {
131
+ console . log ( `AggressiveSplittingPlugin assign id ${ splitData . id } ` ) ;
132
+ newChunk . id = splitData . id ;
133
+ }
134
+ return true ;
135
+ } else { // chunk is identical to the split
136
+ if ( j < savedSplits . length )
137
+ this . fromAggressiveSplittingIndexMap . set ( chunk , j ) ;
138
+ chunk . name = null ;
139
+ this . xxx . set ( splitData , chunk ) ;
140
+ if ( splitData . id !== null && splitData . id !== undefined ) {
141
+ console . log ( `AggressiveSplittingPlugin assign id ${ splitData . id } ` ) ;
142
+ chunk . id = splitData . id ;
143
+ }
98
144
}
99
145
}
100
146
}
@@ -139,9 +185,10 @@ class AggressiveSplittingPlugin {
139
185
if ( newChunk . getNumberOfModules ( ) > 0 ) {
140
186
chunk . split ( newChunk ) ;
141
187
chunk . name = null ;
142
- compilation . _aggressiveSplittingSplits = ( compilation . _aggressiveSplittingSplits || [ ] ) . concat ( {
188
+ storedSplits = ( storedSplits || [ ] ) . concat ( {
143
189
modules : newChunk . mapModules ( m => identifierUtils . makePathsRelative ( compiler . context , m . identifier ( ) , compilation . cache ) )
144
190
} ) ;
191
+ this . usedSplitsMap . set ( compilation , storedSplits ) ;
145
192
return true ;
146
193
} else {
147
194
chunks . splice ( chunks . indexOf ( newChunk ) , 1 ) ;
@@ -160,7 +207,8 @@ class AggressiveSplittingPlugin {
160
207
const size = chunk . size ( this . options ) ;
161
208
const incorrectSize = size < minSize ;
162
209
const modules = chunk . mapModules ( m => identifierUtils . makePathsRelative ( compiler . context , m . identifier ( ) , compilation . cache ) ) ;
163
- if ( typeof chunk . _fromAggressiveSplittingIndex === "undefined" ) {
210
+ const index = this . fromAggressiveSplittingIndexMap . get ( chunk ) ;
211
+ if ( typeof index === "undefined" ) {
164
212
if ( incorrectSize ) return ;
165
213
// this is a new chunk splitting, we record it so we reuse it next time
166
214
chunk . recorded = true ;
@@ -170,29 +218,31 @@ class AggressiveSplittingPlugin {
170
218
id : chunk . id
171
219
} ) ;
172
220
} else {
173
- const splitData = records . aggressiveSplits [ chunk . _fromAggressiveSplittingIndex ] ;
221
+ const splitData = records . aggressiveSplits [ index ] ;
174
222
if ( splitData . hash !== chunk . hash || incorrectSize ) {
175
- if ( chunk . _fromAggressiveSplitting ) {
176
- chunk . _aggressiveSplittingInvalid = true ;
223
+ if ( this . fromAggressiveSplittingSet . has ( chunk ) ) {
224
+ this . aggressiveSplittingInvalidSet . add ( chunk ) ;
177
225
splitData . invalid = true ;
178
226
splittingInvalid = true ;
179
227
} else {
180
228
splitData . hash = chunk . hash ;
181
229
}
182
230
}
231
+ console . log ( splitData ) ;
183
232
}
184
233
} ) ;
185
234
if ( splittingInvalid ) {
186
235
records . aggressiveSplits = records . aggressiveSplits . filter ( ( splitData ) => {
187
236
return ! splitData . invalid ;
188
237
} ) ;
189
238
} else {
239
+ console . log ( newSplits ) ;
190
240
records . aggressiveSplits = records . aggressiveSplits . concat ( newSplits ) ;
191
241
}
192
242
} ) ;
193
243
compilation . hooks . needAdditionalSeal . tap ( "AggressiveSplittingPlugin" , ( ) => {
194
244
const invalid = compilation . chunks . some ( ( chunk ) => {
195
- return chunk . _aggressiveSplittingInvalid ;
245
+ return this . aggressiveSplittingInvalidSet . has ( chunk ) ;
196
246
} ) ;
197
247
if ( invalid )
198
248
return true ;
0 commit comments