@pmmmwh/react-refresh-webpack-plugin
Advanced tools
Comparing version 0.3.0-beta.1 to 0.3.0-beta.2
{ | ||
"name": "@pmmmwh/react-refresh-webpack-plugin", | ||
"version": "0.3.0-beta.1", | ||
"version": "0.3.0-beta.2", | ||
"description": "An **EXPERIMENTAL** Webpack plugin to enable \"Fast Refresh\" (also previously known as _Hot Reloading_) for React components.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -111,3 +111,3 @@ # React Refresh Webpack Plugin | ||
### Polyfill for Older Browsers (WDS Only) | ||
### Polyfill for Older Browsers | ||
@@ -161,4 +161,5 @@ If you need to develop on IE11, you will need to polyfill the DOM URL API. | ||
- A `module` property must be defined. | ||
It should reference a JS file that exports at least two functions with footprints as follows: | ||
- An optional `module` property could be defined. | ||
If it is not defined, the bundled error overlay will be used. | ||
If defined, it should reference a JS file that exports at least two functions with footprints as follows: | ||
@@ -170,3 +171,3 @@ ```ts | ||
- An optional `entry` property could also be defined, which should also reference a JS file that contains code needed to set up your custom error overlay integration. | ||
- An optional `entry` property could be defined, which should also reference a JS file that contains code needed to set up your custom error overlay integration. | ||
If it is not defined, the bundled error overlay entry will be used. | ||
@@ -192,17 +193,31 @@ It expects the `module` file to export two more functions: | ||
### `options.sockHost` | ||
#### `options.overlay.sockHost` | ||
Type: `string` | ||
Default: effectively `window.location.hostname` | ||
Default: `window.location.hostname` | ||
Set this if you are running webpack on a host other than `window.location.hostname`. This is used by the error overlay module. | ||
Set this if you are running webpack on a host other than `window.location.hostname`. | ||
This will be used by the error overlay module, and is available for `webpack-dev-server` only. | ||
### `options.sockPort` | ||
#### `options.overlay.sockIntegration` | ||
Type: `wds` or `whm` or `string` | ||
Default: `wds` | ||
This controls how the error overlay connects to the sockets provided by several Webpack hot reload integrations. | ||
- If you use `webpack-dev-server`, you don't need to set this as it defaults to `wds`. | ||
- If you use `webpack-hot-middleware`, you should set this to `whm`. | ||
- If you use anything else, you will have to provide a path to a module that will accept a message handler function and initializes the socket connection. | ||
See the [`runtime/sockets`](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/master/src/runtime/sockets) folder for sample implementations. | ||
#### `options.overlay.sockPort` | ||
Type: `number` | ||
Default: effectively `window.location.port` | ||
Default: `window.location.port` | ||
Set this if you are running webpack on a port other than `window.location.port` | ||
Set this if you are running webpack on a port other than `window.location.port`. | ||
This will be used by the error overlay module, and is available for `webpack-dev-server` only. | ||
### `options.sockPath` | ||
#### `options.overlay.sockPath` | ||
@@ -212,2 +227,5 @@ Type: `string` | ||
Set this if you are running webpack on a custom path. | ||
This will be used by the error overlay module, and is available for `webpack-dev-server` only. | ||
### `options.useLegacyWDSSockets` | ||
@@ -214,0 +232,0 @@ |
const createRefreshTemplate = require('./createRefreshTemplate'); | ||
const getSocketIntegration = require('./getSocketIntegration'); | ||
const injectRefreshEntry = require('./injectRefreshEntry'); | ||
@@ -7,4 +8,5 @@ const validateOptions = require('./validateOptions'); | ||
createRefreshTemplate, | ||
getSocketIntegration, | ||
injectRefreshEntry, | ||
validateOptions, | ||
}; |
@@ -0,1 +1,3 @@ | ||
const querystring = require('querystring'); | ||
/** @typedef {string | string[] | import('webpack').Entry} StaticEntry */ | ||
@@ -10,14 +12,25 @@ /** @typedef {StaticEntry | import('webpack').EntryFunc} WebpackEntry */ | ||
*/ | ||
const injectRefreshEntry = (originalEntry, options) => { | ||
const sockHost = options.sockHost ? `&sockHost=${options.sockHost}` : ''; | ||
const sockPort = options.sockPort ? `&sockPort=${options.sockPort}` : ''; | ||
const sockPath = options.sockPath ? `&sockPath=${options.sockPath}` : ''; | ||
const queryParams = `?options${sockHost}${sockPort}${sockPath}`; | ||
const entryInjects = [ | ||
// Legacy WDS SockJS integration | ||
options.useLegacyWDSSockets && require.resolve('../runtime/LegacyWebpackDevServerSocket'), | ||
function injectRefreshEntry(originalEntry, options) { | ||
let resourceQuery = {}; | ||
if (options.overlay) { | ||
options.overlay.sockHost && (resourceQuery.sockHost = options.overlay.sockHost); | ||
options.overlay.sockPath && (resourceQuery.sockPath = options.overlay.sockPath); | ||
options.overlay.sockPort && (resourceQuery.sockPort = options.overlay.sockPort); | ||
} | ||
// We don't need to URI encode the resourceQuery as it will be parsed by Webpack | ||
const queryString = querystring.stringify(resourceQuery, null, null, { | ||
encodeURIComponent: (string) => string, | ||
}); | ||
const prependEntries = [ | ||
// React-refresh runtime | ||
require.resolve('../runtime/ReactRefreshEntry'), | ||
]; | ||
const appendEntries = [ | ||
// Legacy WDS SockJS integration | ||
options.useLegacyWDSSockets && require.resolve('../runtime/LegacyWDSSocketEntry'), | ||
// Error overlay runtime | ||
options.overlay && options.overlay.entry + queryParams, | ||
options.overlay && options.overlay.entry + (queryString && `?${queryString}`), | ||
].filter(Boolean); | ||
@@ -27,7 +40,7 @@ | ||
if (typeof originalEntry === 'string') { | ||
return [...entryInjects, originalEntry]; | ||
return [...prependEntries, originalEntry, ...appendEntries]; | ||
} | ||
// Single array entry point | ||
if (Array.isArray(originalEntry)) { | ||
return [...entryInjects, ...originalEntry]; | ||
return [...prependEntries, ...originalEntry, ...appendEntries]; | ||
} | ||
@@ -53,4 +66,4 @@ // Multiple entry points | ||
throw new Error('Failed to parse the Webpack `entry` object!'); | ||
}; | ||
} | ||
module.exports = injectRefreshEntry; |
@@ -1,13 +0,39 @@ | ||
/** @type {import('../types').ReactRefreshPluginOptions} */ | ||
const defaultOptions = { | ||
forceEnable: false, | ||
useLegacyWDSSockets: false, | ||
}; | ||
const { defaultOptions, defaultOverlayOptions } = require('./defaults'); | ||
/** @type {import('../types').ErrorOverlayOptions} */ | ||
const defaultOverlayOptions = { | ||
entry: require.resolve('../runtime/ErrorOverlayEntry'), | ||
module: require.resolve('../overlay'), | ||
}; | ||
function isBooleanOrUndefined(name, value) { | ||
const valueType = typeof value; | ||
if (valueType !== 'undefined' && valueType !== 'boolean') { | ||
throw new Error( | ||
[ | ||
`The "${name}" option, if defined, must be a boolean value.`, | ||
`Instead received: "${valueType}".`, | ||
].join('\n') | ||
); | ||
} | ||
} | ||
function isNumberOrUndefined(name, value) { | ||
const valueType = typeof value; | ||
if (valueType !== 'undefined' && valueType !== 'number') { | ||
throw new Error( | ||
[ | ||
`The "${name}" option, if defined, must be a number.`, | ||
`Instead received: "${valueType}".`, | ||
].join('\n') | ||
); | ||
} | ||
} | ||
function isStringOrUndefined(name, value) { | ||
const valueType = typeof value; | ||
if (valueType !== 'undefined' && valueType !== 'string') { | ||
throw new Error( | ||
[ | ||
`The "${name}" option, if defined, must be a string.`, | ||
`Instead received: "${valueType}".`, | ||
].join('\n') | ||
); | ||
} | ||
} | ||
/** | ||
@@ -18,6 +44,5 @@ * Validates the options for the plugin. | ||
*/ | ||
module.exports = function validateOptions(options) { | ||
const validatedOptions = Object.assign(defaultOptions, options); | ||
if (typeof validatedOptions.disableRefreshCheck !== 'undefined') { | ||
function validateOptions(options) { | ||
// Show deprecation notice and remove the option before any processing | ||
if (typeof options.disableRefreshCheck !== 'undefined') { | ||
console.warn( | ||
@@ -29,27 +54,63 @@ [ | ||
); | ||
delete validatedOptions.disableRefreshCheck; | ||
delete options.disableRefreshCheck; | ||
} | ||
isBooleanOrUndefined('forceEnable', options.forceEnable); | ||
isBooleanOrUndefined('useLegacyWDSSockets', options.useLegacyWDSSockets); | ||
const overlayValueType = typeof options.overlay; | ||
if ( | ||
typeof validatedOptions.overlay !== 'undefined' && | ||
typeof validatedOptions.overlay !== 'boolean' | ||
// Not undefined | ||
overlayValueType !== 'undefined' && | ||
// Not a boolean | ||
overlayValueType !== 'boolean' && | ||
// Not a function ([object Function]) | ||
overlayValueType !== 'function' && | ||
// Not an object ([object *]) or is null | ||
(overlayValueType !== 'object' || options.overlay === null) | ||
) { | ||
if (typeof validatedOptions.overlay.module !== 'string') { | ||
throw new Error( | ||
`To use the "overlay" option, a string must be provided in the "module" property. Instead, the provided value has type: "${typeof options | ||
.overlay.module}".` | ||
); | ||
} | ||
throw new Error( | ||
[ | ||
`The "overlay" option, if defined, must be one of: boolean or object.`, | ||
`Instead received: "${overlayValueType}".`, | ||
].join('\n') | ||
); | ||
} | ||
validatedOptions.overlay = { | ||
entry: options.overlay.entry || defaultOverlayOptions.entry, | ||
module: options.overlay.module, | ||
const defaultedOptions = Object.assign(defaultOptions, options); | ||
if ( | ||
typeof defaultedOptions.overlay !== 'undefined' && | ||
typeof defaultedOptions.overlay !== 'boolean' | ||
) { | ||
const { | ||
entry, | ||
module: overlayModule, | ||
sockHost, | ||
sockIntegration, | ||
sockPath, | ||
sockPort, | ||
} = defaultedOptions.overlay; | ||
isStringOrUndefined('overlay.entry', entry); | ||
isStringOrUndefined('overlay.module', overlayModule); | ||
isStringOrUndefined('overlay.sockHost', sockHost); | ||
isStringOrUndefined('overlay.sockIntegration', sockIntegration); | ||
isStringOrUndefined('overlay.sockPath', sockPath); | ||
isNumberOrUndefined('overlay.sockPort', sockPort); | ||
defaultedOptions.overlay = { | ||
...defaultedOptions.overlay, | ||
entry: entry || defaultOverlayOptions.entry, | ||
module: overlayModule || defaultOverlayOptions.module, | ||
sockIntegration: sockIntegration || defaultOverlayOptions.sockIntegration, | ||
}; | ||
} else { | ||
validatedOptions.overlay = | ||
(typeof validatedOptions.overlay === 'undefined' || validatedOptions.overlay) && | ||
defaultedOptions.overlay = | ||
(typeof defaultedOptions.overlay === 'undefined' || defaultedOptions.overlay) && | ||
defaultOverlayOptions; | ||
} | ||
return validatedOptions; | ||
}; | ||
return defaultedOptions; | ||
} | ||
module.exports = validateOptions; |
const path = require('path'); | ||
const webpack = require('webpack'); | ||
const { createRefreshTemplate, injectRefreshEntry, validateOptions } = require('./helpers'); | ||
const { errorOverlay, refreshUtils } = require('./runtime/globals'); | ||
const { | ||
createRefreshTemplate, | ||
getSocketIntegration, | ||
injectRefreshEntry, | ||
validateOptions, | ||
} = require('./helpers'); | ||
const { errorOverlay, initSocket, refreshUtils } = require('./runtime/globals'); | ||
@@ -12,3 +17,3 @@ class ReactRefreshPlugin { | ||
constructor(options) { | ||
this.options = validateOptions(options); | ||
this.options = validateOptions(options || {}); | ||
} | ||
@@ -43,2 +48,3 @@ | ||
[errorOverlay]: require.resolve(this.options.overlay.module), | ||
[initSocket]: getSocketIntegration(this.options.overlay.sockIntegration), | ||
}), | ||
@@ -45,0 +51,0 @@ }); |
@@ -1,5 +0,3 @@ | ||
/* global __resourceQuery, __react_refresh_error_overlay__ */ | ||
/* global __resourceQuery, __react_refresh_error_overlay__, __react_refresh_init_socket__ */ | ||
const formatWebpackErrors = require('./formatWebpackErrors'); | ||
const createSocket = require('./createSocket'); | ||
const { | ||
@@ -9,2 +7,3 @@ error: registerErrorHandler, | ||
} = require('./errorEventHandlers'); | ||
const formatWebpackErrors = require('./formatWebpackErrors'); | ||
@@ -77,7 +76,10 @@ // Setup error states | ||
if (__resourceQuery) { | ||
overrides = require('querystring').parse(__resourceQuery.slice(1)); | ||
const searchParams = new URLSearchParams(__resourceQuery.slice(1)); | ||
searchParams.forEach(function (value, key) { | ||
overrides[key] = value; | ||
}); | ||
} | ||
// Registers handlers for compile errors | ||
createSocket(compileMessageHandler, overrides); | ||
__react_refresh_init_socket__(compileMessageHandler, overrides); | ||
// Registers handlers for runtime errors | ||
@@ -84,0 +86,0 @@ registerErrorHandler(function handleError(error) { |
@@ -1,3 +0,5 @@ | ||
module.exports.errorOverlay = '__react_refresh_error_overlay__'; | ||
module.exports.refreshUtils = '__react_refresh_utils__'; | ||
module.exports = { | ||
errorOverlay: '__react_refresh_error_overlay__', | ||
initSocket: '__react_refresh_init_socket__', | ||
refreshUtils: '__react_refresh_utils__', | ||
}; |
/** | ||
* @typedef {Object} ErrorOverlayOptions | ||
* @property {string} [entry] Path to a JS file that sets up the error overlay integration. | ||
* @property {string} module The error overlay module to use. | ||
* @property {string} [module] The error overlay module to use. | ||
* @property {string} [sockHost] The socket host to use. | ||
* @property {'wds' | 'whm' | string} [sockIntegration] Path to a JS file that sets up the Webpack socket integration. | ||
* @property {string} [sockPath] The socket path to use. | ||
* @property {number} [sockPort] The socket port to use. | ||
*/ | ||
@@ -12,5 +16,2 @@ | ||
* @property {boolean | ErrorOverlayOptions} [overlay] Modifies how the error overlay integration works in the plugin. | ||
* @property {string} [sockHost] The socket host to use for the error overlay integration. | ||
* @property {string} [sockPath] The socket path to use for the error overlay integration. | ||
* @property {number} [sockPort] The socket port to use for the error overlay integration. | ||
* @property {boolean} [useLegacyWDSSockets] Uses a custom SocketJS implementation for older versions of webpack-dev-server. | ||
@@ -17,0 +18,0 @@ */ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
71334
35
1715
237
5