Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { normalizedAssetPrefix } from '../../../../../shared/lib/normalized-asset-prefix'

function getSocketProtocol(assetPrefix: string): string {
let protocol = window.location.protocol

Expand All @@ -9,18 +11,16 @@ function getSocketProtocol(assetPrefix: string): string {
return protocol === 'http:' ? 'ws' : 'wss'
}

export function getSocketUrl(assetPrefix: string): string {
export function getSocketUrl(assetPrefix: string | undefined): string {
const { hostname, port } = window.location
const protocol = getSocketProtocol(assetPrefix)
const normalizedAssetPrefix = assetPrefix.replace(/^\/+/, '')

let url = `${protocol}://${hostname}:${port}${
normalizedAssetPrefix ? `/${normalizedAssetPrefix}` : ''
}`
const protocol = getSocketProtocol(assetPrefix || '')
const prefix = normalizedAssetPrefix(assetPrefix)

if (normalizedAssetPrefix.startsWith('http')) {
url = `${protocol}://${normalizedAssetPrefix.split('://', 2)[1]}`
// if original assetPrefix is a full URL with protocol
// we just update to use the correct `ws` protocol
if (assetPrefix?.replace(/^\/+/, '').includes('://')) {
return `${protocol}://${prefix}`
}

return url
return `${protocol}://${hostname}:${port}${prefix}`
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import type { HMR_ACTION_TYPES } from '../../../../server/dev/hot-reloader-types'
import { getSocketUrl } from '../internal/helpers/get-socket-url'

let source: WebSocket

type ActionCallback = (action: HMR_ACTION_TYPES) => void

const eventCallbacks: Array<ActionCallback> = []

function getSocketProtocol(assetPrefix: string): string {
let protocol = location.protocol

try {
// assetPrefix is a url
protocol = new URL(assetPrefix).protocol
} catch {}

return protocol === 'http:' ? 'ws' : 'wss'
}

export function addMessageListener(callback: ActionCallback) {
eventCallbacks.push(callback)
}
Expand Down Expand Up @@ -62,17 +52,7 @@ export function connectHMR(options: { path: string; assetPrefix: string }) {
timer = setTimeout(init, reconnections > 5 ? 5000 : 1000)
}

const { hostname, port } = location
const protocol = getSocketProtocol(options.assetPrefix || '')
const assetPrefix = options.assetPrefix.replace(/^\/+/, '')

let url = `${protocol}://${hostname}:${port}${
assetPrefix ? `/${assetPrefix}` : ''
}`

if (assetPrefix.startsWith('http')) {
url = `${protocol}://${assetPrefix.split('://', 2)[1]}`
}
const url = getSocketUrl(options.assetPrefix)

source = new window.WebSocket(`${url}${options.path}`)
source.onopen = handleOnline
Expand Down
9 changes: 8 additions & 1 deletion packages/next/src/server/lib/router-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
HMR_ACTIONS_SENT_TO_BROWSER,
type AppIsrManifestAction,
} from '../dev/hot-reloader-types'
import { normalizedAssetPrefix } from '../../shared/lib/normalized-asset-prefix'

const debug = setupDebug('next:router-server:main')
const isNextFont = (pathname: string | null) =>
Expand Down Expand Up @@ -662,8 +663,14 @@ export async function initialize(opts: {
if (opts.dev && developmentBundler && req.url) {
const { basePath, assetPrefix } = config

let hmrPrefix = basePath

// assetPrefix overrides basePath for HMR path
if (assetPrefix) {
hmrPrefix = normalizedAssetPrefix(assetPrefix)
}
const isHMRRequest = req.url.startsWith(
ensureLeadingSlash(`${assetPrefix || basePath}/_next/webpack-hmr`)
ensureLeadingSlash(`${hmrPrefix}/_next/webpack-hmr`)
)

// only handle HMR requests if the basePath in the request
Expand Down
16 changes: 16 additions & 0 deletions packages/next/src/shared/lib/normalized-asset-prefix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function normalizedAssetPrefix(assetPrefix: string | undefined): string {
const escapedAssetPrefix = assetPrefix?.replace(/^\/+/, '') || false

// assetPrefix as a url
if (escapedAssetPrefix && escapedAssetPrefix.startsWith('://')) {
return escapedAssetPrefix.split('://', 2)[1]
}

// assetPrefix is set to `undefined` or '/'
if (!escapedAssetPrefix) {
return ''
}

// assetPrefix is a common path but escaped so let's add one leading slash
return `/${escapedAssetPrefix}`
}
Loading
Loading