UNPKG

4.25 kBJavaScriptView Raw
1const fs = require('fs')
2const path = require('path')
3const filesize = require('filesize')
4const chalk = require('chalk')
5const stripAnsi = require('strip-ansi')
6const gzipSize = require('gzip-size').sync
7const { groupBy } = require('lodash')
8
9// assetsData:{<Object>: <Array>}
10function reporter(assetsData, maxBundleGzipSize, maxChunkGzipSize) {
11 // https://raw.githubusercontent.com/webpack/analyse/master/app/pages/upload/example.json
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 // __format 属性为组件资源特有
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 // path.normalize 跨平台格式化路径
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
146module.exports = reporter