diff --git a/packages/core/integration-tests/test/hmr.js b/packages/core/integration-tests/test/hmr.js index 0fe734ce817..d1dc9d765db 100644 --- a/packages/core/integration-tests/test/hmr.js +++ b/packages/core/integration-tests/test/hmr.js @@ -1,7 +1,14 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); -const {bundler, run, rimraf, ncp} = require('@parcel/test-utils'); +const { + bundler, + run, + rimraf, + ncp, + prepareBrowserContext +} = require('@parcel/test-utils'); +const vm = require('vm'); const {sleep} = require('@parcel/test-utils'); const WebSocket = require('ws'); const json5 = require('json5'); @@ -318,6 +325,52 @@ describe('hmr', function() { assert.deepEqual(outputs, [3, 10]); }); + it('should accept HMR updates in the runtime after an initial error', async function() { + await fs.mkdirp(path.join(__dirname, '/input')); + fs.writeFile( + path.join(__dirname, '/input/index.js'), + 'module.hot.accept();throw new Error("Something");\noutput(123);' + ); + + b = bundler(path.join(__dirname, '/input/index.js'), { + watch: true, + hmr: true + }); + let bundle = await b.bundle(); + + let outputs = []; + let errors = []; + + var ctx = prepareBrowserContext(bundle, { + output(o) { + outputs.push(o); + }, + error(e) { + errors.push(e); + } + }); + vm.createContext(ctx); + vm.runInContext( + `try { + ${(await fs.readFile(bundle.name)).toString()} + } catch(e) { + error(e); + }`, + ctx + ); + + assert.deepEqual(outputs, []); + assert.equal(errors.length, 1); + assert.equal(errors[0].message, 'Something'); + + await sleep(100); + fs.writeFile(path.join(__dirname, '/input/index.js'), 'output(123);'); + + await nextEvent(b, 'bundled'); + assert.deepEqual(outputs, [123]); + assert.equal(errors.length, 1); + }); + it('should call dispose and accept callbacks', async function() { await ncp( path.join(__dirname, '/integration/hmr-callbacks'), diff --git a/packages/core/parcel-bundler/src/builtins/prelude.js b/packages/core/parcel-bundler/src/builtins/prelude.js index 9dccee3e5b3..db17e45c58d 100644 --- a/packages/core/parcel-bundler/src/builtins/prelude.js +++ b/packages/core/parcel-bundler/src/builtins/prelude.js @@ -5,9 +5,7 @@ // // anything defined in a previous bundle is accessed via the // orig method which is the require for previous bundles - -// eslint-disable-next-line no-global-assign -parcelRequire = (function (modules, cache, entry, globalName) { +(function (modules, cache, entry, globalName) { // Save the require from previous bundle to this closure if any var previousRequire = typeof parcelRequire === 'function' && parcelRequire; var nodeRequire = typeof require === 'function' && require; @@ -77,8 +75,16 @@ parcelRequire = (function (modules, cache, entry, globalName) { }, {}]; }; + var error; for (var i = 0; i < entry.length; i++) { - newRequire(entry[i]); + try { + newRequire(entry[i]); + } catch (e) { + // Save first error but execute all entries + if (!error) { + error = e; + } + } } if (entry.length) { @@ -103,5 +109,10 @@ parcelRequire = (function (modules, cache, entry, globalName) { } // Override the current require with this new one - return newRequire; + parcelRequire = newRequire; + + if (error) { + // throw error from earlier, _after updating parcelRequire_ + throw error; + } }) diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index 63dc8436f53..3458b4ebc17 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -293,6 +293,7 @@ exports.symlinkPrivilegeWarning = symlinkPrivilegeWarning; exports.bundler = bundler; exports.bundle = bundle; exports.run = run; +exports.prepareBrowserContext = prepareBrowserContext; exports.assertBundleTree = assertBundleTree; exports.nextBundle = nextBundle; exports.deferred = deferred;