From 5a9a478cc84d013515d62d814f1f746cae5ffdff Mon Sep 17 00:00:00 2001
From: JJ Kasper
Date: Fri, 17 Jan 2020 14:13:51 -0600
Subject: [PATCH] Fix hydration with custom _app and granular chunks (#10144)
* Add failing hydration test
* Add importing of next/router to _app
* Fix type
* Update _app check for windows
* Remove babel fix
* Update to use webpack to require next/router
---
packages/next/build/entries.ts | 11 ++++++-
packages/next/pages/_app.tsx | 1 -
test/integration/hydration/pages/_app.js | 1 +
test/integration/hydration/pages/_document.js | 16 +++++++++
test/integration/hydration/pages/details.js | 6 ++++
test/integration/hydration/pages/index.js | 6 ++++
test/integration/hydration/test/index.test.js | 33 +++++++++++++++++++
7 files changed, 72 insertions(+), 2 deletions(-)
create mode 100644 test/integration/hydration/pages/_app.js
create mode 100644 test/integration/hydration/pages/_document.js
create mode 100644 test/integration/hydration/pages/details.js
create mode 100644 test/integration/hydration/pages/index.js
create mode 100644 test/integration/hydration/test/index.test.js
diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts
index f51675d36655c16..a518b7b9877c69c 100644
--- a/packages/next/build/entries.ts
+++ b/packages/next/build/entries.ts
@@ -115,10 +115,19 @@ export function createEntrypoints(
}
if (!isApiRoute) {
- client[bundlePath] = `next-client-pages-loader?${stringify({
+ const pageLoader = `next-client-pages-loader?${stringify({
page,
absolutePagePath,
})}!`
+
+ // Make sure next/router is a dependency of _app or else granularChunks
+ // might cause the router to not be able to load causing hydration
+ // to fail
+
+ client[bundlePath] =
+ page === '/_app'
+ ? [pageLoader, require.resolve('../client/router')]
+ : pageLoader
}
})
diff --git a/packages/next/pages/_app.tsx b/packages/next/pages/_app.tsx
index c4041f9613d76a5..3971441a24339ef 100644
--- a/packages/next/pages/_app.tsx
+++ b/packages/next/pages/_app.tsx
@@ -7,7 +7,6 @@ import {
AppPropsType,
} from '../next-server/lib/utils'
import { Router } from '../client/router'
-import '../client/router'
export { AppInitialProps }
diff --git a/test/integration/hydration/pages/_app.js b/test/integration/hydration/pages/_app.js
new file mode 100644
index 000000000000000..e3c005467a1695a
--- /dev/null
+++ b/test/integration/hydration/pages/_app.js
@@ -0,0 +1 @@
+export default ({ Component, pageProps }) =>
diff --git a/test/integration/hydration/pages/_document.js b/test/integration/hydration/pages/_document.js
new file mode 100644
index 000000000000000..d4d66d494410fb1
--- /dev/null
+++ b/test/integration/hydration/pages/_document.js
@@ -0,0 +1,16 @@
+import Document, { Head, Html, Main, NextScript } from 'next/document'
+import React from 'react'
+
+class WeddingDocument extends Document {
+ render() {
+ return (
+
+
+
+
+
+ )
+ }
+}
+
+export default WeddingDocument
diff --git a/test/integration/hydration/pages/details.js b/test/integration/hydration/pages/details.js
new file mode 100644
index 000000000000000..0acf307fdefc8c7
--- /dev/null
+++ b/test/integration/hydration/pages/details.js
@@ -0,0 +1,6 @@
+export default () => {
+ if (typeof window !== 'undefined') {
+ window.didHydrate = true
+ }
+ return 'details'
+}
diff --git a/test/integration/hydration/pages/index.js b/test/integration/hydration/pages/index.js
new file mode 100644
index 000000000000000..b0989ad629fb61d
--- /dev/null
+++ b/test/integration/hydration/pages/index.js
@@ -0,0 +1,6 @@
+export default () => {
+ if (typeof window !== 'undefined') {
+ window.didHydrate = true
+ }
+ return 'index'
+}
diff --git a/test/integration/hydration/test/index.test.js b/test/integration/hydration/test/index.test.js
new file mode 100644
index 000000000000000..5a18abec58403b1
--- /dev/null
+++ b/test/integration/hydration/test/index.test.js
@@ -0,0 +1,33 @@
+/* eslint-env jest */
+/* global jasmine */
+import path from 'path'
+import fs from 'fs-extra'
+import webdriver from 'next-webdriver'
+import {
+ nextBuild,
+ nextStart,
+ findPort,
+ waitFor,
+ killApp,
+} from 'next-test-utils'
+
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 1
+const appDir = path.join(__dirname, '..')
+let app
+let appPort
+
+describe('Hydration', () => {
+ beforeAll(async () => {
+ await fs.remove(path.join(appDir, '.next'))
+ await nextBuild(appDir)
+ appPort = await findPort()
+ app = await nextStart(appDir, appPort)
+ })
+ afterAll(() => killApp(app))
+
+ it('Hydrates correctly', async () => {
+ const browser = await webdriver(appPort, '/')
+ await waitFor(2000)
+ expect(await browser.eval('window.didHydrate')).toBe(true)
+ })
+})