UNPKG

6.09 kBJavaScriptView Raw
1let {
2 bgGreen,
3 yellow,
4 bgRed,
5 black,
6 green,
7 bold,
8 gray,
9 red
10} = require('colorette')
11let { join } = require('path')
12let bytes = require('bytes-iec')
13
14function createJsonReporter(process) {
15 function print(data) {
16 process.stdout.write(JSON.stringify(data, null, 2) + '\n')
17 }
18
19 return {
20 error(err) {
21 print({ error: err.stack })
22 },
23
24 results(plugins, config) {
25 print(
26 config.checks.map(i => {
27 let result = { name: i.name }
28 if (typeof i.passed !== 'undefined') result.passed = i.passed
29 if (typeof i.size !== 'undefined') result.size = i.size
30 if (typeof i.runTime !== 'undefined') result.running = i.runTime
31 if (typeof i.loadTime !== 'undefined') result.loading = i.loadTime
32 return result
33 })
34 )
35 }
36 }
37}
38
39function getFixText(prefix, config) {
40 if (config.configPath) {
41 if (config.configPath.endsWith('package.json')) {
42 prefix += ` in ${bold('"size-limit"')} section of `
43 } else {
44 prefix += ' at '
45 }
46 prefix += bold(config.configPath)
47 }
48
49 return prefix
50}
51
52function createHumanReporter(process, isSilentMode = false) {
53 function print(...lines) {
54 process.stdout.write(' ' + lines.join('\n ') + '\n')
55 }
56
57 function formatBytes(size) {
58 return bytes.format(size, { unitSeparator: ' ' })
59 }
60
61 function formatTime(seconds) {
62 if (seconds >= 1) {
63 return Math.ceil(seconds * 10) / 10 + ' s'
64 } else {
65 return Math.ceil(seconds * 1000) + ' ms'
66 }
67 }
68
69 return {
70 error(err) {
71 if (err.name === 'SizeLimitError') {
72 let msg = err.message
73 .split('. ')
74 .map(i => i.replace(/\*([^*]+)\*/g, yellow('$1')))
75 .join('.\n ')
76 process.stderr.write(`${bgRed(black(' ERROR '))} ${red(msg)}\n`)
77 if (err.example) {
78 process.stderr.write(
79 '\n' +
80 err.example
81 .replace(/("[^"]+"):/g, green('$1') + ':')
82 .replace(/: ("[^"]+")/g, ': ' + yellow('$1'))
83 )
84 }
85 } else {
86 process.stderr.write(`${bgRed(black(' ERROR '))} ${red(err.stack)}\n`)
87 }
88 },
89
90 results(plugins, config) {
91 print('')
92 for (let check of config.checks) {
93 if (
94 (check.passed && config.hidePassed && !isSilentMode) ||
95 (isSilentMode && check.passed !== false)
96 ) {
97 continue
98 }
99
100 let unlimited = typeof check.passed === 'undefined'
101 let rows = []
102
103 if (config.checks.length > 1) {
104 print(bold(check.name))
105 }
106
107 if (check.missed) {
108 print(red(`Size Limit can’t find files at ${check.path}`))
109 continue
110 }
111
112 let sizeNote
113 if (check.config) {
114 sizeNote = 'with given webpack configuration'
115 } else if (plugins.has('webpack') && check.brotli === true) {
116 sizeNote = 'with all dependencies, minified and brotli'
117 } else if (plugins.has('webpack') && check.gzip === false) {
118 sizeNote = 'with all dependencies and minified'
119 } else if (plugins.has('webpack')) {
120 sizeNote = 'with all dependencies, minified and gzipped'
121 } else if (plugins.has('file') && check.gzip !== false) {
122 sizeNote = 'gzipped'
123 }
124 let sizeString = formatBytes(check.size)
125
126 if (typeof check.timeLimit !== 'undefined') {
127 if (check.passed === false) {
128 print(red('Total time limit has exceeded'))
129 }
130 rows.push(['Time limit', formatTime(check.timeLimit)])
131 }
132 if (typeof check.sizeLimit !== 'undefined') {
133 let sizeLimitString = formatBytes(check.sizeLimit)
134 if (check.passed === false) {
135 if (sizeLimitString === sizeString) {
136 sizeLimitString = check.sizeLimit + ' B'
137 sizeString = check.size + ' B'
138 }
139 let diff = formatBytes(check.size - check.sizeLimit)
140 print(red(`Package size limit has exceeded by ${diff}`))
141 } else if (check.highlightLess && check.size < check.sizeLimit) {
142 let diff = formatBytes(check.sizeLimit - check.size)
143 print(bgGreen(black(`Package size is ${diff} less than limit`)))
144 }
145 rows.push(['Size limit', sizeLimitString])
146 }
147
148 if (typeof check.size !== 'undefined') {
149 rows.push(['Size', sizeString, sizeNote])
150 }
151 if (typeof check.loadTime !== 'undefined') {
152 rows.push(['Loading time', formatTime(check.loadTime), 'on slow 3G'])
153 }
154 if (typeof check.runTime !== 'undefined') {
155 rows.push(
156 ['Running time', formatTime(check.runTime), 'on Snapdragon 410'],
157 ['Total time', formatTime(check.time)]
158 )
159 }
160
161 let max0 = Math.max(...rows.map(row => row[0].length))
162 let max1 = Math.max(...rows.map(row => row[1].length))
163
164 for (let [name, value, note] of rows) {
165 let str = (name + ':').padEnd(max0 + 1) + ' '
166 if (note) value = value.padEnd(max1)
167 value = bold(value)
168 if (unlimited || name.includes('Limit')) {
169 str += value
170 } else if (check.passed) {
171 str += green(value)
172 } else {
173 str += red(value)
174 }
175 if (note) {
176 str += ' ' + gray(note)
177 }
178 print(str)
179 }
180 print('')
181 }
182
183 if (config.failed) {
184 let fix = getFixText('Try to reduce size or increase limit', config)
185 print(yellow(fix))
186 }
187
188 if (plugins.has('webpack') && config.saveBundle) {
189 let statsFilepath = join(config.saveBundle, 'stats.json')
190 print(`Webpack Stats file was saved to ${statsFilepath}`)
191 print('You can review it using https://webpack.github.io/analyse')
192 }
193 }
194 }
195}
196
197module.exports = (process, isJSON, isSilentMode) => {
198 if (isJSON) {
199 return createJsonReporter(process)
200 } else {
201 return createHumanReporter(process, isSilentMode)
202 }
203}