@@ -74,22 +74,30 @@ function normalizeManifestPaths (tokensByFile, rootDir) {
7474 return output ;
7575}
7676
77+ function dedupeSources ( sources ) {
78+ var foundHashes = { }
79+ Object . keys ( sources ) . forEach ( function ( key ) {
80+ var hash = stringHash ( sources [ key ] ) ;
81+ if ( foundHashes [ hash ] ) {
82+ delete sources [ key ] ;
83+ }
84+ else {
85+ foundHashes [ hash ] = true ;
86+ }
87+ } )
88+ }
89+
7790var cssExt = / \. c s s $ / ;
7891
7992// caches
8093//
8194// persist these for as long as the process is running. #32
8295
83- // keep track of css files visited
84- var filenames = [ ] ;
85-
8696// keep track of all tokens so we can avoid duplicates
8797var tokensByFile = { } ;
8898
89- // keep track of all source files for later builds: when
90- // using watchify, not all files will be caught on subsequent
91- // bundles
92- var sourceByFile = { } ;
99+ // we need a separate loader for each entry point
100+ var loadersByFile = { } ;
93101
94102module . exports = function ( browserify , options ) {
95103 options = options || { } ;
@@ -103,9 +111,10 @@ module.exports = function (browserify, options) {
103111 var jsonOutFilename = options . json || options . jsonOutput ;
104112 var sourceKey = cssOutFilename ;
105113
106- // keying our source caches by the name of our output file means we can
107- // isolate css compilation of seperate bundles that are running in parallel
108- sourceByFile [ sourceKey ] = sourceByFile [ sourceKey ] || { } ;
114+ var loader = loadersByFile [ sourceKey ] ;
115+ if ( ! loader ) {
116+ loader = loadersByFile [ sourceKey ] = new FileSystemLoader ( rootDir , plugins ) ;
117+ }
109118
110119 // PostCSS plugins passed to FileSystemLoader
111120 var plugins = options . use || options . u ;
@@ -158,10 +167,6 @@ module.exports = function (browserify, options) {
158167 return through ( ) ;
159168 }
160169
161- // collect visited filenames
162- filenames . push ( filename ) ;
163-
164- var loader = new FileSystemLoader ( rootDir , plugins ) ;
165170 return through ( function noop ( ) { } , function end ( ) {
166171 var self = this ;
167172
@@ -170,11 +175,6 @@ module.exports = function (browserify, options) {
170175
171176 assign ( tokensByFile , loader . tokensByFile ) ;
172177
173- // store this file's source to be written out to disk later
174- sourceByFile [ sourceKey ] [ filename ] = loader . finalSource ;
175-
176- compiledCssStream . push ( loader . finalSource ) ;
177-
178178 self . queue ( output ) ;
179179 self . queue ( null ) ;
180180 } , function ( err ) {
@@ -195,19 +195,19 @@ module.exports = function (browserify, options) {
195195 bundle . emit ( 'css stream' , compiledCssStream ) ;
196196
197197 bundle . on ( 'end' , function ( ) {
198+ // under certain conditions (eg. with shared libraries) we can end up with
199+ // multiple occurrences of the same rule, so we need to remove duplicates
200+ dedupeSources ( loader . sources )
201+
198202 // Combine the collected sources for a single bundle into a single CSS file
199- var files = Object . keys ( sourceByFile [ sourceKey ] ) ;
200- var css ;
203+ var css = loader . finalSource ;
201204
202205 // end the output stream
206+ compiledCssStream . push ( css ) ;
203207 compiledCssStream . push ( null ) ;
204208
205209 // write the css file
206210 if ( cssOutFilename ) {
207- css = files . map ( function ( file ) {
208- return sourceByFile [ sourceKey ] [ file ] ;
209- } ) . join ( '\n' ) ;
210-
211211 fs . writeFile ( cssOutFilename , css , function ( err ) {
212212 if ( err ) {
213213 browserify . emit ( 'error' , err ) ;
0 commit comments