1 | const chalk = require('chalk')
|
2 | const highlight = require('highlight-es')
|
3 | const _ = require('lodash')
|
4 | const tildify = require('tildify')
|
5 | const logger = require('../../logger')
|
6 |
|
7 | function groupErrorsByType(errors) {
|
8 | return errors.reduce((res, error) => {
|
9 | res[error.type] = res[error.type] || []
|
10 | res[error.type].push(error)
|
11 | return res
|
12 | }, {})
|
13 | }
|
14 |
|
15 | function moduleNotFound(errors) {
|
16 | if (!errors) return false
|
17 |
|
18 | let res = []
|
19 | errors = _.uniqBy(errors, 'payload')
|
20 |
|
21 | res.push(`${chalk.red('module not found:')}\n`)
|
22 | res = res.concat(errors.map(error => {
|
23 | const requestedBy = (error.error.origin && error.error.origin.resource) ? chalk.dim(`: imported at ${chalk.italic(tildify(error.error.origin.resource))}`) : ''
|
24 | return `- ${chalk.yellow(error.payload)}${requestedBy}`
|
25 | }))
|
26 |
|
27 | return res.join('\n')
|
28 | }
|
29 |
|
30 | function uglifyError(errors) {
|
31 | if (!errors) return false
|
32 |
|
33 | const error = errors[0]
|
34 |
|
35 | const res = []
|
36 | const { message } = error.error
|
37 |
|
38 | if (error.kind === 'module') {
|
39 | res.push(`${chalk.red('UglifyJS error')}: unexpected ES6+ code in module "${error.payload}", full error message:\n`)
|
40 | res.push(chalk.dim(message))
|
41 | res.push('')
|
42 | res.push(
|
43 | logger.tip(chalk.bold(`To fix this, try adding "${error.payload}" to "transformModules" option, eg:`), false)
|
44 | )
|
45 | res.push('')
|
46 | res.push(highlight(`// poi.config.js
|
47 | module.exports = {
|
48 | transformModules: ['${error.payload}'],
|
49 | // ...other config
|
50 | }`))
|
51 | } else if (error.kind === 'file') {
|
52 | res.push(`${chalk.red('UglifyJS error')}: unexpected ES6+ code in file "${error.payload}", full error message:\n`)
|
53 | res.push(chalk.dim(message))
|
54 | res.push('')
|
55 | res.push(
|
56 | logger.tip(chalk.bold(`To fix this, please configure .babelrc to compile your app code down to ES5 or use poi-preset-babel-minify if you want to preserve ES6+ code in final bundle.`), false)
|
57 | )
|
58 | }
|
59 |
|
60 | return res.join('\n')
|
61 | }
|
62 |
|
63 | function vueVersionMismatch(errors) {
|
64 | if (!errors) return
|
65 |
|
66 | const res = []
|
67 | const error = errors[0]
|
68 | let message = error.error.message.replace(/This may cause things to work incorrectly[\s\S]+/, '')
|
69 | message += 'Make sure to install both packages with the same version in your project.\nOtherwise webpack will use transitive dependencies from Poi.'
|
70 | res.push(chalk.red(message))
|
71 |
|
72 | return res.join('\n')
|
73 | }
|
74 |
|
75 | function unknownError(errors) {
|
76 | if (!errors) return false
|
77 |
|
78 | const res = errors.map(error => {
|
79 | let msg = ''
|
80 | if (error.error.origin && error.error.origin.resource) {
|
81 | msg += chalk.red(`Error in ${chalk.italic(tildify(error.error.origin.resource))}`)
|
82 | msg += '\n\n'
|
83 | }
|
84 | msg += error.error.message.replace(/Module build failed:\s+/, '').trim()
|
85 | return msg
|
86 | })
|
87 |
|
88 | return res.join('\n')
|
89 | }
|
90 |
|
91 | function babelPluginNotFound(errors) {
|
92 | if (!errors) return false
|
93 |
|
94 | const res = []
|
95 |
|
96 | const error = errors[0]
|
97 | res.push(`${chalk.red('missing babel plugin:')} following babel plugin is referenced in ${chalk.italic(tildify(error.payload.location))}\nbut not installed in current project:\n`)
|
98 | res.push(`- ${error.payload.name.replace(/^(babel-plugin-)?/, 'babel-plugin-')}`)
|
99 |
|
100 | return res.join('\n')
|
101 | }
|
102 |
|
103 | function babelPresetNotFound(errors) {
|
104 | if (!errors) return false
|
105 |
|
106 | const res = []
|
107 | const error = errors[0]
|
108 | res.push(`${chalk.red('missing babel preset:')} following babel preset is not found in ${chalk.italic(tildify(error.payload.location))}:\n`)
|
109 | res.push(`- ${error.payload.name.replace(/^(babel-preset-)?/, 'babel-preset-')}`)
|
110 |
|
111 | return res.join('\n')
|
112 | }
|
113 |
|
114 | function eslintError(errors) {
|
115 | if (!errors) return false
|
116 |
|
117 | const res = []
|
118 | res.push(`${chalk.red('code quality problems:')}`)
|
119 | const error = errors[0]
|
120 | res.push(error.error.message)
|
121 | res.push(
|
122 | logger.tip('You may use special comments to disable some warnings.', false)
|
123 | )
|
124 | res.push(chalk.dim(`
|
125 | - Use ${chalk.yellow('// eslint-disable-next-line')} to ignore the next line.
|
126 | - Use ${chalk.yellow('/* eslint-disable */')} to ignore all warnings in a file.`))
|
127 |
|
128 | return res.join('\n')
|
129 | }
|
130 |
|
131 | function run(results) {
|
132 | console.log(results.filter(result => result).join('\n\n'))
|
133 | console.log()
|
134 | }
|
135 |
|
136 | module.exports = errors => {
|
137 | errors = groupErrorsByType(errors)
|
138 | run([
|
139 | moduleNotFound(errors['module-not-found']),
|
140 | uglifyError(errors['uglify-error']),
|
141 | vueVersionMismatch(errors['vue-version-mismatch']),
|
142 | babelPluginNotFound(errors['babel-plugin-not-found']),
|
143 | babelPresetNotFound(errors['babel-preset-not-found']),
|
144 | eslintError(errors['eslint-error']),
|
145 | unknownError(errors.unknown)
|
146 | ])
|
147 | }
|