-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
126 lines (105 loc) · 2.95 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
'use strict'
var unpack = require('browser-unpack')
function breakdownCore(bundleSrc) {
var deps = unpack(bundleSrc)
// Build dependency graph
var info = {} // node info
var graph = {} // directed graph where each node is a module
var nodes = {} // list of all modules we can work on
deps.forEach(function(row) {
// Store a reference to the package.
info[row.id] = row
// Build graph
Object.keys(row.deps).forEach(function(key) {
var depId = row.deps[key]
addGraphEdge(graph, row.id, depId)
})
// Entry points
if (row.entry) {
addGraphEdge(graph, 'entry:', row.id)
}
nodes[row.id] = true
})
// dummy info for `entry:` node
info['entry:'] = { id: 'entry:', source: '' }
// Walk through the dependency graph, ignoring circular references,
// and return a flat array
var walk = function walk(moduleId, path) {
// Defaults
path = Object.assign({}, path || {})
// Mark node as visited
delete nodes[moduleId]
// Detect circular dep
if (path[moduleId]) {
return {
id: moduleId,
circular: true,
// having a circular dep won't add anything to the total byte size
size: 0
}
}
path[moduleId] = true
// Current module info
var currentModuleInfo = {
id: moduleId,
size: Buffer.byteLength(info[moduleId].source)
}
// Find the module's dependencies
var depKeys = Object.keys(graph[moduleId] || {})
var nodeDeps = depKeys.map(function(dep) {
return walk(dep, Object.assign({}, path))
})
currentModuleInfo.deps = nodeDeps
return currentModuleInfo
}
// Walk entry nodes
var allEntry = walk('entry:')
// Walk isolated nodes, if any remain
var isolatedNodeKeys = Object.keys(nodes)
var allIsolated = isolatedNodeKeys.map(function(moduleId) {
return walk(moduleId, {}, 1)
})
var graphObject = {
id: '',
size: 0,
deps: allEntry.deps.concat(allIsolated),
isolatedNodes: isolatedNodeKeys
}
// Invoke assign total size to every node.
function visitTotalSize(node) {
node.totalSize = totalSize(node)
node.deps && node.deps.forEach(function(node) {
visitTotalSize(node)
})
}
// Get the total size of the node. This excludes repeated modules.
function totalSize(node, visited) {
visited = visited || {}
if (visited[node.id]) {
return 0
}
else {
visited[node.id] = true
}
var deps = node.deps || []
return node.size +
sum(deps.map(function(dep) { return totalSize(dep, visited) }))
}
visitTotalSize(graphObject)
return {
result: graphObject,
info: info,
graph: graph
}
}
function sum(arr) {
return arr.reduce(function(a, b) { return a + b }, 0)
}
function addGraphEdge(graph, node1, node2) {
graph[node1] = graph[node1] || {}
graph[node1][node2] = true
}
module.exports = function breakdown(bundleSrc) {
return breakdownCore(bundleSrc).result
}
module.exports.core = breakdownCore