@@ -209,6 +209,7 @@ class ExtractCssChunks {
209209 result . push ( {
210210 render : ( ) =>
211211 this . renderContentAsset (
212+ compilation ,
212213 chunk ,
213214 renderedModules ,
214215 compilation . runtimeTemplate . requestShortener ,
@@ -234,6 +235,7 @@ class ExtractCssChunks {
234235 result . push ( {
235236 render : ( ) =>
236237 this . renderContentAsset (
238+ compilation ,
237239 chunk ,
238240 renderedModules ,
239241 compilation . runtimeTemplate . requestShortener ,
@@ -423,27 +425,103 @@ class ExtractCssChunks {
423425 return obj ;
424426 }
425427
426- renderContentAsset ( chunk , modules , requestShortener ) {
427- // get first chunk group and take ordr from this one
428- // When a chunk is shared between multiple chunk groups
429- // with different order this can lead to wrong order
430- // but it's not possible to create a correct order in
431- // this case. Don't share chunks if you don't like it.
428+ renderContentAsset ( compilation , chunk , modules , requestShortener ) {
429+ let usedModules ;
430+
432431 const [ chunkGroup ] = chunk . groupsIterable ;
433432 if ( typeof chunkGroup . getModuleIndex2 === 'function' ) {
434- modules . sort (
435- ( a , b ) => chunkGroup . getModuleIndex2 ( a ) - chunkGroup . getModuleIndex2 ( b ) ,
436- ) ;
433+ // Store dependencies for modules
434+ const moduleDependencies = new Map ( modules . map ( m => [ m , new Set ( ) ] ) ) ;
435+
436+ // Get ordered list of modules per chunk group
437+ // This loop also gathers dependencies from the ordered lists
438+ // Lists are in reverse order to allow to use Array.pop()
439+ const modulesByChunkGroup = Array . from ( chunk . groupsIterable , ( cg ) => {
440+ const sortedModules = modules
441+ . map ( m => ( {
442+ module : m ,
443+ index : cg . getModuleIndex2 ( m ) ,
444+ } ) )
445+ . filter ( item => item . index !== undefined )
446+ . sort ( ( a , b ) => b . index - a . index )
447+ . map ( item => item . module ) ;
448+ for ( let i = 0 ; i < sortedModules . length ; i ++ ) {
449+ const set = moduleDependencies . get ( sortedModules [ i ] ) ;
450+ for ( let j = i + 1 ; j < sortedModules . length ; j ++ ) {
451+ set . add ( sortedModules [ j ] ) ;
452+ }
453+ }
454+
455+ return sortedModules ;
456+ } ) ;
457+
458+ // set with already included modules in correct order
459+ usedModules = new Set ( ) ;
460+
461+ const unusedModulesFilter = m => ! usedModules . has ( m ) ;
462+
463+ while ( usedModules . size < modules . length ) {
464+ let success = false ;
465+ let bestMatch ;
466+ let bestMatchDeps ;
467+ // get first module where dependencies are fulfilled
468+ for ( const list of modulesByChunkGroup ) {
469+ // skip and remove already added modules
470+ while ( list . length > 0 && usedModules . has ( list [ list . length - 1 ] ) ) {
471+ list . pop ( ) ;
472+ }
473+
474+ // skip empty lists
475+ if ( list . length !== 0 ) {
476+ const module = list [ list . length - 1 ] ;
477+ const deps = moduleDependencies . get ( module ) ;
478+ // determine dependencies that are not yet included
479+ const failedDeps = Array . from ( deps )
480+ . filter ( unusedModulesFilter ) ;
481+
482+ // store best match for fallback behavior
483+ if ( ! bestMatchDeps || bestMatchDeps . length > failedDeps . length ) {
484+ bestMatch = list ;
485+ bestMatchDeps = failedDeps ;
486+ }
487+ if ( failedDeps . length === 0 ) {
488+ // use this module and remove it from list
489+ usedModules . add ( list . pop ( ) ) ;
490+ success = true ;
491+ break ;
492+ }
493+ }
494+ }
495+
496+ if ( ! success ) {
497+ // no module found => there is a conflict
498+ // use list with fewest failed deps
499+ // and emit a warning
500+ const fallbackModule = bestMatch . pop ( ) ;
501+ compilation . warnings . push (
502+ new Error (
503+ `chunk ${ chunk . name || chunk . id } [mini-css-extract-plugin]\n` +
504+ 'Conflicting order between:\n' +
505+ ` * ${ fallbackModule . readableIdentifier ( requestShortener ) } \n` +
506+ `${ bestMatchDeps
507+ . map ( m => ` * ${ m . readableIdentifier ( requestShortener ) } ` )
508+ . join ( '\n' ) } `,
509+ ) ,
510+ ) ;
511+ usedModules . add ( fallbackModule ) ;
512+ }
513+ }
437514 } else {
438515 // fallback for older webpack versions
439516 // (to avoid a breaking change)
440517 // TODO remove this in next mayor version
441518 // and increase minimum webpack version to 4.12.0
442519 modules . sort ( ( a , b ) => a . index2 - b . index2 ) ;
520+ usedModules = modules ;
443521 }
444522 const source = new ConcatSource ( ) ;
445523 const externalsSource = new ConcatSource ( ) ;
446- for ( const m of modules ) {
524+ for ( const m of usedModules ) {
447525 if ( / ^ @ i m p o r t u r l / . test ( m . content ) ) {
448526 // HACK for IE
449527 // http://stackoverflow.com/a/14676665/1458162
0 commit comments