modules.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. const getModulePath = function (identifier) {
  2. return identifier.replace(/.*!/, '').replace(/\\/g, '/')
  3. }
  4. exports.filterModules = function (modules) {
  5. return modules.filter(module => module.name.indexOf('(webpack)') === -1)
  6. }
  7. exports.buildSortedModules = function (modules, sizeField) {
  8. let list = modules.slice()
  9. if (list.length) {
  10. list = list.map(module => {
  11. const size = module.size[sizeField]
  12. return {
  13. id: module.id,
  14. identifier: module.identifier,
  15. size
  16. }
  17. })
  18. list.sort((a, b) => b.size - a.size)
  19. }
  20. return list
  21. }
  22. exports.buildDepModules = function (modules) {
  23. const deps = new Map()
  24. for (const module of modules) {
  25. const path = getModulePath(module.identifier)
  26. const pathParts = path.split('/node_modules/')
  27. if (pathParts.length === 2) {
  28. let name = pathParts[1]
  29. if (name.charAt(0) === '@') {
  30. // Scoped package
  31. name = name.substr(0, name.indexOf('/', name.indexOf('/') + 1))
  32. } else {
  33. name = name.substr(0, name.indexOf('/'))
  34. }
  35. let dep = deps.get(name)
  36. if (!dep) {
  37. dep = {
  38. name,
  39. size: 0
  40. }
  41. deps.set(name, dep)
  42. }
  43. dep.size += module.size
  44. }
  45. }
  46. const list = Array.from(deps.values())
  47. list.sort((a, b) => b.size - a.size)
  48. if (list.length) {
  49. const max = list[0].size
  50. for (const dep of list) {
  51. dep.ratio = dep.size / max
  52. }
  53. }
  54. return list
  55. }
  56. /*
  57. {
  58. id: './node_modules',
  59. size: {
  60. stats: 1024,
  61. parsed: 0,
  62. gzip: 400
  63. }
  64. fullPath: '/node_modules',
  65. children: [
  66. {
  67. id: 'vuex',
  68. identifier: '...',
  69. size: {
  70. stats: 42,
  71. parsed: 0,
  72. gzip: 12
  73. },
  74. // Total size of previous children in list
  75. previousSize: {
  76. stats: 0,
  77. parsed: 0,
  78. gzip: 0
  79. },
  80. fullPath: '/node_modules/vuex',
  81. children: [
  82. ...
  83. ],
  84. },
  85. ...
  86. ]
  87. }
  88. */
  89. exports.buildModulesTrees = function (modules, sizeType) {
  90. const trees = {}
  91. for (const module of modules) {
  92. const path = getModulePath(module.identifier)
  93. if (path.indexOf('multi ') === 0) continue
  94. const parts = path.split('/')
  95. for (const treeId of module.chunks) {
  96. let subtree = trees[treeId]
  97. if (!subtree) {
  98. subtree = trees[treeId] = {
  99. id: treeId,
  100. size: {
  101. stats: 0,
  102. parsed: 0,
  103. gzip: 0
  104. },
  105. children: {}
  106. }
  107. }
  108. const fullPath = []
  109. for (let i = 0; i < parts.length; i++) {
  110. const part = parts[i]
  111. let child = subtree.children[part]
  112. if (!child) {
  113. fullPath.push(part)
  114. child = subtree.children[part] = {
  115. id: part,
  116. size: {
  117. stats: 0,
  118. parsed: 0,
  119. gzip: 0
  120. },
  121. fullPath: fullPath.join('/'),
  122. children: {}
  123. }
  124. }
  125. child.size.stats += module.size.stats
  126. child.size.parsed += module.size.parsed || 0
  127. child.size.gzip += module.size.gzip || 0
  128. // Leaf
  129. if (i === parts.length - 1) {
  130. child.identifier = module.identifier
  131. }
  132. subtree = child
  133. }
  134. }
  135. }
  136. for (const n in trees) {
  137. let tree = trees[n]
  138. let keys
  139. while ((keys = Object.keys(tree.children)).length !== 0 && keys.length === 1) {
  140. tree = tree.children[keys[0]]
  141. }
  142. walkTreeToSortChildren(tree, sizeType)
  143. trees[n] = tree
  144. }
  145. return trees
  146. }
  147. function walkTreeToSortChildren (tree, sizeType) {
  148. const size = {
  149. stats: 0,
  150. parsed: 0,
  151. gzip: 0
  152. }
  153. tree.children = Object.keys(tree.children).map(
  154. key => tree.children[key]
  155. ).filter(
  156. child => child.size.stats > tree.size.stats * 0.01 && child.size.stats > 1024
  157. ).sort((a, b) => b.size[sizeType] - a.size[sizeType])
  158. for (const child of tree.children) {
  159. child.previousSize = {
  160. stats: size.stats,
  161. parsed: size.parsed,
  162. gzip: size.gzip
  163. }
  164. size.stats += child.size.stats
  165. size.parsed += child.size.parsed
  166. size.gzip += child.size.gzip
  167. walkTreeToSortChildren(child, sizeType)
  168. }
  169. }