1 | let {
|
2 | bgGreen,
|
3 | yellow,
|
4 | bgRed,
|
5 | black,
|
6 | green,
|
7 | bold,
|
8 | gray,
|
9 | red
|
10 | } = require('colorette')
|
11 | let { join } = require('path')
|
12 | let bytes = require('bytes-iec')
|
13 |
|
14 | function 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 |
|
39 | function 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 |
|
52 | function 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 |
|
197 | module.exports = (process, isJSON, isSilentMode) => {
|
198 | if (isJSON) {
|
199 | return createJsonReporter(process)
|
200 | } else {
|
201 | return createHumanReporter(process, isSilentMode)
|
202 | }
|
203 | }
|