Skip to content

Commit

Permalink
Improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
bcomnes committed Feb 13, 2022
1 parent fbcf29c commit 92f76e0
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 88 deletions.
137 changes: 78 additions & 59 deletions bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import desm from 'desm'
import process from 'process'
import tree from 'pretty-tree'
import cleanDeep from 'clean-deep'
import { inspect } from 'util'

import { Siteup } from './index.js'

Expand Down Expand Up @@ -101,77 +102,95 @@ async function run () {

if (!argv.watch) {
// TODO: handle warning and error output
const results = await siteup.build()
// console.dir(results, { color: true, depth: 999 })

const cwdDir = basename(cwd)
const srcDir = basename(relative(cwd, src))
const destDir = basename(relative(cwd, dest))

const treeStructure = {
label: `${join(cwdDir, srcDir)} => ${join(cwdDir, destDir)}`,
leaf: {
globalStyle: results?.siteData?.globalStyle?.basename,
globalClient: results?.siteData?.globalClient?.basename,
globalVars: results?.siteData?.globalVars?.basename,
rootLayout: results?.siteData?.rootLayout?.basename
},
nodes: []
try {
const results = await siteup.build()
console.log(tree(generateTreeData(cwd, src, dest, results)))
if (results?.warnings) {
console.log(
'\nThere were build warnings:\n'
)
}
for (const warning of results?.warnings) {
console.log(` ${warning.message}`)
}
console.log('\nBuild Success!\n\n')
} catch (err) {
if (err.results) {
console.log(tree(generateTreeData(cwd, src, dest, err.results)))
}
console.error(inspect(err, { depth: 999, colors: true }))
console.log('\nBuild Failed!\n\n')
}
} else {
// TODO: handle watch data event or something... maybe like a async iterator?
const initialResults = await siteup.watch()
console.log(initialResults)
}
}

for (const page of results?.siteData?.pages) {
const segments = page.page.relname.split(sep)
segments.pop()
function generateTreeData (cwd, src, dest, results) {
const cwdDir = basename(cwd)
const srcDir = basename(relative(cwd, src))
const destDir = basename(relative(cwd, dest))

const treeStructure = {
label: `${join(cwdDir, srcDir)} => ${join(cwdDir, destDir)}`,
leaf: {
globalStyle: results?.siteData?.globalStyle?.basename,
globalClient: results?.siteData?.globalClient?.basename,
globalVars: results?.siteData?.globalVars?.basename,
rootLayout: results?.siteData?.rootLayout?.basename
},
nodes: []
}

let nodes = treeStructure.nodes
let targetNode = treeStructure
for (const page of results?.siteData?.pages) {
const segments = page.page.relname.split(sep)
segments.pop()

for (const segment of segments) {
targetNode = nodes.find(node => segment === node.label)
if (!targetNode) {
targetNode = { label: segment, leaf: {}, nodes: [] }
nodes.push(targetNode)
}
nodes = targetNode.nodes
}
let nodes = treeStructure.nodes
let targetNode = treeStructure

targetNode.leaf[page.page.basename] = join(page.path, page.outputName)
if (page.pageStyle) targetNode.leaf[page.pageStyle.basename] = join(page.path, page.pageStyle.basename)
if (page.clientBundle) targetNode.leaf[page.clientBundle.basename] = join(page.path, page.clientBundle.basename)
if (page.pageVars) targetNode.leaf[page.pageVars.basename] = join(page.path, page.pageVars.basename)
for (const segment of segments) {
targetNode = nodes.find(node => segment === node.label)
if (!targetNode) {
targetNode = { label: segment, leaf: {}, nodes: [] }
nodes.push(targetNode)
}
nodes = targetNode.nodes
}

for (const file of results?.static?.report?.copied) {
const srcFile = relative(srcDir, file.source)
const destFile = relative(destDir, file.output)
const segments = srcFile.split(sep)
segments.pop()

let nodes = treeStructure.nodes
let targetNode = treeStructure

for (const segment of segments) {
targetNode = nodes.find(node => segment === node.label)
if (!targetNode) {
targetNode = { label: segment, leaf: {}, nodes: [] }
nodes.push(targetNode)
}
nodes = targetNode.nodes
}
targetNode.leaf[page.page.basename] = join(page.path, page.outputName)
if (page.pageStyle) targetNode.leaf[page.pageStyle.basename] = join(page.path, page.pageStyle.basename)
if (page.clientBundle) targetNode.leaf[page.clientBundle.basename] = join(page.path, page.clientBundle.basename)
if (page.pageVars) targetNode.leaf[page.pageVars.basename] = join(page.path, page.pageVars.basename)
}

targetNode.leaf[basename(srcFile)] = destFile
for (const file of results?.static?.report?.copied) {
const srcFile = relative(srcDir, file.source)
const destFile = relative(destDir, file.output)
const segments = srcFile.split(sep)
segments.pop()

let nodes = treeStructure.nodes
let targetNode = treeStructure

for (const segment of segments) {
targetNode = nodes.find(node => segment === node.label)
if (!targetNode) {
targetNode = { label: segment, leaf: {}, nodes: [] }
nodes.push(targetNode)
}
nodes = targetNode.nodes
}

console.log(tree(cleanDeep(treeStructure)))
console.log('Build Success!\n\n')
} else {
// TODO: handle watch data event or something... maybe like a async iterator?
const initialResults = await siteup.watch()
console.log(initialResults)
targetNode.leaf[basename(srcFile)] = destFile
}

return cleanDeep(treeStructure)
}

run().catch(e => {
console.error(e)
run().catch(err => {
console.error(new Error('Unhandled siteup error', { cause: err }))
process.exit(1)
})
8 changes: 4 additions & 4 deletions lib/build-css/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export async function buildCss (src, dest, siteData, opts) {
if (page.pageStyle) styles.push(page.pageStyle)
}

const results = {
const reports = {
type: 'css',
success: [],
errors: [],
Expand Down Expand Up @@ -50,13 +50,13 @@ export async function buildCss (src, dest, siteData, opts) {
}
delete result.css
delete result.root
results.success.push(result)
reports.success.push(result)
} catch (err) {
const buildError = new Error('Error building css', { cause: err })
buildError.style = style
results.errors.push(buildError)
reports.errors.push(buildError)
}
}

return results
return reports
}
10 changes: 5 additions & 5 deletions lib/build-js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ export async function buildJs (src, dest, siteData, opts) {

try {
// esbuild returns { errors:[], warnings: [] } already
const report = await esbuild.build(buildOpts)
return { ...report, buildOpts, type: 'js' }
const buildResults = await esbuild.build(buildOpts)
return { ...buildResults, buildOpts, type: 'js' }
} catch (err) {
const results = {
const report = {
type: 'js',
errors: [],
warnings: [],
buildOpts
}
const buildError = new Error('Error building JS clients', { cause: err })
buildError.buildOpts = buildOpts
results.errors.push(buildError)
return results
report.errors.push(buildError)
return report
}
}
24 changes: 12 additions & 12 deletions lib/build-pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ export function buildPages (src, dest, siteData, opts) {
workerData: { src, dest, siteData }
})

worker.once('message', results => {
if (results.errors.length > 0) {
worker.once('message', report => {
if (report.errors.length > 0) {
// Put the errorData on the error to be consistent with the rest of the builders.
results.errors = results.errors.map(({ error, errorData }) => {
report.errors = report.errors.map(({ error, errorData }) => {
for (const [key, val] of Object.entries(errorData)) {
error[key] = val
}
return error
})
}
resolve(results)
resolve(report)
})
worker.once('error', reject)
worker.once('exit', (code) => {
Expand All @@ -51,7 +51,7 @@ export function buildPages (src, dest, siteData, opts) {
* @return {[type]} [description]
*/
export async function buildPagesDirect (src, dest, siteData) {
const results = {
const report = {
type: 'page',
success: [],
errors: [],
Expand All @@ -67,18 +67,18 @@ export async function buildPagesDirect (src, dest, siteData) {
])

if (globalVars.status === 'rejected') {
results.errors.push(new Error('Encountered an error when resolving globalVars', {
report.errors.push(new Error('Encountered an error when resolving globalVars', {
cause: globalVars.reason
}))
}

if (rootLayout.status === 'rejected') {
results.errors.push(new Error('Encountered an error when resolving rootLayout', {
report.errors.push(new Error('Encountered an error when resolving rootLayout', {
cause: rootLayout.reason
}))
}

if (results.errors.length > 0) return results // Return early, these will all fail.
if (report.errors.length > 0) return report // Return early, these will all fail.

for (const page of siteData.pages) {
try {
Expand All @@ -90,20 +90,20 @@ export async function buildPagesDirect (src, dest, siteData) {
globalVars.value.styles = siteData.globalStyle ? ['/global.css'] : []
globalVars.value.scripts = siteData.globalClient ? ['/global.client.js'] : []

const result = await builder({
const buildResult = await builder({
src,
dest,
page,
globalVars: globalVars.value,
rootLayout: rootLayout.value
})
results.success.push(result)
report.success.push(buildResult)
} catch (err) {
const buildError = new Error('Error building page', { cause: err })
// I can't put stuff on the error, the worker swallows it for some reason.
results.errors.push({ error: buildError, errorData: { page } })
report.errors.push({ error: buildError, errorData: { page } })
}
}

return results
return report
}
16 changes: 8 additions & 8 deletions lib/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,28 @@ export function createBuilder (steps) {
const siteData = await identifyPages(src, pageBuilders, opts)
await ensureDest(src, dest, siteData)

const results = await Promise.all(
const reports = await Promise.all(
steps.map(
step => step(src, dest, siteData, opts)
)
)

const allResults = [siteData, ...results]
const reportsAndSiteData = [siteData, ...reports]

const errors = collectKeys('errors', allResults)
const warnings = collectKeys('warnings', allResults)
const errors = collectKeys('errors', reportsAndSiteData)
const warnings = collectKeys('warnings', reportsAndSiteData)

const report = {
...keyBy(allResults, result => result.type),
const results = {
...keyBy(reportsAndSiteData, result => result.type),
warnings
}

if (errors.length > 0) {
const buildError = new AggregateError(errors, 'Build finished but there were errors.')
buildError.report = report
buildError.results = results
throw buildError
} else {
return report
return results
}
}

Expand Down

0 comments on commit 92f76e0

Please sign in to comment.