From a809fcc0d4cedd4e1aa2849f150bd8f774416413 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Fri, 2 Oct 2020 12:41:09 -0700 Subject: [PATCH] improve error handing (#1180) --- esinstall/src/stats.ts | 2 +- snowpack/src/commands/build.ts | 31 +++++++++++++++++++++++++++--- snowpack/src/commands/dev.ts | 35 +++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/esinstall/src/stats.ts b/esinstall/src/stats.ts index e8703940ef..fb3500c011 100644 --- a/esinstall/src/stats.ts +++ b/esinstall/src/stats.ts @@ -85,7 +85,7 @@ export function printStats(dependencyStats: DependencyStatsOutput): string { output += `${formatFiles(allDirect, maxFileNameLength)}\n`; if (Object.values(common).length > 0) { output += ` ⦿ ${colors.bold('web_modules/common/ (Shared)')}\n`; - output += `${formatFiles(allCommon, maxFileNameLength)}\n`; + output += `${formatFiles(allCommon, maxFileNameLength)}`; } return `\n${output}\n`; } diff --git a/snowpack/src/commands/build.ts b/snowpack/src/commands/build.ts index b0d71aaf20..0f3b10a2ab 100644 --- a/snowpack/src/commands/build.ts +++ b/snowpack/src/commands/build.ts @@ -40,6 +40,11 @@ function getIsHmrEnabled(config: SnowpackConfig) { return config.buildOptions.watch && !!config.devOptions.hmr; } +function handleFileError(err: Error, builder: FileBuilder) { + logger.error(`✘ ${builder.filepath}\n ${err.stack ? err.stack : err.message}`); + process.exit(1); +} + async function installOptimizedDependencies( scannedFiles: SnowpackSourceFile[], installDest: string, @@ -383,7 +388,9 @@ export async function command(commandOptions: CommandOptions) { const parallelWorkQueue = new PQueue({concurrency: CONCURRENT_WORKERS}); const allBuildPipelineFiles = Object.values(buildPipelineFiles); for (const buildPipelineFile of allBuildPipelineFiles) { - parallelWorkQueue.add(() => buildPipelineFile.buildFile()); + parallelWorkQueue.add(() => + buildPipelineFile.buildFile().catch((err) => handleFileError(err, buildPipelineFile)), + ); } await parallelWorkQueue.onIdle(); @@ -397,13 +404,21 @@ export async function command(commandOptions: CommandOptions) { // 2. Install all dependencies. This gets us the import map we need to resolve imports. let installResult = await installDependencies(); + logger.info(colors.yellow('! verifying build...')); + // 3. Resolve all built file imports. for (const buildPipelineFile of allBuildPipelineFiles) { - parallelWorkQueue.add(() => buildPipelineFile.resolveImports(installResult.importMap!)); + parallelWorkQueue.add(() => + buildPipelineFile + .resolveImports(installResult.importMap!) + .catch((err) => handleFileError(err, buildPipelineFile)), + ); } await parallelWorkQueue.onIdle(); + logger.info(`${colors.green('✔')} verification complete`); // 4. Write files to disk. + logger.info(colors.yellow('! writing build to disk...')); const allImportProxyFiles = new Set( allBuildPipelineFiles.map((b) => b.filesToProxy).reduce((flat, item) => flat.concat(item), []), ); @@ -411,12 +426,22 @@ export async function command(commandOptions: CommandOptions) { parallelWorkQueue.add(() => buildPipelineFile.writeToDisk()); for (const builtFile of Object.keys(buildPipelineFile.output)) { if (allImportProxyFiles.has(builtFile)) { - parallelWorkQueue.add(() => buildPipelineFile.writeProxyToDisk(builtFile)); + parallelWorkQueue.add(() => + buildPipelineFile + .writeProxyToDisk(builtFile) + .catch((err) => handleFileError(err, buildPipelineFile)), + ); } } } await parallelWorkQueue.onIdle(); + logger.info( + `${colors.green('✔')} build complete ${colors.dim( + `[${((buildEnd - buildStart) / 1000).toFixed(2)}s]`, + )}`, + ); + // 5. Optimize the build. if (!config.buildOptions.watch) { await runPipelineCleanupStep(config); diff --git a/snowpack/src/commands/dev.ts b/snowpack/src/commands/dev.ts index 801730c243..a4f0a307d2 100644 --- a/snowpack/src/commands/dev.ts +++ b/snowpack/src/commands/dev.ts @@ -83,6 +83,8 @@ import { import {getInstallTargets, run as installRunner} from './install'; import {getPort, paint, paintEvent} from './paint'; +const FILE_BUILD_RESULT_ERROR = `Build Result Error: There was a problem with a file build result.`; + const DEFAULT_PROXY_ERROR_HANDLER = ( err: Error, req: http.IncomingMessage, @@ -233,6 +235,7 @@ const sendFile = ( }; const sendError = (req: http.IncomingMessage, res: http.ServerResponse, status: number) => { + logger.error(`[${status}] ${req.url}`); const contentType = mime.contentType(path.extname(req.url!) || '.html'); const headers: Record = { 'Access-Control-Allow-Origin': '*', @@ -769,7 +772,22 @@ export async function startServer(commandOptions: CommandOptions) { // 1. Check the hot build cache. If it's already found, then just serve it. let hotCachedResponse: SnowpackBuildMap | undefined = inMemoryBuildCache.get(fileLoc, isSSR); if (hotCachedResponse) { - const responseContent = await finalizeResponse(fileLoc, requestedFileExt, hotCachedResponse); + let responseContent: string | Buffer | null; + try { + responseContent = await finalizeResponse(fileLoc, requestedFileExt, hotCachedResponse); + } catch (err) { + logger.error(FILE_BUILD_RESULT_ERROR); + logger.error(err.toString()); + hmrEngine.broadcastMessage({ + type: 'error', + title: FILE_BUILD_RESULT_ERROR, + errorMessage: err.toString(), + fileLoc, + errorStackTrace: err.stack, + }); + sendError(req, res, 500); + return; + } if (!responseContent) { sendError(req, res, 404); return; @@ -854,7 +872,8 @@ export async function startServer(commandOptions: CommandOptions) { hmrEngine.broadcastMessage({ type: 'error', title: - `Build Error` + err.__snowpackBuildDetails ? `: ${err.__snowpackBuildDetails.name}` : '', + `Build Error` + + (err.__snowpackBuildDetails ? `: ${err.__snowpackBuildDetails.name}` : ''), errorMessage: err.toString(), fileLoc, errorStackTrace: err.stack, @@ -865,8 +884,15 @@ export async function startServer(commandOptions: CommandOptions) { try { responseContent = await finalizeResponse(fileLoc, requestedFileExt, responseOutput); } catch (err) { - logger.error(`${reqPath} -${err}`); + logger.error(FILE_BUILD_RESULT_ERROR); + logger.error(err.toString()); + hmrEngine.broadcastMessage({ + type: 'error', + title: FILE_BUILD_RESULT_ERROR, + errorMessage: err.toString(), + fileLoc, + errorStackTrace: err.stack, + }); sendError(req, res, 500); return; } @@ -909,7 +935,6 @@ ${err}`); const server = createServer((req, res) => { /** Handle errors not handled in our requestHandler. */ function onUnhandledError(err: Error) { - logger.error(`[500] ${req.url}`); logger.error(err.toString()); sendError(req, res, 500); }