@@ -76,7 +76,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
76
76
continue ;
77
77
}
78
78
79
- bundlesSources [ statAsset . name ] = bundleInfo . src ;
79
+ bundlesSources [ statAsset . name ] = _ . pick ( bundleInfo , ' src' , 'runtimeSrc' ) ;
80
80
_ . assign ( parsedModules , bundleInfo . modules ) ;
81
81
}
82
82
@@ -94,19 +94,48 @@ function getViewerData(bundleStats, bundleDir, opts) {
94
94
const asset = result [ statAsset . name ] = _ . pick ( statAsset , 'size' ) ;
95
95
96
96
if ( bundlesSources && _ . has ( bundlesSources , statAsset . name ) ) {
97
- asset . parsedSize = Buffer . byteLength ( bundlesSources [ statAsset . name ] ) ;
98
- asset . gzipSize = gzipSize . sync ( bundlesSources [ statAsset . name ] ) ;
97
+ asset . parsedSize = Buffer . byteLength ( bundlesSources [ statAsset . name ] . src ) ;
98
+ asset . gzipSize = gzipSize . sync ( bundlesSources [ statAsset . name ] . src ) ;
99
99
}
100
100
101
101
// Picking modules from current bundle script
102
- asset . modules = _ ( modules )
103
- . filter ( statModule => assetHasModule ( statAsset , statModule ) )
104
- . each ( statModule => {
105
- if ( parsedModules ) {
102
+ const assetModules = modules . filter ( statModule => assetHasModule ( statAsset , statModule ) ) ;
103
+
104
+ // Adding parsed sources
105
+ if ( parsedModules ) {
106
+ const unparsedEntryModules = [ ] ;
107
+
108
+ for ( const statModule of assetModules ) {
109
+ if ( parsedModules [ statModule . id ] ) {
106
110
statModule . parsedSrc = parsedModules [ statModule . id ] ;
111
+ } else if ( isEntryModule ( statModule ) ) {
112
+ unparsedEntryModules . push ( statModule ) ;
107
113
}
108
- } ) ;
114
+ }
115
+
116
+ // Webpack 5 changed bundle format and now entry modules are concatenated and located at the end on the it.
117
+ // Because of this they basically become a concatenated module, for which we can't even precisely determine its
118
+ // parsed source as it's located in the same scope as all Webpack runtime helpers.
119
+ if ( unparsedEntryModules . length ) {
120
+ if ( unparsedEntryModules . length === 1 ) {
121
+ // So if there is only one entry we consider its parsed source to be all the bundle code excluding code
122
+ // from parsed modules.
123
+ unparsedEntryModules [ 0 ] . parsedSrc = bundlesSources [ statAsset . name ] . runtimeSrc ;
124
+ } else {
125
+ // If there are multiple entry points we move all of them under synthetic concatenated module.
126
+ _ . pullAll ( assetModules , unparsedEntryModules ) ;
127
+ assetModules . unshift ( {
128
+ identifier : './entry modules' ,
129
+ name : './entry modules' ,
130
+ modules : unparsedEntryModules ,
131
+ size : unparsedEntryModules . reduce ( ( totalSize , module ) => totalSize + module . size , 0 ) ,
132
+ parsedSrc : bundlesSources [ statAsset . name ] . runtimeSrc
133
+ } ) ;
134
+ }
135
+ }
136
+ }
109
137
138
+ asset . modules = assetModules ;
110
139
asset . tree = createModulesTree ( asset . modules ) ;
111
140
} , { } ) ;
112
141
@@ -148,6 +177,8 @@ function getBundleModules(bundleStats) {
148
177
. compact ( )
149
178
. flatten ( )
150
179
. uniqBy ( 'id' )
180
+ // Filtering out Webpack's runtime modules as they don't have ids and can't be parsed (introduced in Webpack 5)
181
+ . reject ( isRuntimeModule )
151
182
. value ( ) ;
152
183
}
153
184
@@ -158,6 +189,14 @@ function assetHasModule(statAsset, statModule) {
158
189
) ;
159
190
}
160
191
192
+ function isEntryModule ( statModule ) {
193
+ return statModule . depth === 0 ;
194
+ }
195
+
196
+ function isRuntimeModule ( statModule ) {
197
+ return statModule . moduleType === 'runtime' ;
198
+ }
199
+
161
200
function createModulesTree ( modules ) {
162
201
const root = new Folder ( '.' ) ;
163
202
0 commit comments