diff --git a/client-src/index.js b/client-src/index.js index 53bb7a6e30..0116250807 100644 --- a/client-src/index.js +++ b/client-src/index.js @@ -12,43 +12,20 @@ const sendMessage = require('./utils/sendMessage'); const reloadApp = require('./utils/reloadApp'); const createSocketURL = require('./utils/createSocketURL'); -const status = { - isUnloading: false, - currentHash: '', -}; -const defaultOptions = { +const status = { isUnloading: false, currentHash: '' }; +const options = { hot: false, - hotReload: true, liveReload: false, initial: true, progress: false, overlay: false, }; const parsedResourceQuery = parseURL(__resourceQuery); -const options = defaultOptions; - -// Handle Node.js legacy format and `new URL()` -if (parsedResourceQuery.query) { - Object.assign(options, parsedResourceQuery.query); -} else if (parsedResourceQuery.searchParams) { - const paramsToObject = (entries) => { - const result = {}; - - for (const [key, value] of entries) { - result[key] = value; - } - return result; - }; - - Object.assign( - options, - paramsToObject(parsedResourceQuery.searchParams.entries()) - ); +if (parsedResourceQuery.logging) { + options.logging = parsedResourceQuery.logging; } -const socketURL = createSocketURL(parsedResourceQuery); - function setAllLogLevel(level) { // This is needed because the HMR logger operate separately from dev server logger webpackHotLog.setLogLevel( @@ -65,12 +42,6 @@ self.addEventListener('beforeunload', () => { status.isUnloading = true; }); -if (typeof window !== 'undefined') { - const qs = window.location.search.toLowerCase(); - - options.hotReload = qs.indexOf('hotreload=false') === -1; -} - const onSocketMessage = { hot() { options.hot = true; @@ -220,4 +191,6 @@ const onSocketMessage = { }, }; +const socketURL = createSocketURL(parsedResourceQuery); + socket(socketURL, onSocketMessage); diff --git a/client-src/utils/createSocketURL.js b/client-src/utils/createSocketURL.js index 525aecd4cb..d0ebbf25f9 100644 --- a/client-src/utils/createSocketURL.js +++ b/client-src/utils/createSocketURL.js @@ -5,14 +5,13 @@ const url = require('url'); // We handle legacy API that is Node.js specific, and a newer API that implements the same WHATWG URL Standard used by web browsers // Please look at https://nodejs.org/api/url.html#url_url_strings_and_url_objects function createSocketURL(parsedURL) { - let { auth, hostname, protocol, port } = parsedURL; + let { hostname } = parsedURL; // Node.js module parses it as `::` // `new URL(urlString, [baseURLstring])` parses it as '[::]' const isInAddrAny = hostname === '0.0.0.0' || hostname === '::' || hostname === '[::]'; - // check ipv4 and ipv6 `all hostname` // why do we need this check? // hostname n/a for file protocol (example, when using electron, ionic) // see: https://github.com/webpack/webpack-dev-server/pull/384 @@ -24,54 +23,55 @@ function createSocketURL(parsedURL) { hostname = self.location.hostname; } - if (protocol === 'auto:') { - protocol = self.location.protocol; - } + let socketURLProtocol = parsedURL.protocol || 'ws:'; - // `hostname` can be empty when the script path is relative. In that case, specifying a protocol would result in an invalid URL. // When https is used in the app, secure web sockets are always necessary because the browser doesn't accept non-secure web sockets. - if (hostname && isInAddrAny && self.location.protocol === 'https:') { - protocol = self.location.protocol; + if ( + socketURLProtocol === 'auto:' || + (hostname && isInAddrAny && self.location.protocol === 'https:') + ) { + socketURLProtocol = self.location.protocol; } - const socketURLProtocol = protocol.replace( + socketURLProtocol = socketURLProtocol.replace( /^(?:http|.+-extension|file)/i, 'ws' ); + let socketURLAuth = ''; + // `new URL(urlString, [baseURLstring])` doesn't have `auth` property // Parse authentication credentials in case we need them if (parsedURL.username) { - auth = parsedURL.username; + socketURLAuth = parsedURL.username; // Since HTTP basic authentication does not allow empty username, // we only include password if the username is not empty. if (parsedURL.password) { // Result: : - auth = auth.concat(':', parsedURL.password); + socketURLAuth = socketURLAuth.concat(':', parsedURL.password); } } - const socketURLAuth = auth; - // In case the host is a raw IPv6 address, it can be enclosed in // the brackets as the brackets are needed in the final URL string. // Need to remove those as url.format blindly adds its own set of brackets // if the host string contains colons. That would lead to non-working // double brackets (e.g. [[::]]) host // - // All of these sock url params are optionally passed in through resourceQuery, + // All of these web socket url params are optionally passed in through resourceQuery, // so we need to fall back to the default if they are not provided - const socketURLHostname = (hostname || 'localhost').replace( - /^\[(.*)\]$/, - '$1' - ); + const socketURLHostname = ( + hostname || + self.location.hostname || + 'localhost' + ).replace(/^\[(.*)\]$/, '$1'); - if (!port || port === '0') { - port = self.location.port; - } + let socketURLPort = parsedURL.port; - const socketURLPort = port; + if (!socketURLPort || socketURLPort === '0') { + socketURLPort = self.location.port; + } // If path is provided it'll be passed in via the resourceQuery as a // query param so it has to be parsed out of the querystring in order for the diff --git a/client-src/utils/parseURL.js b/client-src/utils/parseURL.js index d40db3c2b1..effcc0f78b 100644 --- a/client-src/utils/parseURL.js +++ b/client-src/utils/parseURL.js @@ -4,24 +4,16 @@ const url = require('url'); const getCurrentScriptSource = require('./getCurrentScriptSource'); function parseURL(resourceQuery) { - let options; + let options = {}; if (typeof resourceQuery === 'string' && resourceQuery !== '') { - // If this bundle is inlined, use the resource query to get the correct url. - // for backward compatibility we supports: - // - ?ws://0.0.0.0:8096&3Flogging=info - // - ?ws%3A%2F%2F192.168.0.5%3A8080%2F%3Flogging%3Dinfo - // Also we support `http` and `https` for backward compatibility too - options = url.parse( - decodeURIComponent( - resourceQuery - // strip leading `?` from query string to get a valid URL - .substr(1) - // replace first `&` with `?` to have a valid query string - .replace('&', '?') - ), - true - ); + const searchParams = resourceQuery.substr(1).split('&'); + + for (let i = 0; i < searchParams.length; i++) { + const pair = searchParams[i].split('='); + + options[pair[0]] = decodeURIComponent(pair[1]); + } } else { // Else, get the url from the