diff --git a/packages/next-server/server/config.js b/packages/next-server/server/config.js index 943edc6bb986aec2e4a56f45ab273d0ccb64a315..d98a1fcbfd421c2667054f35d701015fd0127492 100644 --- a/packages/next-server/server/config.js +++ b/packages/next-server/server/config.js @@ -14,7 +14,12 @@ const defaultConfig = { generateBuildId: () => null, generateEtags: true, pageExtensions: ['jsx', 'js'], - target: 'server' + target: 'server', + onDemandEntries: { + maxInactiveAge: 60 * 1000, + pagesBufferLength: 2, + websocketPort: 0 + } } function normalizeConfig (phase, config) { @@ -40,6 +45,12 @@ export default function loadConfig (phase, dir, customConfig) { if (userConfig.target && !targets.includes(userConfig.target)) { throw new Error(`Specified target is invalid. Provided: "${userConfig.target}" should be one of ${targets.join(', ')}`) } + if (userConfig.onDemandEntries) { + userConfig.onDemandEntries = { + ...defaultConfig.onDemandEntries, + ...userConfig.onDemandEntries + } + } return {...defaultConfig, configOrigin: CONFIG_FILE, ...userConfig} } diff --git a/packages/next/README.md b/packages/next/README.md index 9b13ded442abbbc446b43e4836506a4dbb3f60bb..471289a04894a920de3b18283800084af4b4a4f7 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -1292,7 +1292,9 @@ module.exports = { maxInactiveAge: 25 * 1000, // number of pages that should be kept simultaneously without being disposed pagesBufferLength: 2, - } + // optionally configure a port for the onDemandEntries WebSocket, not needed by default + websocketPort: 3001, + }, } ``` diff --git a/packages/next/server/hot-reloader.js b/packages/next/server/hot-reloader.js index e31dfd9b043cb1eace9c84507bb57c7261010263..763542ae48285dee0182260d797a19797b02754f 100644 --- a/packages/next/server/hot-reloader.js +++ b/packages/next/server/hot-reloader.js @@ -173,8 +173,9 @@ export default class HotReloader { await this.clean() this.wsPort = await new Promise((resolve, reject) => { - // create dynamic entries WebSocket - this.wss = new WebSocket.Server({ port: 0 }, function (err) { + const { websocketPort } = this.config.onDemandEntries + // create on-demand-entries WebSocket + this.wss = new WebSocket.Server({ port: websocketPort }, function (err) { if (err) { return reject(err) } diff --git a/packages/next/server/on-demand-entry-handler.js b/packages/next/server/on-demand-entry-handler.js index 58168d2eb008ba786a38197f1c200a7186307284..0d13f2c45d8881d841655b40cfee8790f44f49db 100644 --- a/packages/next/server/on-demand-entry-handler.js +++ b/packages/next/server/on-demand-entry-handler.js @@ -33,8 +33,8 @@ export default function onDemandEntryHandler (devMiddleware, multiCompiler, { dev, reload, pageExtensions, - maxInactiveAge = 1000 * 60, - pagesBufferLength = 2, + maxInactiveAge, + pagesBufferLength, wsPort }) { const {compilers} = multiCompiler diff --git a/test/integration/config/next.config.js b/test/integration/config/next.config.js index a709be300bdea68469cf2e4e523e11cde430778f..01f0a6c641f7dffff6ca13bffdb6c823974fe45c 100644 --- a/test/integration/config/next.config.js +++ b/test/integration/config/next.config.js @@ -5,7 +5,8 @@ const path = require('path') module.exports = withCSS(withSass({ onDemandEntries: { // Make sure entries are not getting disposed. - maxInactiveAge: 1000 * 60 * 60 + maxInactiveAge: 1000 * 60 * 60, + websocketPort: 3001 }, cssModules: true, serverRuntimeConfig: { diff --git a/test/integration/config/test/client.js b/test/integration/config/test/client.js index 70216789a747ba9a5f2180db2321c0e5a1b0ffc5..93b725483d3e9e92fb5f1e79c0fa061804988a2e 100644 --- a/test/integration/config/test/client.js +++ b/test/integration/config/test/client.js @@ -1,7 +1,7 @@ /* eslint-env jest */ import webdriver from 'next-webdriver' -import { waitFor } from 'next-test-utils' /* check, File */ +import { waitFor, fetchViaHTTP } from 'next-test-utils' /* check, File */ import { readFileSync, writeFileSync } from 'fs' import { join } from 'path' @@ -20,6 +20,12 @@ export default (context, render) => { browser.close() }) + it('should use websocketPort for on-demand-entries WebSocket', async () => { + const res = await fetchViaHTTP(context.appPort, '/_next/on-demand-entries-ping') + const wsPort = res.headers.get('port') + expect(wsPort).toBe(context.devWebSocketPort + '') + }) + it('should update css styles using hmr', async () => { let browser try { diff --git a/test/integration/config/test/index.test.js b/test/integration/config/test/index.test.js index 6cd7774793d0d9cdf95b3f66459fd4aac996ca1b..69af07bb34a895784c76674e0bdd1a6d02a235c7 100644 --- a/test/integration/config/test/index.test.js +++ b/test/integration/config/test/index.test.js @@ -6,7 +6,8 @@ import { fetchViaHTTP, findPort, launchApp, - killApp + killApp, + File } from 'next-test-utils' // test suits @@ -19,6 +20,15 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5 describe('Configuration', () => { beforeAll(async () => { context.appPort = await findPort() + context.devWebSocketPort = await findPort() + + // update next.config with found devWebSocketPort (must come before launchApp) + context.nextConfig = new File(join(__dirname, '../next.config.js')) + context.nextConfig.replace( + 'websocketPort: 3001', + `websocketPort: ${context.devWebSocketPort}` + ) + context.server = await launchApp(join(__dirname, '../'), context.appPort) // pre-build all pages at the start @@ -28,7 +38,10 @@ describe('Configuration', () => { renderViaHTTP(context.appPort, '/webpack-css') ]) }) - afterAll(() => killApp(context.server)) + afterAll(() => { + killApp(context.server) + context.nextConfig.restore() + }) rendering(context, 'Rendering via HTTP', (p, q) => renderViaHTTP(context.appPort, p, q), (p, q) => fetchViaHTTP(context.appPort, p, q)) client(context, (p, q) => renderViaHTTP(context.appPort, p, q))