From ffade8d5acc9270b098983710b57e2d6bc04721c Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala Date: Sun, 19 Mar 2017 04:31:55 +0530 Subject: [PATCH] Fix client error modal not showing in dev (HMR) (#1448) * Fix HMR not working issue. Our hot-reload code on the server has custom webpack error dectection logic. Is supports only multi-modules entries. So, we need to all entries as multi-module entries even if there's just a single entry. * Add a test case for showing errors over HMR. --- server/build/webpack.js | 6 ++-- server/on-demand-entry-handler.js | 2 +- test/integration/basic/pages/hmr/about.js | 7 ++++ test/integration/basic/test/hmr.js | 40 +++++++++++++++++++++++ test/integration/basic/test/index.test.js | 2 ++ 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 test/integration/basic/pages/hmr/about.js create mode 100644 test/integration/basic/test/hmr.js diff --git a/server/build/webpack.js b/server/build/webpack.js index dae3c8ec..e4b0403d 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -52,18 +52,18 @@ export default async function createCompiler (dir, { dev = false, quiet = false, // managing pages. if (dev) { for (const p of devPages) { - entries[join('bundles', p)] = `./${p}?entry` + entries[join('bundles', p)] = [`./${p}?entry`] } } else { for (const p of pages) { - entries[join('bundles', p)] = `./${p}?entry` + entries[join('bundles', p)] = [`./${p}?entry`] } } for (const p of defaultPages) { const entryName = join('bundles', 'pages', p) if (!entries[entryName]) { - entries[entryName] = [...defaultEntries, join(nextPagesDir, p) + '?entry'] + entries[entryName] = [join(nextPagesDir, p) + '?entry'] } } diff --git a/server/on-demand-entry-handler.js b/server/on-demand-entry-handler.js index 79c9160b..765c4da5 100644 --- a/server/on-demand-entry-handler.js +++ b/server/on-demand-entry-handler.js @@ -71,7 +71,7 @@ export default function onDemandEntryHandler (devMiddleware, compiler, { const pathname = await resolvePath(pagePath) const name = join('bundles', pathname.substring(dir.length)) - const entry = `${pathname}?entry` + const entry = [`${pathname}?entry`] await new Promise((resolve, reject) => { const entryInfo = entries[page] diff --git a/test/integration/basic/pages/hmr/about.js b/test/integration/basic/pages/hmr/about.js new file mode 100644 index 00000000..86b0b765 --- /dev/null +++ b/test/integration/basic/pages/hmr/about.js @@ -0,0 +1,7 @@ +export default () => ( +
+

+ This is the about page. +

+
+) diff --git a/test/integration/basic/test/hmr.js b/test/integration/basic/test/hmr.js new file mode 100644 index 00000000..4dde55d2 --- /dev/null +++ b/test/integration/basic/test/hmr.js @@ -0,0 +1,40 @@ +/* global describe, it, expect */ +import webdriver from 'next-webdriver' +import { readFileSync, writeFileSync } from 'fs' +import { join } from 'path' + +export default (context, render) => { + describe('Hot Module Reloading', () => { + describe('syntax error', () => { + it('should detect the error and recover', async () => { + const browser = await webdriver(context.appPort, '/hmr/about') + const text = await browser + .elementByCss('p').text() + expect(text).toBe('This is the about page.') + + const aboutPagePath = join(__dirname, '../', 'pages', 'hmr', 'about.js') + + const originalContent = readFileSync(aboutPagePath, 'utf8') + const erroredContent = originalContent.replace('', 'div') + + // change the content + writeFileSync(aboutPagePath, erroredContent, 'utf8') + + const errorMessage = await browser + .waitForElementByCss('pre') + .elementByCss('pre').text() + expect(errorMessage.includes('SyntaxError: Unterminated JSX contents')).toBeTruthy() + + // add the original content + writeFileSync(aboutPagePath, originalContent, 'utf8') + + const newContent = await browser + .waitForElementByCss('.hmr-about-page') + .elementByCss('p').text() + expect(newContent).toBe('This is the about page.') + + browser.close() + }) + }) + }) +} diff --git a/test/integration/basic/test/index.test.js b/test/integration/basic/test/index.test.js index 9922c703..94bacaa7 100644 --- a/test/integration/basic/test/index.test.js +++ b/test/integration/basic/test/index.test.js @@ -14,6 +14,7 @@ import xPoweredBy from './xpowered-by' import rendering from './rendering' import misc from './misc' import clientNavigation from './client-navigation' +import hmr from './hmr' const context = {} context.app = nextServer({ @@ -57,4 +58,5 @@ describe('Basic Features', () => { xPoweredBy(context) misc(context) clientNavigation(context, (p, q) => renderViaHTTP(context.appPort, p, q)) + hmr(context, (p, q) => renderViaHTTP(context.appPort, p, q)) })