From 560287704ae7c375be6251c578ca3cf85da591d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Domen=20Ko=C5=BEar?= Date: Wed, 26 Dec 2018 18:22:59 +0000 Subject: [PATCH] Defer throwing asset errors until after dependencies are handled. This allows compiled langauges like Elm that handle their own dependency compilation to set up watchers for dependencies so that hot-reload continues to work due to errors in new depdenencies. Fixes #2147. --- packages/core/parcel-bundler/src/Bundler.js | 7 +++++++ packages/core/parcel-bundler/src/Pipeline.js | 20 ++++++++++++++++--- .../parcel-bundler/src/assets/ElmAsset.js | 20 ++++++++++++------- .../src/builtins/hmr-runtime.js | 6 ++++-- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index f82222bf88f..fef0eb1ab42 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -593,6 +593,13 @@ class Bundler extends EventEmitter { }) ); + // If there was a processing error, re-throw now that we've set up + // depdenency watchers. This keeps hot-reloading working if there is an + // error in a dependency not directly handled by Parcel. + if (processed.error !== null) { + throw processed.error; + } + // Store resolved assets in their original order dependencies.forEach((dep, i) => { asset.dependencies.set(dep.name, dep); diff --git a/packages/core/parcel-bundler/src/Pipeline.js b/packages/core/parcel-bundler/src/Pipeline.js index 03a7579492f..c5554ccfc3d 100644 --- a/packages/core/parcel-bundler/src/Pipeline.js +++ b/packages/core/parcel-bundler/src/Pipeline.js @@ -17,16 +17,30 @@ class Pipeline { } let asset = this.parser.getAsset(path, options); - let generated = await this.processAsset(asset); + let error = null; let generatedMap = {}; - for (let rendition of generated) { - generatedMap[rendition.type] = rendition.value; + try { + let generated = await this.processAsset(asset); + for (let rendition of generated) { + generatedMap[rendition.type] = rendition.value; + } + } catch (err) { + // Error instances need to be converted to plain JS objects. + if (err instanceof Error) { + error = { + message: err.message, + stack: err.stack + }; + } else { + error = err; + } } return { id: asset.id, dependencies: Array.from(asset.dependencies.values()), generated: generatedMap, + error: error, hash: asset.hash, cacheData: asset.cacheData }; diff --git a/packages/core/parcel-bundler/src/assets/ElmAsset.js b/packages/core/parcel-bundler/src/assets/ElmAsset.js index 7a2309b3a5f..63311dd6662 100644 --- a/packages/core/parcel-bundler/src/assets/ElmAsset.js +++ b/packages/core/parcel-bundler/src/assets/ElmAsset.js @@ -44,12 +44,7 @@ class ElmAsset extends Asset { options.optimize = true; } - let compiled = await this.elm.compileToString(this.name, options); - this.contents = compiled.toString(); - if (this.options.hmr) { - let {inject} = await localRequire('elm-hot', this.name); - this.contents = inject(this.contents); - } + this.elmOpts = options; } async collectDependencies() { @@ -76,7 +71,14 @@ class ElmAsset extends Asset { } async generate() { - let output = this.contents; + let compiled = null; + compiled = await this.elm.compileToString(this.name, this.elmOpts); + let output = compiled.toString(); + + if (this.options.hmr) { + let {inject} = await localRequire('elm-hot', this.name); + output = inject(output); + } if (this.options.minify) { output = pack(output); @@ -129,6 +131,10 @@ class ElmAsset extends Asset { return result.code; } } + + generateErrorMessage(err) { + return err.message; + } } module.exports = ElmAsset; diff --git a/packages/core/parcel-bundler/src/builtins/hmr-runtime.js b/packages/core/parcel-bundler/src/builtins/hmr-runtime.js index 74efb86d4d6..5be0d7aa28a 100644 --- a/packages/core/parcel-bundler/src/builtins/hmr-runtime.js +++ b/packages/core/parcel-bundler/src/builtins/hmr-runtime.js @@ -57,7 +57,9 @@ if ((!parent || !parent.isParcelRequire) && typeof WebSocket !== 'undefined') { } if (data.type === 'error') { - console.error('[parcel] 🚨 ' + data.error.message + '\n' + data.error.stack); + console.error( + '[parcel] 🚨 ' + data.error.message + '\n' + (data.error.stack || '') + ); removeErrorOverlay(); @@ -82,7 +84,7 @@ function createErrorOverlay(data) { var message = document.createElement('div'); var stackTrace = document.createElement('pre'); message.innerText = data.error.message; - stackTrace.innerText = data.error.stack; + stackTrace.innerText = data.error.stack || ''; overlay.innerHTML = ( '
' +