1 | const fs = require('fs')
|
2 | const path = require('path')
|
3 | const filesize = require('filesize')
|
4 | const chalk = require('chalk')
|
5 | const stripAnsi = require('strip-ansi')
|
6 | const gzipSize = require('gzip-size').sync
|
7 | const { groupBy } = require('lodash')
|
8 |
|
9 |
|
10 | function reporter(assetsData, maxBundleGzipSize, maxChunkGzipSize) {
|
11 |
|
12 | let labelLengthArr = []
|
13 | let suggestBundleSplitting = false
|
14 | const isJS = val => /\.js$/.test(val)
|
15 | const isCSS = val => /\.css$/.test(val)
|
16 | const isMinJS = val => /\.min\.js$/.test(val)
|
17 |
|
18 | function mainAssetInfo(info, type) {
|
19 |
|
20 | const isMainBundle =
|
21 | type === 'page' && info.name.indexOf(`${info.folder}.`) === 0
|
22 | const maxRecommendedSize = isMainBundle
|
23 | ? maxBundleGzipSize
|
24 | : maxChunkGzipSize
|
25 | const isLarge = maxRecommendedSize && info.size > maxRecommendedSize
|
26 |
|
27 | if (isLarge && isJS(info.name)) {
|
28 | suggestBundleSplitting = true
|
29 | }
|
30 |
|
31 | assetInfo(info, isLarge)
|
32 | }
|
33 |
|
34 | function assetInfo(info, isLarge = false) {
|
35 | let sizeLabel = info.sizeLabel
|
36 | const sizeLength = stripAnsi(sizeLabel).length
|
37 | const longestSizeLabelLength = Math.max.apply(null, labelLengthArr)
|
38 |
|
39 | let assetPath =
|
40 | chalk.dim(info.folder + path.sep) + chalk.cyan(path.normalize(info.name))
|
41 |
|
42 | if (isJS(info.name)) {
|
43 |
|
44 | assetPath += info.format ? chalk.cyan(` (${info.format})`) : ''
|
45 | }
|
46 |
|
47 | if (sizeLength < longestSizeLabelLength) {
|
48 | const rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength)
|
49 | sizeLabel += rightPadding
|
50 | }
|
51 |
|
52 | console.log(
|
53 | ` ${isLarge ? chalk.yellow(sizeLabel) : sizeLabel} ${assetPath}`
|
54 | )
|
55 | }
|
56 |
|
57 | function parseAssets(assets) {
|
58 | const seenNames = new Map()
|
59 | const assetsInfo = groupBy(
|
60 | assets
|
61 | .filter(
|
62 | a => (seenNames.has(a.name) ? false : seenNames.set(a.name, true))
|
63 | )
|
64 | .map(asset => {
|
65 | const buildDir = assets['__dist'] || asset['__dist']
|
66 | const fileContents = fs.readFileSync(path.join(buildDir, asset.name))
|
67 | const size = gzipSize(fileContents)
|
68 | const sizeLabel = filesize(size)
|
69 |
|
70 | labelLengthArr.push(stripAnsi(sizeLabel).length)
|
71 |
|
72 | return {
|
73 | folder: path.basename(buildDir),
|
74 | name: asset.name,
|
75 | format: asset['__format'],
|
76 | size: size,
|
77 | sizeLabel
|
78 | }
|
79 | }),
|
80 | asset => (/\.(js|css)$/.test(asset.name) ? 'main' : 'other')
|
81 | )
|
82 |
|
83 | assetsInfo.main = assetsInfo.main || []
|
84 | assetsInfo.other = assetsInfo.other || []
|
85 |
|
86 | return assetsInfo
|
87 | }
|
88 |
|
89 | const assetList = Object.keys(assetsData).map(type => {
|
90 | let assets = assetsData[type]
|
91 | let output
|
92 |
|
93 | if (type === 'lib') {
|
94 | assets = [].concat.apply([], assets)
|
95 | output = [parseAssets(assets)]
|
96 | } else {
|
97 | output = assets.map(a => parseAssets(a))
|
98 | }
|
99 |
|
100 | return {
|
101 | type,
|
102 | output
|
103 | }
|
104 | })
|
105 |
|
106 | assetList.forEach(item => {
|
107 | if (item.type === 'demo' && item.output.length) console.log('\nDEMO:')
|
108 |
|
109 | item.output.forEach(assetsInfo => {
|
110 | if (item.type === 'demo') console.log()
|
111 |
|
112 | assetsInfo.main
|
113 | .sort((a, b) => {
|
114 | if (isJS(a.name) && isCSS(b.name)) return -1
|
115 | if (isCSS(a.name) && isJS(b.name)) return 1
|
116 | if (isMinJS(a.name) && !isMinJS(b.name)) return -1
|
117 | if (!isMinJS(a.name) && isMinJS(b.name)) return 1
|
118 | return b.size - a.size
|
119 | })
|
120 | .forEach(info => mainAssetInfo(info, item.type))
|
121 |
|
122 | assetsInfo.other
|
123 | .sort((a, b) => b.size - a.size)
|
124 | .forEach(info => assetInfo(info))
|
125 | })
|
126 | })
|
127 |
|
128 | if (suggestBundleSplitting) {
|
129 | console.log()
|
130 | console.log(
|
131 | chalk.yellow('The bundle size is significantly larger than recommended.')
|
132 | )
|
133 | console.log(
|
134 | chalk.yellow(
|
135 | 'Consider reducing it with code splitting: https://goo.gl/9VhYWB'
|
136 | )
|
137 | )
|
138 | console.log(
|
139 | chalk.yellow(
|
140 | 'You can also analyze the project dependencies: https://goo.gl/LeUzfb'
|
141 | )
|
142 | )
|
143 | }
|
144 | }
|
145 |
|
146 | module.exports = reporter
|