UNPKG

browserify-breakdown

Version:

break down and analyze browserify/browser-pack bundles

127 lines (105 loc) 3.15 kB
'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