UNPKG

3.2 kBJavaScriptView Raw
1'use strict';
2
3var fs = require('fs');
4var _ = require('lodash');
5var acorn = require('acorn');
6var walk = require('acorn/dist/walk');
7
8module.exports = {
9 getModuleSizesFromBundle: getModuleSizesFromBundle
10};
11
12function getModuleSizesFromBundle(bundlePath) {
13 var ast = acorn.parse(fs.readFileSync(bundlePath, 'utf8'), {
14 sourceType: 'script'
15 });
16
17 var walkState = {
18 sizes: null
19 };
20
21 walk.recursive(ast, walkState, {
22 CallExpression: function CallExpression(node, state, c) {
23 if (state.sizes) return;
24
25 var args = node.arguments;
26
27 // Additional bundle without webpack loader
28 // Modules are stored in second argument:
29 // webpackJsonp([<chunks>], <modules>)
30 if (_.get(node, 'callee.name') === 'webpackJsonp') {
31 state.sizes = getModulesSizesFromFunctionArgument(args[1]);
32 return;
33 }
34
35 // Main bundle with webpack loader
36 // Modules are stored in first argument:
37 // (function (...) {...})(<modules>)
38 if (node.callee.type === 'FunctionExpression' && !node.callee.id && args.length === 1) {
39 var arg = args[0];
40
41
42 if (arg.type === 'CallExpression') {
43 // DedupePlugin and maybe some others wrap modules in additional self-invoking function expression.
44 // Walking into it.
45 return c(arg, state);
46 } else if (isArgumentContainsModulesList(arg)) {
47 state.sizes = getModulesSizesFromFunctionArgument(arg);
48 }
49 }
50 }
51 });
52
53 return walkState.sizes;
54}
55
56function isArgumentContainsModulesList(arg) {
57 if (arg.type === 'ObjectExpression') {
58 return _(arg.properties).map('value').every(isModuleWrapper);
59 }
60
61 if (arg.type === 'ArrayExpression') {
62 // Modules are contained in array.
63 // Array indexes are module ids
64 return _.every(arg.elements, function (elem) {
65 return (
66 // Some of array items may be skipped because there is no module with such id
67 !elem || isModuleWrapper(elem)
68 );
69 });
70 }
71
72 return false;
73}
74
75function isModuleWrapper(node) {
76 return (
77 // It's an anonymous function expression that wraps module
78 node.type === 'FunctionExpression' && !node.id ||
79 // If `DedupePlugin` is used it can be an ID of duplicated module
80 node.type === 'Literal' && (typeof node.value === 'number' || typeof node.value === 'string')
81 );
82}
83
84function getModulesSizesFromFunctionArgument(arg) {
85 if (arg.type === 'ObjectExpression') {
86 var modulesNodes = arg.properties;
87
88 return _.transform(modulesNodes, function (result, moduleNode) {
89 var moduleId = moduleNode.key.name || moduleNode.key.value;
90
91 result[moduleId] = getModuleSize(moduleNode.value);
92 }, {});
93 }
94
95 if (arg.type === 'ArrayExpression') {
96 var _modulesNodes = arg.elements;
97
98 return _.transform(_modulesNodes, function (result, moduleNode, i) {
99 if (!moduleNode) return;
100
101 result[i] = getModuleSize(moduleNode);
102 }, {});
103 }
104
105 return {};
106}
107
108function getModuleSize(node) {
109 if (node.type === 'FunctionExpression') {
110 return node.body.end - node.body.start;
111 }
112
113 if (node.type === 'Literal') {
114 return node.end - node.start;
115 }
116
117 // Fallback for unknown node types
118 return 0;
119}
\No newline at end of file