mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
imrpove nuxt-generate error report summary
This commit is contained in:
parent
061059beb4
commit
118d3fb8c2
@ -104,15 +104,8 @@ if (options.mode !== 'spa') {
|
|||||||
debug(`HTML Files generated in ${duration}s`)
|
debug(`HTML Files generated in ${duration}s`)
|
||||||
|
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
const report = errors.map(({ type, route, error }) => {
|
/* eslint-disable no-console */
|
||||||
/* istanbul ignore if */
|
console.log('\n' + errors.toString())
|
||||||
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:')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -86,17 +86,11 @@ nuxt.hook('generate:done', (generator, errors) => {
|
|||||||
const duration = Math.round((Date.now() - s) / 100) / 10
|
const duration = Math.round((Date.now() - s) / 100) / 10
|
||||||
|
|
||||||
debug(`HTML Files generated in ${duration}s`)
|
debug(`HTML Files generated in ${duration}s`)
|
||||||
|
console.log(errors.length)
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
const report = errors.map(({ type, route, error }) => {
|
/* eslint-disable no-console */
|
||||||
/* istanbul ignore if */
|
console.log('\n Generate errors summary:')
|
||||||
if (type === 'unhandled') {
|
console.log('\n' + errors.toString())
|
||||||
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:')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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 _ = require('lodash')
|
||||||
const { resolve, join, dirname, sep } = require('path')
|
const { resolve, join, dirname, sep } = require('path')
|
||||||
const { minify } = require('html-minifier')
|
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 {
|
module.exports = class Generator {
|
||||||
constructor(nuxt, builder) {
|
constructor(nuxt, builder) {
|
||||||
@ -14,7 +29,10 @@ module.exports = class Generator {
|
|||||||
this.staticRoutes = resolve(this.options.srcDir, 'static')
|
this.staticRoutes = resolve(this.options.srcDir, 'static')
|
||||||
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
|
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
|
||||||
this.distPath = resolve(this.options.rootDir, this.options.generate.dir)
|
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 } = {}) {
|
async generate({ build = true, init = true } = {}) {
|
||||||
@ -25,7 +43,7 @@ module.exports = class Generator {
|
|||||||
const errors = await this.generateRoutes(routes)
|
const errors = await this.generateRoutes(routes)
|
||||||
await this.afterGenerate()
|
await this.afterGenerate()
|
||||||
|
|
||||||
// done hook
|
// Done hook
|
||||||
await this.nuxt.callHook('generate:done', this, errors)
|
await this.nuxt.callHook('generate:done', this, errors)
|
||||||
|
|
||||||
return { errors }
|
return { errors }
|
||||||
@ -57,14 +75,20 @@ module.exports = class Generator {
|
|||||||
let generateRoutes = []
|
let generateRoutes = []
|
||||||
if (this.options.router.mode !== 'hash') {
|
if (this.options.router.mode !== 'hash') {
|
||||||
try {
|
try {
|
||||||
generateRoutes = await promisifyRoute(this.options.generate.routes || [], ...args)
|
generateRoutes = await promisifyRoute(
|
||||||
|
this.options.generate.routes || [],
|
||||||
|
...args
|
||||||
|
)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Could not resolve routes') // eslint-disable-line no-console
|
console.error('Could not resolve routes') // eslint-disable-line no-console
|
||||||
throw e // eslint-disable-line no-unreachable
|
throw e // eslint-disable-line no-unreachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate only index.html for router.mode = 'hash'
|
// 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)
|
routes = this.decorateWithPayloads(routes, generateRoutes)
|
||||||
|
|
||||||
// extendRoutes hook
|
// extendRoutes hook
|
||||||
@ -79,15 +103,43 @@ module.exports = class Generator {
|
|||||||
// Start generate process
|
// Start generate process
|
||||||
while (routes.length) {
|
while (routes.length) {
|
||||||
let n = 0
|
let n = 0
|
||||||
await Promise.all(routes.splice(0, this.options.generate.concurrency).map(async ({ route, payload }) => {
|
await Promise.all(
|
||||||
await waitFor(n++ * this.options.generate.interval)
|
routes
|
||||||
await this.generateRoute({ route, payload, errors })
|
.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
|
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() {
|
async afterGenerate() {
|
||||||
const indexPath = join(this.distPath, 'index.html')
|
const indexPath = join(this.distPath, 'index.html')
|
||||||
if (existsSync(indexPath)) {
|
if (existsSync(indexPath)) {
|
||||||
@ -138,14 +190,14 @@ module.exports = class Generator {
|
|||||||
decorateWithPayloads(routes, generateRoutes) {
|
decorateWithPayloads(routes, generateRoutes) {
|
||||||
let routeMap = {}
|
let routeMap = {}
|
||||||
// Fill routeMap for known routes
|
// Fill routeMap for known routes
|
||||||
routes.forEach((route) => {
|
routes.forEach(route => {
|
||||||
routeMap[route] = {
|
routeMap[route] = {
|
||||||
route,
|
route,
|
||||||
payload: null
|
payload: null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Fill routeMap with given generate.routes
|
// Fill routeMap with given generate.routes
|
||||||
generateRoutes.forEach((route) => {
|
generateRoutes.forEach(route => {
|
||||||
// route is either a string or like { route : '/my_route/1', payload: {} }
|
// route is either a string or like { route : '/my_route/1', payload: {} }
|
||||||
const path = _.isString(route) ? route : route.route
|
const path = _.isString(route) ? route : route.route
|
||||||
routeMap[path] = {
|
routeMap[path] = {
|
||||||
@ -161,7 +213,10 @@ module.exports = class Generator {
|
|||||||
const pageErrors = []
|
const pageErrors = []
|
||||||
|
|
||||||
try {
|
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
|
html = res.html
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
pageErrors.push({ type: 'handled', route, error: 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 })
|
pageErrors.push({ type: 'unhandled', route, error: err })
|
||||||
Array.prototype.push.apply(errors, pageErrors)
|
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
|
return false
|
||||||
}
|
}
|
||||||
@ -180,7 +238,9 @@ module.exports = class Generator {
|
|||||||
try {
|
try {
|
||||||
html = minify(html, this.options.generate.minify)
|
html = minify(html, this.options.generate.minify)
|
||||||
} catch (err) /* istanbul ignore next */ {
|
} 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 })
|
pageErrors.push({ type: 'unhandled', route, error: minifyErr })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +265,11 @@ module.exports = class Generator {
|
|||||||
await mkdirp(dirname(page.path))
|
await mkdirp(dirname(page.path))
|
||||||
await writeFile(page.path, page.html, 'utf8')
|
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) {
|
if (pageErrors.length) {
|
||||||
Array.prototype.push.apply(errors, pageErrors)
|
Array.prototype.push.apply(errors, pageErrors)
|
||||||
|
@ -3,26 +3,28 @@ const _ = require('lodash')
|
|||||||
const PrettyError = require('pretty-error')
|
const PrettyError = require('pretty-error')
|
||||||
const Chalk = require('chalk')
|
const Chalk = require('chalk')
|
||||||
|
|
||||||
const pe = new PrettyError()
|
exports.pe = new PrettyError()
|
||||||
|
|
||||||
exports.printWarn = function (msg, from) {
|
exports.printWarn = function (msg, from) {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
const fromStr = from ? Chalk.yellow(` ${from}\n\n`) : ' '
|
const fromStr = from ? Chalk.yellow(` ${from}\n\n`) : ' '
|
||||||
|
|
||||||
console.error('\n' + Chalk.bgYellow.black(' WARN ') + fromStr + msg + '\n')
|
console.error('\n' + Chalk.bgYellow.black(' WARN ') + fromStr + msg + '\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.printError = function (_error, from) {
|
exports.renderError = function (_error, from) {
|
||||||
/* eslint-disable no-console */
|
const errStr = exports.pe.render(_error)
|
||||||
const errStr = pe.render(_error)
|
|
||||||
const fromStr = from ? Chalk.red(` ${from}`) : ''
|
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')
|
exports.printError = function () {
|
||||||
console.error(errStr + '\n')
|
/* eslint-disable no-console */
|
||||||
|
console.error(exports.renderError(...arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.fatalError = function () {
|
exports.fatalError = function () {
|
||||||
exports.printError(...arguments)
|
/* eslint-disable no-console */
|
||||||
|
console.error(exports.renderError(...arguments))
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +93,6 @@ test.serial('bin/nuxt-generate', async t => {
|
|||||||
t.true(stderr.includes('Destination folder cleaned'))
|
t.true(stderr.includes('Destination folder cleaned'))
|
||||||
t.true(stderr.includes('Static & build files copied'))
|
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 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'))
|
t.true(stderr.includes('Generate done'))
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user