imrpove nuxt-generate error report summary

This commit is contained in:
Pooya Parsa 2018-01-11 21:50:35 +03:30
parent 061059beb4
commit 118d3fb8c2
5 changed files with 97 additions and 44 deletions

View File

@ -104,15 +104,8 @@ if (options.mode !== 'spa') {
debug(`HTML Files generated in ${duration}s`)
if (errors.length) {
const report = errors.map(({ type, route, error }) => {
/* istanbul ignore if */
if (type === 'unhandled') {
return `Route: '${route}'\n${error.stack}`
} else {
return `Route: '${route}' thrown an error: \n` + JSON.stringify(error)
}
})
Utils.printError(report.join('\n\n'), 'Generate errors summary:')
/* eslint-disable no-console */
console.log('\n' + errors.toString())
}
})

View File

@ -86,17 +86,11 @@ nuxt.hook('generate:done', (generator, errors) => {
const duration = Math.round((Date.now() - s) / 100) / 10
debug(`HTML Files generated in ${duration}s`)
console.log(errors.length)
if (errors.length) {
const report = errors.map(({ type, route, error }) => {
/* istanbul ignore if */
if (type === 'unhandled') {
return `Route: '${route}'\n${error.stack}`
} else {
return `Route: '${route}' thrown an error: \n` + JSON.stringify(error)
}
})
Utils.printError(report.join('\n\n'), 'Generate errors summary:')
/* eslint-disable no-console */
console.log('\n Generate errors summary:')
console.log('\n' + errors.toString())
}
})

View File

@ -1,8 +1,23 @@
const { copy, remove, writeFile, mkdirp, removeSync, existsSync } = require('fs-extra')
const {
copy,
remove,
writeFile,
mkdirp,
removeSync,
existsSync
} = require('fs-extra')
const _ = require('lodash')
const { resolve, join, dirname, sep } = require('path')
const { minify } = require('html-minifier')
const { isUrl, promisifyRoute, waitFor, flatRoutes } = require('../common/utils')
const Chalk = require('chalk')
const {
isUrl,
promisifyRoute,
waitFor,
flatRoutes,
pe
} = require('../common/utils')
module.exports = class Generator {
constructor(nuxt, builder) {
@ -14,7 +29,10 @@ module.exports = class Generator {
this.staticRoutes = resolve(this.options.srcDir, 'static')
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
this.distPath = resolve(this.options.rootDir, this.options.generate.dir)
this.distNuxtPath = join(this.distPath, (isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath))
this.distNuxtPath = join(
this.distPath,
isUrl(this.options.build.publicPath) ? '' : this.options.build.publicPath
)
}
async generate({ build = true, init = true } = {}) {
@ -25,7 +43,7 @@ module.exports = class Generator {
const errors = await this.generateRoutes(routes)
await this.afterGenerate()
// done hook
// Done hook
await this.nuxt.callHook('generate:done', this, errors)
return { errors }
@ -57,14 +75,20 @@ module.exports = class Generator {
let generateRoutes = []
if (this.options.router.mode !== 'hash') {
try {
generateRoutes = await promisifyRoute(this.options.generate.routes || [], ...args)
generateRoutes = await promisifyRoute(
this.options.generate.routes || [],
...args
)
} catch (e) {
console.error('Could not resolve routes') // eslint-disable-line no-console
throw e // eslint-disable-line no-unreachable
}
}
// Generate only index.html for router.mode = 'hash'
let routes = (this.options.router.mode === 'hash') ? ['/'] : flatRoutes(this.options.router.routes)
let routes =
this.options.router.mode === 'hash'
? ['/']
: flatRoutes(this.options.router.routes)
routes = this.decorateWithPayloads(routes, generateRoutes)
// extendRoutes hook
@ -79,15 +103,43 @@ module.exports = class Generator {
// Start generate process
while (routes.length) {
let n = 0
await Promise.all(routes.splice(0, this.options.generate.concurrency).map(async ({ route, payload }) => {
await waitFor(n++ * this.options.generate.interval)
await this.generateRoute({ route, payload, errors })
}))
await Promise.all(
routes
.splice(0, this.options.generate.concurrency)
.map(async ({ route, payload }) => {
await waitFor(n++ * this.options.generate.interval)
await this.generateRoute({ route, payload, errors })
})
)
}
// Improve string representation for errors
errors.toString = () => this._formatErrors(errors)
return errors
}
_formatErrors(errors) {
return errors
.map(({ type, route, error }) => {
const isHandled = type === 'handled'
const bgColor = isHandled ? 'bgYellow' : 'bgRed'
const color = isHandled ? 'yellow' : 'red'
let line =
Chalk.black[bgColor](' ROUTE ') + Chalk[color](` ${route}\n\n`)
if (isHandled) {
line += Chalk.grey(JSON.stringify(error, undefined, 2) + '\n')
} else {
line += Chalk.grey(pe.render(error))
}
return line
})
.join('\n')
}
async afterGenerate() {
const indexPath = join(this.distPath, 'index.html')
if (existsSync(indexPath)) {
@ -138,14 +190,14 @@ module.exports = class Generator {
decorateWithPayloads(routes, generateRoutes) {
let routeMap = {}
// Fill routeMap for known routes
routes.forEach((route) => {
routes.forEach(route => {
routeMap[route] = {
route,
payload: null
}
})
// Fill routeMap with given generate.routes
generateRoutes.forEach((route) => {
generateRoutes.forEach(route => {
// route is either a string or like { route : '/my_route/1', payload: {} }
const path = _.isString(route) ? route : route.route
routeMap[path] = {
@ -161,7 +213,10 @@ module.exports = class Generator {
const pageErrors = []
try {
const res = await this.nuxt.renderer.renderRoute(route, { _generate: true, payload })
const res = await this.nuxt.renderer.renderRoute(route, {
_generate: true,
payload
})
html = res.html
if (res.error) {
pageErrors.push({ type: 'handled', route, error: res.error })
@ -171,7 +226,10 @@ module.exports = class Generator {
pageErrors.push({ type: 'unhandled', route, error: err })
Array.prototype.push.apply(errors, pageErrors)
await this.nuxt.callHook('generate:routeFailed', { route, errors: pageErrors })
await this.nuxt.callHook('generate:routeFailed', {
route,
errors: pageErrors
})
return false
}
@ -180,7 +238,9 @@ module.exports = class Generator {
try {
html = minify(html, this.options.generate.minify)
} catch (err) /* istanbul ignore next */ {
const minifyErr = new Error(`HTML minification failed. Make sure the route generates valid HTML. Failed HTML:\n ${html}`)
const minifyErr = new Error(
`HTML minification failed. Make sure the route generates valid HTML. Failed HTML:\n ${html}`
)
pageErrors.push({ type: 'unhandled', route, error: minifyErr })
}
}
@ -205,7 +265,11 @@ module.exports = class Generator {
await mkdirp(dirname(page.path))
await writeFile(page.path, page.html, 'utf8')
await this.nuxt.callHook('generate:routeCreated', { route, path: page.path, errors: pageErrors })
await this.nuxt.callHook('generate:routeCreated', {
route,
path: page.path,
errors: pageErrors
})
if (pageErrors.length) {
Array.prototype.push.apply(errors, pageErrors)

View File

@ -3,26 +3,28 @@ const _ = require('lodash')
const PrettyError = require('pretty-error')
const Chalk = require('chalk')
const pe = new PrettyError()
exports.pe = new PrettyError()
exports.printWarn = function (msg, from) {
/* eslint-disable no-console */
const fromStr = from ? Chalk.yellow(` ${from}\n\n`) : ' '
console.error('\n' + Chalk.bgYellow.black(' WARN ') + fromStr + msg + '\n')
}
exports.printError = function (_error, from) {
/* eslint-disable no-console */
const errStr = pe.render(_error)
exports.renderError = function (_error, from) {
const errStr = exports.pe.render(_error)
const fromStr = from ? Chalk.red(` ${from}`) : ''
return '\n' + Chalk.bgRed.black(' ERROR ') + fromStr + '\n' + errStr + '\n'
}
console.error('\n' + Chalk.bgRed.black(' ERROR ') + fromStr + '\n')
console.error(errStr + '\n')
exports.printError = function () {
/* eslint-disable no-console */
console.error(exports.renderError(...arguments))
}
exports.fatalError = function () {
exports.printError(...arguments)
/* eslint-disable no-console */
console.error(exports.renderError(...arguments))
process.exit(1)
}

View File

@ -93,6 +93,6 @@ test.serial('bin/nuxt-generate', async t => {
t.true(stderr.includes('Destination folder cleaned'))
t.true(stderr.includes('Static & build files copied'))
t.true(stderr.includes(`Generate file: ${sep}users${sep}1${sep}index.html`))
t.true(stderr.includes('Generate errors summary:'))
t.true(stdout.includes('Generate errors summary:'))
t.true(stderr.includes('Generate done'))
})