2
2
MIT License http://www.opensource.org/licenses/mit-license.php
3
3
Author Tobias Koppers @sokra
4
4
*/
5
- var SourceMapSource = require ( "webpack/lib/SourceMapSource " ) ;
5
+ var ConcatSource = require ( "webpack/lib/ConcatSource " ) ;
6
6
var Template = require ( "webpack/lib/Template" ) ;
7
7
var async = require ( "async" ) ;
8
8
var SourceNode = require ( "source-map" ) . SourceNode ;
9
9
var SourceMapConsumer = require ( "source-map" ) . SourceMapConsumer ;
10
10
var ModuleFilenameHelpers = require ( "webpack/lib/ModuleFilenameHelpers" ) ;
11
+ var ExtractedModule = require ( "./ExtractedModule" ) ;
12
+ var Chunk = require ( "webpack/lib/Chunk" ) ;
11
13
12
14
var nextId = 0 ;
13
15
@@ -21,6 +23,7 @@ function ExtractTextPlugin(id, filename, options) {
21
23
this . filename = filename ;
22
24
this . options = options ;
23
25
this . id = id ;
26
+ this . modulesByIdentifier = { } ;
24
27
}
25
28
module . exports = ExtractTextPlugin ;
26
29
@@ -44,15 +47,15 @@ ExtractTextPlugin.extract = function(before, loader) {
44
47
}
45
48
} ;
46
49
47
- ExtractTextPlugin . prototype . applyAdditionalInformation = function ( node , info ) {
48
- if ( info . length === 1 && info [ 0 ] ) {
49
- node = new SourceNode ( null , null , null , [
50
+ ExtractTextPlugin . prototype . applyAdditionalInformation = function ( source , info ) {
51
+ if ( info ) {
52
+ return new ConcatSource (
50
53
"@media " + info [ 0 ] + " {" ,
51
- node ,
54
+ source ,
52
55
"}"
53
- ] ) ;
56
+ ) ;
54
57
}
55
- return node ;
58
+ return source ;
56
59
} ;
57
60
58
61
ExtractTextPlugin . prototype . loader = function ( options ) {
@@ -64,7 +67,7 @@ ExtractTextPlugin.prototype.loader = function(options) {
64
67
ExtractTextPlugin . prototype . extract = function ( before , loader ) {
65
68
if ( loader ) {
66
69
return [
67
- this . loader ( { move : before . split ( "!" ) . length , extract : true , remove : true } ) ,
70
+ this . loader ( { omit : before . split ( "!" ) . length , extract : true , remove : true } ) ,
68
71
before ,
69
72
loader
70
73
] . join ( "!" ) ;
@@ -82,6 +85,8 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
82
85
compiler . plugin ( "this-compilation" , function ( compilation ) {
83
86
compilation . plugin ( "normal-module-loader" , function ( loaderContext , module ) {
84
87
loaderContext [ __dirname ] = function ( content , opt ) {
88
+ if ( options . disable )
89
+ return false ;
85
90
if ( ! Array . isArray ( content ) && content !== null )
86
91
throw new Error ( "Exported value is not a string." ) ;
87
92
module . meta [ __dirname ] = {
@@ -94,11 +99,38 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
94
99
var contents ;
95
100
var filename = this . filename ;
96
101
var id = this . id ;
102
+ var extractedChunks , entryChunks ;
103
+ compilation . plugin ( "optimize" , function ( ) {
104
+ entryChunks = compilation . chunks . filter ( function ( c ) {
105
+ return c . entry ;
106
+ } ) ;
107
+ } . bind ( this ) ) ;
97
108
compilation . plugin ( "optimize-tree" , function ( chunks , modules , callback ) {
98
109
contents = [ ] ;
110
+ extractedChunks = chunks . map ( function ( chunk ) {
111
+ return new Chunk ( ) ;
112
+ } ) ;
113
+ chunks . forEach ( function ( chunk , i ) {
114
+ var extractedChunk = extractedChunks [ i ] ;
115
+ extractedChunk . index = i ;
116
+ extractedChunk . originalChunk = chunk ;
117
+ extractedChunk . name = chunk . name ;
118
+ chunk . chunks . forEach ( function ( c ) {
119
+ extractedChunk . addChunk ( extractedChunks [ chunks . indexOf ( c ) ] ) ;
120
+ } ) ;
121
+ chunk . parents . forEach ( function ( c ) {
122
+ extractedChunk . addParent ( extractedChunks [ chunks . indexOf ( c ) ] ) ;
123
+ } ) ;
124
+ } ) ;
125
+ entryChunks . forEach ( function ( chunk ) {
126
+ var idx = chunks . indexOf ( chunk ) ;
127
+ if ( idx < 0 ) return ;
128
+ var extractedChunk = extractedChunks [ idx ] ;
129
+ extractedChunk . entry = extractedChunk . initial = true ;
130
+ } ) ;
99
131
async . forEach ( chunks , function ( chunk , callback ) {
132
+ var extractedChunk = extractedChunks [ chunks . indexOf ( chunk ) ] ;
100
133
var shouldExtract = ! ! ( options . allChunks || chunk . initial ) ;
101
- var content = [ ] ;
102
134
async . forEach ( chunk . modules . slice ( ) , function ( module , callback ) {
103
135
var meta = module . meta && module . meta [ __dirname ] ;
104
136
if ( meta ) {
@@ -116,59 +148,89 @@ ExtractTextPlugin.prototype.apply = function(compiler) {
116
148
compilation . errors . push ( err ) ;
117
149
return callback ( ) ;
118
150
}
119
- if ( meta . content ) content . push ( meta . content ) ;
151
+ if ( meta . content )
152
+ this . addResultToChunk ( module . identifier ( ) , meta . content , extractedChunk ) ;
120
153
callback ( ) ;
121
- } ) ;
154
+ } . bind ( this ) ) ;
122
155
} else {
123
- if ( meta . content ) content . push ( meta . content ) ;
156
+ if ( meta . content )
157
+ this . addResultToChunk ( module . identifier ( ) , meta . content , extractedChunk ) ;
124
158
callback ( ) ;
125
159
}
126
160
} else callback ( ) ;
127
- } , function ( err ) {
161
+ } . bind ( this ) , function ( err ) {
128
162
if ( err ) return callback ( err ) ;
129
- if ( content . length > 0 ) {
130
- contents . push ( {
131
- chunk : chunk ,
132
- content : content
133
- } ) ;
134
- }
135
163
callback ( ) ;
136
164
} . bind ( this ) ) ;
137
165
} . bind ( this ) , function ( err ) {
138
166
if ( err ) return callback ( err ) ;
167
+ extractedChunks . forEach ( function ( extractedChunk ) {
168
+ if ( extractedChunk . initial )
169
+ this . mergeNonInitialChunks ( extractedChunk ) ;
170
+ } , this ) ;
171
+ compilation . applyPlugins ( "optimize-extracted-chunks" , extractedChunks ) ;
139
172
callback ( ) ;
140
173
} . bind ( this ) ) ;
141
- } ) ;
174
+ } . bind ( this ) ) ;
142
175
compilation . plugin ( "additional-assets" , function ( callback ) {
143
176
var assetContents = { } ;
144
- contents . forEach ( function ( item ) {
145
- var chunk = item . chunk ;
146
- var file = compilation . getPath ( filename , {
147
- chunk : chunk
148
- } ) ;
149
- assetContents [ file ] = ( assetContents [ file ] || [ ] ) . concat ( item . content ) ;
150
- chunk . files . push ( file ) ;
151
- } ) ;
152
- Object . keys ( assetContents ) . forEach ( function ( file ) {
153
- var contained = { } ;
154
- var content = assetContents [ file ] . reduce ( function ( arr , items ) {
155
- return arr . concat ( items ) ;
156
- } , [ ] ) . filter ( function ( item ) {
157
- if ( contained [ item [ 0 ] ] ) return false ;
158
- contained [ item [ 0 ] ] = true ;
159
- return true ;
160
- } ) . map ( function ( item ) {
161
- var css = item [ 1 ] ;
162
- var contents = item . slice ( 1 ) . filter ( function ( i ) { return typeof i === "string" ; } ) ;
163
- var sourceMap = typeof item [ item . length - 1 ] === "object" ? item [ item . length - 1 ] : undefined ;
164
- var text = contents . shift ( ) ;
165
- var node = sourceMap ? SourceNode . fromStringWithSourceMap ( text , new SourceMapConsumer ( sourceMap ) ) : new SourceNode ( null , null , null , text ) ;
166
- return this . applyAdditionalInformation ( node , contents ) ;
167
- } . bind ( this ) ) ;
168
- var strAndMap = new SourceNode ( null , null , null , content ) . toStringWithSourceMap ( ) ;
169
- compilation . assets [ file ] = new SourceMapSource ( strAndMap . code , file , strAndMap . map . toJSON ( ) ) ;
170
- } . bind ( this ) ) ;
177
+ extractedChunks . forEach ( function ( extractedChunk ) {
178
+ if ( extractedChunk . modules . length ) {
179
+ var chunk = extractedChunk . originalChunk ;
180
+ var file = compilation . getPath ( filename , {
181
+ chunk : chunk
182
+ } ) ;
183
+ compilation . assets [ file ] = this . renderExtractedChunk ( extractedChunk ) ;
184
+ chunk . files . push ( file ) ;
185
+ }
186
+ } , this ) ;
171
187
callback ( ) ;
172
188
} . bind ( this ) ) ;
173
189
} . bind ( this ) ) ;
174
190
} ;
191
+
192
+ ExtractTextPlugin . prototype . mergeNonInitialChunks = function ( chunk , intoChunk , checkedChunks ) {
193
+ if ( ! intoChunk ) {
194
+ checkedChunks = [ ] ;
195
+ chunk . chunks . forEach ( function ( c ) {
196
+ if ( c . initial ) return ;
197
+ this . mergeNonInitialChunks ( c , chunk , checkedChunks ) ;
198
+ } , this ) ;
199
+ } else if ( checkedChunks . indexOf ( chunk ) < 0 ) {
200
+ checkedChunks . push ( chunk ) ;
201
+ chunk . modules . slice ( ) . forEach ( function ( module ) {
202
+ chunk . removeModule ( module ) ;
203
+ intoChunk . addModule ( module ) ;
204
+ module . addChunk ( intoChunk ) ;
205
+ } ) ;
206
+ chunk . chunks . forEach ( function ( c ) {
207
+ if ( c . initial ) return ;
208
+ this . mergeNonInitialChunks ( c , intoChunk , checkedChunks ) ;
209
+ } , this ) ;
210
+ }
211
+ } ;
212
+
213
+ ExtractTextPlugin . prototype . addModule = function ( identifier , source , sourceMap , additionalInformation ) {
214
+ if ( ! this . modulesByIdentifier [ identifier ] )
215
+ return this . modulesByIdentifier [ identifier ] = new ExtractedModule ( identifier , source , sourceMap , additionalInformation ) ;
216
+ return this . modulesByIdentifier [ identifier ] ;
217
+ } ;
218
+
219
+ ExtractTextPlugin . prototype . addResultToChunk = function ( identifier , result , extractedChunk ) {
220
+ if ( ! Array . isArray ( result ) ) {
221
+ result = [ [ identifier , result ] ] ;
222
+ }
223
+ result . forEach ( function ( item ) {
224
+ var module = this . addModule . apply ( this , item ) ;
225
+ extractedChunk . addModule ( module ) ;
226
+ module . addChunk ( extractedChunk ) ;
227
+ } , this ) ;
228
+ } ;
229
+
230
+ ExtractTextPlugin . prototype . renderExtractedChunk = function ( chunk ) {
231
+ var source = new ConcatSource ( ) ;
232
+ chunk . modules . forEach ( function ( module ) {
233
+ source . add ( this . applyAdditionalInformation ( module . source ( ) , module . additionalInformation ) ) ;
234
+ } , this ) ;
235
+ return source ;
236
+ } ;
0 commit comments