Spaces:
Sleeping
Sleeping
classifieur
/
frontend
/node_modules
/@pmmmwh
/react-refresh-webpack-plugin
/sockets
/utils
/getSocketUrlParts.js
const getCurrentScriptSource = require('./getCurrentScriptSource.js'); | |
/** | |
* @typedef {Object} SocketUrlParts | |
* @property {string} [auth] | |
* @property {string} hostname | |
* @property {string} [protocol] | |
* @property {string} pathname | |
* @property {string} [port] | |
*/ | |
/** | |
* Parse current location and Webpack's `__resourceQuery` into parts that can create a valid socket URL. | |
* @param {string} [resourceQuery] The Webpack `__resourceQuery` string. | |
* @param {import('./getWDSMetadata').WDSMetaObj} [metadata] The parsed WDS metadata object. | |
* @returns {SocketUrlParts} The parsed URL parts. | |
* @see https://webpack.js.org/api/module-variables/#__resourcequery-webpack-specific | |
*/ | |
function getSocketUrlParts(resourceQuery, metadata) { | |
if (typeof metadata === 'undefined') { | |
metadata = {}; | |
} | |
/** @type {SocketUrlParts} */ | |
let urlParts = {}; | |
// If the resource query is available, | |
// parse it and ignore everything we received from the script host. | |
if (resourceQuery) { | |
const parsedQuery = {}; | |
const searchParams = new URLSearchParams(resourceQuery.slice(1)); | |
searchParams.forEach(function (value, key) { | |
parsedQuery[key] = value; | |
}); | |
urlParts.hostname = parsedQuery.sockHost; | |
urlParts.pathname = parsedQuery.sockPath; | |
urlParts.port = parsedQuery.sockPort; | |
// Make sure the protocol from resource query has a trailing colon | |
if (parsedQuery.sockProtocol) { | |
urlParts.protocol = parsedQuery.sockProtocol + ':'; | |
} | |
} else { | |
const scriptSource = getCurrentScriptSource(); | |
let url = {}; | |
try { | |
// The placeholder `baseURL` with `window.location.href`, | |
// is to allow parsing of path-relative or protocol-relative URLs, | |
// and will have no effect if `scriptSource` is a fully valid URL. | |
url = new URL(scriptSource, window.location.href); | |
} catch (e) { | |
// URL parsing failed, do nothing. | |
// We will still proceed to see if we can recover using `resourceQuery` | |
} | |
// Parse authentication credentials in case we need them | |
if (url.username) { | |
// Since HTTP basic authentication does not allow empty username, | |
// we only include password if the username is not empty. | |
// Result: <username> or <username>:<password> | |
urlParts.auth = url.username; | |
if (url.password) { | |
urlParts.auth += ':' + url.password; | |
} | |
} | |
// `file://` URLs has `'null'` origin | |
if (url.origin !== 'null') { | |
urlParts.hostname = url.hostname; | |
} | |
urlParts.protocol = url.protocol; | |
urlParts.port = url.port; | |
} | |
if (!urlParts.pathname) { | |
if (metadata.version === 4) { | |
// This is hard-coded in WDS v4 | |
urlParts.pathname = '/ws'; | |
} else { | |
// This is hard-coded in WDS v3 | |
urlParts.pathname = '/sockjs-node'; | |
} | |
} | |
// Check for IPv4 and IPv6 host addresses that correspond to any/empty. | |
// This is important because `hostname` can be empty for some hosts, | |
// such as 'about:blank' or 'file://' URLs. | |
const isEmptyHostname = | |
urlParts.hostname === '0.0.0.0' || urlParts.hostname === '[::]' || !urlParts.hostname; | |
// We only re-assign the hostname if it is empty, | |
// and if we are using HTTP/HTTPS protocols. | |
if ( | |
isEmptyHostname && | |
window.location.hostname && | |
window.location.protocol.indexOf('http') === 0 | |
) { | |
urlParts.hostname = window.location.hostname; | |
} | |
// We only re-assign `protocol` when `protocol` is unavailable, | |
// or if `hostname` is available and is empty, | |
// since otherwise we risk creating an invalid URL. | |
// We also do this when no sockProtocol was passed to the config and 'https' is used, | |
// as it mandates the use of secure sockets. | |
if ( | |
!urlParts.protocol || | |
(urlParts.hostname && | |
(isEmptyHostname || (!resourceQuery && window.location.protocol === 'https:'))) | |
) { | |
urlParts.protocol = window.location.protocol; | |
} | |
// We only re-assign port when it is not available | |
if (!urlParts.port) { | |
urlParts.port = window.location.port; | |
} | |
if (!urlParts.hostname || !urlParts.pathname) { | |
throw new Error( | |
[ | |
'[React Refresh] Failed to get an URL for the socket connection.', | |
"This usually means that the current executed script doesn't have a `src` attribute set.", | |
'You should either specify the socket path parameters under the `devServer` key in your Webpack config, or use the `overlay` option.', | |
'https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/API.md#overlay', | |
].join('\n') | |
); | |
} | |
return { | |
auth: urlParts.auth, | |
hostname: urlParts.hostname, | |
pathname: urlParts.pathname, | |
protocol: urlParts.protocol, | |
port: urlParts.port || undefined, | |
}; | |
} | |
module.exports = getSocketUrlParts; | |