webpack-bundle-analyzer 2.13.0 → 2.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/lib/BundleAnalyzerPlugin.js +1 -0
- package/lib/parseUtils.js +84 -92
- package/package.json +1 -1
- package/src/BundleAnalyzerPlugin.js +1 -0
- package/src/parseUtils.js +123 -124
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,17 @@ _Note: Gaps between patch versions are faulty, broken or test releases._
|
|
|
14
14
|
|
|
15
15
|
<!-- Add changelog entries for new changes under this section -->
|
|
16
16
|
|
|
17
|
+
## 2.13.1
|
|
18
|
+
|
|
19
|
+
* **Improvement**
|
|
20
|
+
* Pretty-format the generated stats.json ([#180](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/180)) [@edmorley](https://github.com/edmorley))
|
|
21
|
+
|
|
22
|
+
* **Bug Fix**
|
|
23
|
+
* Properly parse Webpack 4 async chunk with `Array.concat` optimization ([#184](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/184), fixes [#183](https://github.com/webpack-contrib/webpack-bundle-analyzer/issues/183))
|
|
24
|
+
|
|
25
|
+
* **Internal**
|
|
26
|
+
* Refactor bundle parsing logic ([#184](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/184))
|
|
27
|
+
|
|
17
28
|
## 2.13.0
|
|
18
29
|
|
|
19
30
|
* **Improvement**
|
package/lib/parseUtils.js
CHANGED
|
@@ -25,40 +25,31 @@ function parseBundle(bundlePath) {
|
|
|
25
25
|
|
|
26
26
|
walk.recursive(ast, walkState, {
|
|
27
27
|
CallExpression(node, state, c) {
|
|
28
|
-
if (state.
|
|
28
|
+
if (state.locations) return;
|
|
29
29
|
|
|
30
30
|
var args = node.arguments;
|
|
31
31
|
|
|
32
|
-
//
|
|
33
|
-
// Modules are stored in
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
state.locations = getModulesLocationFromFunctionArgument(args[1]);
|
|
32
|
+
// Main chunk with webpack loader.
|
|
33
|
+
// Modules are stored in first argument:
|
|
34
|
+
// (function (...) {...})(<modules>)
|
|
35
|
+
if (node.callee.type === 'FunctionExpression' && !node.callee.id && args.length === 1 && isSimpleModulesList(args[0])) {
|
|
36
|
+
state.locations = getModulesLocations(args[0]);
|
|
38
37
|
return;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
// webpackJsonp([<chunks>], Array([minimum ID]).concat([<module>, <module>, ...]))
|
|
40
|
+
// Async Webpack < v4 chunk without webpack loader.
|
|
41
|
+
// webpackJsonp([<chunks>], <modules>, ...)
|
|
44
42
|
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
45
|
-
if (node.callee.type === 'Identifier' && (args
|
|
46
|
-
state.locations =
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Main bundle with webpack loader
|
|
51
|
-
// Modules are stored in first argument:
|
|
52
|
-
// (function (...) {...})(<modules>)
|
|
53
|
-
if (node.callee.type === 'FunctionExpression' && !node.callee.id && args.length === 1 && isArgumentContainsModulesList(args[0])) {
|
|
54
|
-
state.locations = getModulesLocationFromFunctionArgument(args[0]);
|
|
43
|
+
if (node.callee.type === 'Identifier' && mayBeAsyncChunkArguments(args) && isModulesList(args[1])) {
|
|
44
|
+
state.locations = getModulesLocations(args[1]);
|
|
55
45
|
return;
|
|
56
46
|
}
|
|
57
47
|
|
|
58
|
-
//
|
|
59
|
-
// (window.webpackJsonp=window.webpackJsonp||[]).push([[
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
// Async Webpack v4 chunk without webpack loader.
|
|
49
|
+
// (window.webpackJsonp=window.webpackJsonp||[]).push([[<chunks>], <modules>, ...]);
|
|
50
|
+
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
51
|
+
if (isAsyncChunkPushExpression(node)) {
|
|
52
|
+
state.locations = getModulesLocations(args[0].elements[1]);
|
|
62
53
|
return;
|
|
63
54
|
}
|
|
64
55
|
|
|
@@ -86,60 +77,45 @@ function parseBundle(bundlePath) {
|
|
|
86
77
|
};
|
|
87
78
|
}
|
|
88
79
|
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
80
|
+
function isModulesList(node) {
|
|
81
|
+
return isSimpleModulesList(node) ||
|
|
82
|
+
// Modules are contained in expression `Array([minimum ID]).concat([<module>, <module>, ...])`
|
|
83
|
+
isOptimizedModulesArray(node);
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
function
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return _.every(arg.elements, function (elem) {
|
|
103
|
-
return (
|
|
104
|
-
// Some of array items may be skipped because there is no module with such id
|
|
105
|
-
!elem || isModuleWrapper(elem)
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
86
|
+
function isSimpleModulesList(node) {
|
|
87
|
+
return (
|
|
88
|
+
// Modules are contained in hash. Keys are module ids.
|
|
89
|
+
isModulesHash(node) ||
|
|
90
|
+
// Modules are contained in array. Indexes are module ids.
|
|
91
|
+
isModulesArray(node)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
109
94
|
|
|
110
|
-
|
|
95
|
+
function isModulesHash(node) {
|
|
96
|
+
return node.type === 'ObjectExpression' && _(node.properties).map('value').every(isModuleWrapper);
|
|
111
97
|
}
|
|
112
98
|
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
|
|
99
|
+
function isModulesArray(node) {
|
|
100
|
+
return node.type === 'ArrayExpression' && _.every(node.elements, function (elem) {
|
|
101
|
+
return (
|
|
102
|
+
// Some of array items may be skipped because there is no module with such id
|
|
103
|
+
!elem || isModuleWrapper(elem)
|
|
104
|
+
);
|
|
105
|
+
});
|
|
118
106
|
}
|
|
119
107
|
|
|
120
|
-
function
|
|
121
|
-
|
|
108
|
+
function isOptimizedModulesArray(node) {
|
|
109
|
+
// Checking whether modules are contained in `Array(<minimum ID>).concat(...modules)` array:
|
|
110
|
+
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
|
|
111
|
+
// The `<minimum ID>` + array indexes are module ids
|
|
112
|
+
return node.type === 'CallExpression' && node.callee.type === 'MemberExpression' &&
|
|
122
113
|
// Make sure the object called is `Array(<some number>)`
|
|
123
|
-
|
|
114
|
+
node.callee.object.type === 'CallExpression' && node.callee.object.callee.type === 'Identifier' && node.callee.object.callee.name === 'Array' && node.callee.object.arguments.length === 1 && isNumericId(node.callee.object.arguments[0]) &&
|
|
124
115
|
// Make sure the property X called for `Array(<some number>).X` is `concat`
|
|
125
|
-
|
|
116
|
+
node.callee.property.type === 'Identifier' && node.callee.property.name === 'concat' &&
|
|
126
117
|
// Make sure exactly one array is passed in to `concat`
|
|
127
|
-
|
|
128
|
-
// Modules are contained in `Array(<minimum ID>).concat(` array:
|
|
129
|
-
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
|
|
130
|
-
// The `<minimum ID>` + array indexes are module ids
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function isAsyncChunkPushExpression(node) {
|
|
138
|
-
var callee = node.callee;
|
|
139
|
-
|
|
140
|
-
return callee.type === 'MemberExpression' && callee.property.name === 'push' && callee.object.type === 'AssignmentExpression' && (callee.object.left.object.name === 'window' ||
|
|
141
|
-
// Webpack 4 uses `this` instead of `window`
|
|
142
|
-
callee.object.left.object.type === 'ThisExpression');
|
|
118
|
+
node.arguments.length === 1 && isModulesArray(node.arguments[0]);
|
|
143
119
|
}
|
|
144
120
|
|
|
145
121
|
function isModuleWrapper(node) {
|
|
@@ -161,9 +137,29 @@ function isNumericId(node) {
|
|
|
161
137
|
return node.type === 'Literal' && Number.isInteger(node.value) && node.value >= 0;
|
|
162
138
|
}
|
|
163
139
|
|
|
164
|
-
function
|
|
165
|
-
|
|
166
|
-
|
|
140
|
+
function isChunkIds(node) {
|
|
141
|
+
// Array of numeric or string ids. Chunk IDs are strings when NamedChunksPlugin is used
|
|
142
|
+
return node.type === 'ArrayExpression' && _.every(node.elements, isModuleId);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function isAsyncChunkPushExpression(node) {
|
|
146
|
+
var callee = node.callee,
|
|
147
|
+
args = node.arguments;
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
return callee.type === 'MemberExpression' && callee.property.name === 'push' && callee.object.type === 'AssignmentExpression' && callee.object.left.object && (callee.object.left.object.name === 'window' ||
|
|
151
|
+
// Webpack 4 uses `this` instead of `window`
|
|
152
|
+
callee.object.left.object.type === 'ThisExpression') && args.length === 1 && args[0].type === 'ArrayExpression' && mayBeAsyncChunkArguments(args[0].elements) && isModulesList(args[0].elements[1]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function mayBeAsyncChunkArguments(args) {
|
|
156
|
+
return args.length >= 2 && isChunkIds(args[0]);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getModulesLocations(node) {
|
|
160
|
+
if (node.type === 'ObjectExpression') {
|
|
161
|
+
// Modules hash
|
|
162
|
+
var modulesNodes = node.properties;
|
|
167
163
|
|
|
168
164
|
return _.transform(modulesNodes, function (result, moduleNode) {
|
|
169
165
|
var moduleId = moduleNode.key.name || moduleNode.key.value;
|
|
@@ -172,35 +168,31 @@ function getModulesLocationFromFunctionArgument(arg) {
|
|
|
172
168
|
}, {});
|
|
173
169
|
}
|
|
174
170
|
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
var isOptimizedArray = node.type === 'CallExpression';
|
|
172
|
+
|
|
173
|
+
if (node.type === 'ArrayExpression' || isOptimizedArray) {
|
|
174
|
+
// Modules array or optimized array
|
|
175
|
+
var minId = isOptimizedArray ?
|
|
176
|
+
// Get the [minId] value from the Array() call first argument literal value
|
|
177
|
+
node.callee.object.arguments[0].value :
|
|
178
|
+
// `0` for simple array
|
|
179
|
+
0;
|
|
180
|
+
var _modulesNodes = isOptimizedArray ?
|
|
181
|
+
// The modules reside in the `concat()` function call arguments
|
|
182
|
+
node.arguments[0].elements : node.elements;
|
|
177
183
|
|
|
178
184
|
return _.transform(_modulesNodes, function (result, moduleNode, i) {
|
|
179
185
|
if (!moduleNode) return;
|
|
180
|
-
|
|
181
|
-
result[i] = getModuleLocation(moduleNode);
|
|
186
|
+
result[i + minId] = getModuleLocation(moduleNode);
|
|
182
187
|
}, {});
|
|
183
188
|
}
|
|
184
189
|
|
|
185
190
|
return {};
|
|
186
191
|
}
|
|
187
192
|
|
|
188
|
-
function getModulesLocationFromArrayConcat(arg) {
|
|
189
|
-
// arg(CallExpression) =
|
|
190
|
-
// Array([minId]).concat([<minId module>, <minId+1 module>, ...])
|
|
191
|
-
//
|
|
192
|
-
// Get the [minId] value from the Array() call first argument literal value
|
|
193
|
-
var minId = arg.callee.object.arguments[0].value;
|
|
194
|
-
// The modules reside in the `concat()` function call arguments
|
|
195
|
-
var modulesNodes = arg.arguments[0].elements;
|
|
196
|
-
|
|
197
|
-
return _.transform(modulesNodes, function (result, moduleNode, i) {
|
|
198
|
-
if (!moduleNode) return;
|
|
199
|
-
|
|
200
|
-
result[i + minId] = getModuleLocation(moduleNode);
|
|
201
|
-
}, {});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
193
|
function getModuleLocation(node) {
|
|
205
|
-
return
|
|
194
|
+
return {
|
|
195
|
+
start: node.start,
|
|
196
|
+
end: node.end
|
|
197
|
+
};
|
|
206
198
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webpack-bundle-analyzer",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.1",
|
|
4
4
|
"description": "Webpack plugin and CLI utility that represents bundle content as convenient interactive zoomable treemap",
|
|
5
5
|
"author": "Yury Grunin <grunin.ya@ya.ru>",
|
|
6
6
|
"license": "MIT",
|
package/src/parseUtils.js
CHANGED
|
@@ -26,59 +26,40 @@ function parseBundle(bundlePath) {
|
|
|
26
26
|
walkState,
|
|
27
27
|
{
|
|
28
28
|
CallExpression(node, state, c) {
|
|
29
|
-
if (state.
|
|
29
|
+
if (state.locations) return;
|
|
30
30
|
|
|
31
31
|
const args = node.arguments;
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
// Modules are stored in second argument, after chunk ids:
|
|
35
|
-
// webpackJsonp([<chunks>], <modules>, ...)
|
|
36
|
-
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
37
|
-
if (
|
|
38
|
-
node.callee.type === 'Identifier' &&
|
|
39
|
-
args.length >= 2 &&
|
|
40
|
-
isArgumentContainsChunkIds(args[0]) &&
|
|
41
|
-
isArgumentContainsModulesList(args[1])
|
|
42
|
-
) {
|
|
43
|
-
state.locations = getModulesLocationFromFunctionArgument(args[1]);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Additional bundle without webpack loader, with module IDs optimized.
|
|
48
|
-
// Modules are stored in second arguments Array(n).concat() call
|
|
49
|
-
// webpackJsonp([<chunks>], Array([minimum ID]).concat([<module>, <module>, ...]))
|
|
50
|
-
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
51
|
-
if (
|
|
52
|
-
node.callee.type === 'Identifier' &&
|
|
53
|
-
(args.length === 2 || args.length === 3) &&
|
|
54
|
-
isArgumentContainsChunkIds(args[0]) &&
|
|
55
|
-
isArgumentArrayConcatContainingChunks(args[1])
|
|
56
|
-
) {
|
|
57
|
-
state.locations = getModulesLocationFromArrayConcat(args[1]);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Main bundle with webpack loader
|
|
33
|
+
// Main chunk with webpack loader.
|
|
62
34
|
// Modules are stored in first argument:
|
|
63
35
|
// (function (...) {...})(<modules>)
|
|
64
36
|
if (
|
|
65
37
|
node.callee.type === 'FunctionExpression' &&
|
|
66
38
|
!node.callee.id &&
|
|
67
39
|
args.length === 1 &&
|
|
68
|
-
|
|
40
|
+
isSimpleModulesList(args[0])
|
|
69
41
|
) {
|
|
70
|
-
state.locations =
|
|
42
|
+
state.locations = getModulesLocations(args[0]);
|
|
71
43
|
return;
|
|
72
44
|
}
|
|
73
45
|
|
|
74
|
-
//
|
|
75
|
-
//
|
|
46
|
+
// Async Webpack < v4 chunk without webpack loader.
|
|
47
|
+
// webpackJsonp([<chunks>], <modules>, ...)
|
|
48
|
+
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
76
49
|
if (
|
|
77
|
-
|
|
78
|
-
args
|
|
79
|
-
|
|
50
|
+
node.callee.type === 'Identifier' &&
|
|
51
|
+
mayBeAsyncChunkArguments(args) &&
|
|
52
|
+
isModulesList(args[1])
|
|
80
53
|
) {
|
|
81
|
-
state.locations =
|
|
54
|
+
state.locations = getModulesLocations(args[1]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Async Webpack v4 chunk without webpack loader.
|
|
59
|
+
// (window.webpackJsonp=window.webpackJsonp||[]).push([[<chunks>], <modules>, ...]);
|
|
60
|
+
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
|
61
|
+
if (isAsyncChunkPushExpression(node)) {
|
|
62
|
+
state.locations = getModulesLocations(args[0].elements[1]);
|
|
82
63
|
return;
|
|
83
64
|
}
|
|
84
65
|
|
|
@@ -105,80 +86,62 @@ function parseBundle(bundlePath) {
|
|
|
105
86
|
};
|
|
106
87
|
}
|
|
107
88
|
|
|
108
|
-
function
|
|
109
|
-
|
|
110
|
-
|
|
89
|
+
function isModulesList(node) {
|
|
90
|
+
return (
|
|
91
|
+
isSimpleModulesList(node) ||
|
|
92
|
+
// Modules are contained in expression `Array([minimum ID]).concat([<module>, <module>, ...])`
|
|
93
|
+
isOptimizedModulesArray(node)
|
|
94
|
+
);
|
|
111
95
|
}
|
|
112
96
|
|
|
113
|
-
function
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
function isSimpleModulesList(node) {
|
|
98
|
+
return (
|
|
99
|
+
// Modules are contained in hash. Keys are module ids.
|
|
100
|
+
isModulesHash(node) ||
|
|
101
|
+
// Modules are contained in array. Indexes are module ids.
|
|
102
|
+
isModulesArray(node)
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isModulesHash(node) {
|
|
107
|
+
return (
|
|
108
|
+
node.type === 'ObjectExpression' &&
|
|
109
|
+
_(node.properties)
|
|
116
110
|
.map('value')
|
|
117
|
-
.every(isModuleWrapper)
|
|
118
|
-
|
|
111
|
+
.every(isModuleWrapper)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
function isModulesArray(node) {
|
|
116
|
+
return (
|
|
117
|
+
node.type === 'ArrayExpression' &&
|
|
118
|
+
_.every(node.elements, elem =>
|
|
124
119
|
// Some of array items may be skipped because there is no module with such id
|
|
125
120
|
!elem ||
|
|
126
121
|
isModuleWrapper(elem)
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function isArgumentContainingChunkIdsAndModulesList(arg) {
|
|
134
|
-
if (
|
|
135
|
-
arg.type === 'ArrayExpression' &&
|
|
136
|
-
arg.elements.length >= 2 &&
|
|
137
|
-
isArgumentContainsChunkIds(arg.elements[0]) &&
|
|
138
|
-
isArgumentContainsModulesList(arg.elements[1])
|
|
139
|
-
) {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
return false;
|
|
122
|
+
)
|
|
123
|
+
);
|
|
143
124
|
}
|
|
144
125
|
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
126
|
+
function isOptimizedModulesArray(node) {
|
|
127
|
+
// Checking whether modules are contained in `Array(<minimum ID>).concat(...modules)` array:
|
|
128
|
+
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
|
|
129
|
+
// The `<minimum ID>` + array indexes are module ids
|
|
130
|
+
return (
|
|
131
|
+
node.type === 'CallExpression' &&
|
|
132
|
+
node.callee.type === 'MemberExpression' &&
|
|
149
133
|
// Make sure the object called is `Array(<some number>)`
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
isNumericId(
|
|
134
|
+
node.callee.object.type === 'CallExpression' &&
|
|
135
|
+
node.callee.object.callee.type === 'Identifier' &&
|
|
136
|
+
node.callee.object.callee.name === 'Array' &&
|
|
137
|
+
node.callee.object.arguments.length === 1 &&
|
|
138
|
+
isNumericId(node.callee.object.arguments[0]) &&
|
|
155
139
|
// Make sure the property X called for `Array(<some number>).X` is `concat`
|
|
156
|
-
|
|
157
|
-
|
|
140
|
+
node.callee.property.type === 'Identifier' &&
|
|
141
|
+
node.callee.property.name === 'concat' &&
|
|
158
142
|
// Make sure exactly one array is passed in to `concat`
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
) {
|
|
162
|
-
// Modules are contained in `Array(<minimum ID>).concat(` array:
|
|
163
|
-
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
|
|
164
|
-
// The `<minimum ID>` + array indexes are module ids
|
|
165
|
-
return true;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function isAsyncChunkPushExpression(node) {
|
|
172
|
-
const { callee } = node;
|
|
173
|
-
return (
|
|
174
|
-
callee.type === 'MemberExpression' &&
|
|
175
|
-
callee.property.name === 'push' &&
|
|
176
|
-
callee.object.type === 'AssignmentExpression' &&
|
|
177
|
-
(
|
|
178
|
-
callee.object.left.object.name === 'window' ||
|
|
179
|
-
// Webpack 4 uses `this` instead of `window`
|
|
180
|
-
callee.object.left.object.type === 'ThisExpression'
|
|
181
|
-
)
|
|
143
|
+
node.arguments.length === 1 &&
|
|
144
|
+
isModulesArray(node.arguments[0])
|
|
182
145
|
);
|
|
183
146
|
}
|
|
184
147
|
|
|
@@ -201,9 +164,48 @@ function isNumericId(node) {
|
|
|
201
164
|
return (node.type === 'Literal' && Number.isInteger(node.value) && node.value >= 0);
|
|
202
165
|
}
|
|
203
166
|
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
|
|
167
|
+
function isChunkIds(node) {
|
|
168
|
+
// Array of numeric or string ids. Chunk IDs are strings when NamedChunksPlugin is used
|
|
169
|
+
return (
|
|
170
|
+
node.type === 'ArrayExpression' &&
|
|
171
|
+
_.every(node.elements, isModuleId)
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function isAsyncChunkPushExpression(node) {
|
|
176
|
+
const {
|
|
177
|
+
callee,
|
|
178
|
+
arguments: args
|
|
179
|
+
} = node;
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
callee.type === 'MemberExpression' &&
|
|
183
|
+
callee.property.name === 'push' &&
|
|
184
|
+
callee.object.type === 'AssignmentExpression' &&
|
|
185
|
+
callee.object.left.object &&
|
|
186
|
+
(
|
|
187
|
+
callee.object.left.object.name === 'window' ||
|
|
188
|
+
// Webpack 4 uses `this` instead of `window`
|
|
189
|
+
callee.object.left.object.type === 'ThisExpression'
|
|
190
|
+
) &&
|
|
191
|
+
args.length === 1 &&
|
|
192
|
+
args[0].type === 'ArrayExpression' &&
|
|
193
|
+
mayBeAsyncChunkArguments(args[0].elements) &&
|
|
194
|
+
isModulesList(args[0].elements[1])
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function mayBeAsyncChunkArguments(args) {
|
|
199
|
+
return (
|
|
200
|
+
args.length >= 2 &&
|
|
201
|
+
isChunkIds(args[0])
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function getModulesLocations(node) {
|
|
206
|
+
if (node.type === 'ObjectExpression') {
|
|
207
|
+
// Modules hash
|
|
208
|
+
const modulesNodes = node.properties;
|
|
207
209
|
|
|
208
210
|
return _.transform(modulesNodes, (result, moduleNode) => {
|
|
209
211
|
const moduleId = moduleNode.key.name || moduleNode.key.value;
|
|
@@ -212,35 +214,32 @@ function getModulesLocationFromFunctionArgument(arg) {
|
|
|
212
214
|
}, {});
|
|
213
215
|
}
|
|
214
216
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
const isOptimizedArray = (node.type === 'CallExpression');
|
|
218
|
+
|
|
219
|
+
if (node.type === 'ArrayExpression' || isOptimizedArray) {
|
|
220
|
+
// Modules array or optimized array
|
|
221
|
+
const minId = isOptimizedArray ?
|
|
222
|
+
// Get the [minId] value from the Array() call first argument literal value
|
|
223
|
+
node.callee.object.arguments[0].value :
|
|
224
|
+
// `0` for simple array
|
|
225
|
+
0;
|
|
226
|
+
const modulesNodes = isOptimizedArray ?
|
|
227
|
+
// The modules reside in the `concat()` function call arguments
|
|
228
|
+
node.arguments[0].elements :
|
|
229
|
+
node.elements;
|
|
217
230
|
|
|
218
231
|
return _.transform(modulesNodes, (result, moduleNode, i) => {
|
|
219
232
|
if (!moduleNode) return;
|
|
220
|
-
|
|
221
|
-
result[i] = getModuleLocation(moduleNode);
|
|
233
|
+
result[i + minId] = getModuleLocation(moduleNode);
|
|
222
234
|
}, {});
|
|
223
235
|
}
|
|
224
236
|
|
|
225
237
|
return {};
|
|
226
238
|
}
|
|
227
239
|
|
|
228
|
-
function getModulesLocationFromArrayConcat(arg) {
|
|
229
|
-
// arg(CallExpression) =
|
|
230
|
-
// Array([minId]).concat([<minId module>, <minId+1 module>, ...])
|
|
231
|
-
//
|
|
232
|
-
// Get the [minId] value from the Array() call first argument literal value
|
|
233
|
-
const minId = arg.callee.object.arguments[0].value;
|
|
234
|
-
// The modules reside in the `concat()` function call arguments
|
|
235
|
-
const modulesNodes = arg.arguments[0].elements;
|
|
236
|
-
|
|
237
|
-
return _.transform(modulesNodes, (result, moduleNode, i) => {
|
|
238
|
-
if (!moduleNode) return;
|
|
239
|
-
|
|
240
|
-
result[i + minId] = getModuleLocation(moduleNode);
|
|
241
|
-
}, {});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
240
|
function getModuleLocation(node) {
|
|
245
|
-
return
|
|
241
|
+
return {
|
|
242
|
+
start: node.start,
|
|
243
|
+
end: node.end
|
|
244
|
+
};
|
|
246
245
|
}
|