@pmmmwh/react-refresh-webpack-plugin
Advanced tools
Comparing version 0.5.4 to 0.5.5
@@ -0,1 +1,17 @@ | ||
## 0.5.5 (4 April 2022) | ||
### Fixes | ||
- Handle unknown `moduleId` for dynamically generated modules (#547) | ||
- Handle WDS `auto` value on `port` (#574) | ||
- Fixed `react-refresh@0.12.0` compatibility (#576) | ||
- Fixed crash when parsing compile errors in overlay (#577) | ||
- Respect virtual modules when injecting loader (#593) | ||
- Allow `port` to be missing for WDS, also some general refactoring (#623) | ||
### Internal | ||
- A couple documentation changes in README (#575, 8c39623, #597) | ||
- Bumped dependencies for testing infrastructure (#526, #564, #567, #581, #588, #591, #594, #616) | ||
## 0.5.4 (22 December 2021) | ||
@@ -2,0 +18,0 @@ |
/* global __react_refresh_library__ */ | ||
const safeThis = require('core-js-pure/features/global-this.js'); | ||
const RefreshRuntime = require('react-refresh/runtime.js'); | ||
const safeThis = require('core-js-pure/features/global-this'); | ||
const RefreshRuntime = require('react-refresh/runtime'); | ||
@@ -6,0 +6,0 @@ if (process.env.NODE_ENV !== 'production') { |
@@ -10,4 +10,15 @@ /* global __webpack_require__ */ | ||
function getModuleExports(moduleId) { | ||
if (typeof moduleId === 'undefined') { | ||
// `moduleId` is unavailable, which indicates that this module is not in the cache, | ||
// which means we won't be able to capture any exports, | ||
// and thus they cannot be refreshed safely. | ||
// These are likely runtime or dynamically generated modules. | ||
return {}; | ||
} | ||
var maybeModule = __webpack_require__.c[moduleId]; | ||
if (typeof maybeModule === 'undefined') { | ||
// `moduleId` is available but the module in cache is unavailable, | ||
// which indicates the module is somehow corrupted (e.g. broken Webpacak `module` globals). | ||
// We will warn the user (as this is likely a mistake) and assume they cannot be refreshed. | ||
console.warn('[React Refresh] Failed to get exports for module: ' + moduleId + '.'); | ||
@@ -14,0 +25,0 @@ return {}; |
@@ -48,3 +48,3 @@ const querystring = require('querystring'); | ||
if (parsedUrl.port != null) { | ||
port = String(parsedUrl.port) !== '0' ? parsedUrl.port : undefined; | ||
port = !['0', 'auto'].includes(String(parsedUrl.port)) ? parsedUrl.port : undefined; | ||
} | ||
@@ -51,0 +51,0 @@ if (parsedUrl.protocol != null) { |
@@ -28,3 +28,3 @@ const path = require('path'); | ||
// Include and exclude user-specified files | ||
match(moduleData.resource) && | ||
match(moduleData.matchResource || moduleData.resource) && | ||
// Exclude files referenced as assets | ||
@@ -31,0 +31,0 @@ !moduleData.type.includes('asset') && |
@@ -20,3 +20,3 @@ // This is a patch for mozilla/source-map#349 - | ||
const RefreshRuntimePath = require | ||
.resolve('react-refresh/runtime.js') | ||
.resolve('react-refresh') | ||
.replace(/\\/g, '/') | ||
@@ -23,0 +23,0 @@ .replace(/'/g, "\\'"); |
@@ -23,7 +23,2 @@ const ansiHTML = require('ansi-html-community'); | ||
if (errorParts.length) { | ||
const errorMessage = errorParts | ||
.splice(1, 1)[0] | ||
// Strip filename from the error message | ||
.replace(/^(.*:)\s.*:(\s.*)$/, '$1$2'); | ||
if (errorParts[0]) { | ||
@@ -33,3 +28,7 @@ errorParts[0] = utils.formatFilename(errorParts[0]); | ||
errorParts.unshift(errorMessage); | ||
const errorMessage = errorParts.splice(1, 1)[0]; | ||
if (errorMessage) { | ||
// Strip filename from the error message | ||
errorParts.unshift(errorMessage.replace(/^(.*:)\s.*:(\s.*)$/, '$1$2')); | ||
} | ||
} | ||
@@ -36,0 +35,0 @@ |
{ | ||
"name": "@pmmmwh/react-refresh-webpack-plugin", | ||
"version": "0.5.4", | ||
"version": "0.5.5", | ||
"description": "An **EXPERIMENTAL** Webpack plugin to enable \"Fast Refresh\" (also previously known as _Hot Reloading_) for React components.", | ||
@@ -44,4 +44,5 @@ "keywords": [ | ||
"test:exec": "node scripts/test.js", | ||
"test:post": "yalc remove --all", | ||
"test:post": "yarn yalc:clean", | ||
"yalc:add": "yalc add --dev @pmmmwh/react-refresh-webpack-plugin", | ||
"yalc:clean": "yalc remove --all", | ||
"yalc:publish": "yalc publish --no-scripts", | ||
@@ -55,4 +56,4 @@ "lint": "eslint --report-unused-disable-directives --ext .js,.jsx .", | ||
"types:prune-private": "del \"types/*/*\" \"!types/{lib,loader,options}/{index,types}.d.ts\"", | ||
"generate-types": "run-s types:compile types:prune-private \"format --loglevel silent\"", | ||
"prepublishOnly": "run-s types:clean generate-types" | ||
"generate-types": "run-s types:clean types:compile types:prune-private \"format --loglevel silent\"", | ||
"prepublishOnly": "yarn generate-types" | ||
}, | ||
@@ -78,30 +79,28 @@ "dependencies": { | ||
"@types/module-alias": "^2.0.0", | ||
"@types/node": "^16.0.0", | ||
"@types/puppeteer": "^5.4.0", | ||
"@types/node": "^17.0.8", | ||
"@types/semver": "^7.3.9", | ||
"@types/webpack": "^5.28.0", | ||
"babel-jest": "^27.0.5", | ||
"babel-loader": "^8.1.0", | ||
"cross-env": "^7.0.3", | ||
"cross-spawn": "^7.0.3", | ||
"del-cli": "^3.0.1", | ||
"eslint": "^7.26.0", | ||
"del-cli": "^4.0.1", | ||
"eslint": "^8.6.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"eslint-plugin-prettier": "^3.4.0", | ||
"fs-extra": "^9.0.1", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"fs-extra": "^10.0.0", | ||
"get-port": "^5.1.1", | ||
"jest": "^27.0.5", | ||
"jest-environment-node": "^27.0.5", | ||
"jest-junit": "^12.2.0", | ||
"jest-watch-typeahead": "^0.6.4", | ||
"jest-junit": "^13.0.0", | ||
"memfs": "^3.2.0", | ||
"module-alias": "^2.2.2", | ||
"nanoid": "^3.1.23", | ||
"nanoid": "^3.1.31", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.3.0", | ||
"puppeteer": "^9.1.1", | ||
"react-refresh": "^0.11.0", | ||
"puppeteer": "^13.4.0", | ||
"react-refresh": "^0.12.0", | ||
"semver": "^7.3.5", | ||
"sourcemap-validator": "^2.1.0", | ||
"type-fest": "^1.4.0", | ||
"typescript": "4.4.3", | ||
"type-fest": "^2.9.0", | ||
"typescript": "4.5.5", | ||
"webpack": "^5.42.0", | ||
@@ -149,3 +148,3 @@ "webpack-cli": "^4.7.2", | ||
"resolutions": { | ||
"type-fest": "1.4.0" | ||
"type-fest": "2.12.2" | ||
}, | ||
@@ -152,0 +151,0 @@ "engines": { |
@@ -112,3 +112,3 @@ # React Refresh Webpack Plugin | ||
For most setups, we recommend integrate using `babel-loader`. | ||
For most setups, we recommend integrating with `babel-loader`. | ||
It covers the most use cases and is officially supported by the React team. | ||
@@ -196,4 +196,3 @@ | ||
> | ||
> Even though both the Babel transform (`react-refresh/babel`) and this plugin have optimisations to do nothing in `production`, | ||
> it is suggested to only have them both enabled in `development` mode to prevent shipping any additional code accidentally. | ||
> Ensure both the Babel transform (`react-refresh/babel`) and this plugin are enabled only in `development` mode! | ||
@@ -225,2 +224,3 @@ <details> | ||
```js | ||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); | ||
const ReactRefreshTypeScript = require('react-refresh-typescript'); | ||
@@ -231,2 +231,3 @@ | ||
module.exports = { | ||
mode: isDevelopment ? 'development' : 'production', | ||
module: { | ||
@@ -251,2 +252,3 @@ rules: [ | ||
}, | ||
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean), | ||
}; | ||
@@ -274,3 +276,8 @@ ``` | ||
```js | ||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); | ||
const isDevelopment = process.env.NODE_ENV !== 'production'; | ||
module.exports = { | ||
mode: isDevelopment ? 'development' : 'production', | ||
module: { | ||
@@ -299,2 +306,3 @@ rules: [ | ||
}, | ||
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean), | ||
}; | ||
@@ -301,0 +309,0 @@ ``` |
@@ -9,3 +9,3 @@ const getCurrentScriptSource = require('./getCurrentScriptSource.js'); | ||
* @property {string} pathname | ||
* @property {string} port | ||
* @property {string} [port] | ||
*/ | ||
@@ -25,46 +25,9 @@ | ||
const scriptSource = getCurrentScriptSource(); | ||
/** @type {SocketUrlParts} */ | ||
let urlParts = {}; | ||
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` | ||
} | ||
/** @type {string | undefined} */ | ||
let auth; | ||
/** @type {string | undefined} */ | ||
let hostname = url.hostname; | ||
/** @type {string | undefined} */ | ||
let protocol = url.protocol; | ||
/** @type {string | undefined} */ | ||
let port = url.port; | ||
// This is hard-coded in WDS v3 | ||
let pathname = '/sockjs-node'; | ||
if (metadata.version === 4) { | ||
// This is hard-coded in WDS v4 | ||
pathname = '/ws'; | ||
} | ||
// 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> | ||
auth = url.username; | ||
if (url.password) { | ||
auth += ':' + url.password; | ||
} | ||
} | ||
// If the resource query is available, | ||
// parse it and overwrite everything we received from the script host. | ||
const parsedQuery = {}; | ||
// parse it and ignore everything we received from the script host. | ||
if (resourceQuery) { | ||
const parsedQuery = {}; | ||
const searchParams = new URLSearchParams(resourceQuery.slice(1)); | ||
@@ -74,17 +37,60 @@ searchParams.forEach(function (value, key) { | ||
}); | ||
} | ||
hostname = parsedQuery.sockHost || hostname; | ||
pathname = parsedQuery.sockPath || pathname; | ||
port = parsedQuery.sockPort || port; | ||
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) { | ||
protocol = parsedQuery.sockProtocol + ':'; | ||
// 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; | ||
} | ||
// Check for IPv4 and IPv6 host addresses that corresponds to any/empty. | ||
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 = hostname === '0.0.0.0' || hostname === '[::]' || !hostname; | ||
const isEmptyHostname = | ||
urlParts.hostname === '0.0.0.0' || urlParts.hostname === '[::]' || !urlParts.hostname; | ||
// We only re-assign the hostname if it is empty, | ||
@@ -95,20 +101,25 @@ // and if we are using HTTP/HTTPS protocols. | ||
window.location.hostname && | ||
window.location.protocol.indexOf('http') !== -1 | ||
window.location.protocol.indexOf('http') === 0 | ||
) { | ||
hostname = window.location.hostname; | ||
urlParts.hostname = window.location.hostname; | ||
} | ||
// We only re-assign `protocol` when `hostname` is available and is empty, | ||
// 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 'https' is used as it mandates the use of secure sockets. | ||
if (hostname && (isEmptyHostname || window.location.protocol === 'https:')) { | ||
protocol = window.location.protocol; | ||
if ( | ||
!urlParts.protocol || | ||
(urlParts.hostname && (isEmptyHostname || window.location.protocol === 'https:')) | ||
) { | ||
urlParts.protocol = window.location.protocol; | ||
} | ||
// We only re-assign port when it is not available | ||
if (!port) { | ||
port = window.location.port; | ||
if (!urlParts.port) { | ||
urlParts.port = window.location.port; | ||
} | ||
if (!hostname || !pathname || !port) { | ||
if (!urlParts.hostname || !urlParts.pathname) { | ||
console.log(urlParts); | ||
throw new Error( | ||
@@ -125,7 +136,7 @@ [ | ||
return { | ||
auth: auth, | ||
hostname: hostname, | ||
pathname: pathname, | ||
protocol: protocol, | ||
port: port, | ||
auth: urlParts.auth, | ||
hostname: urlParts.hostname, | ||
pathname: urlParts.pathname, | ||
protocol: urlParts.protocol, | ||
port: urlParts.port || undefined, | ||
}; | ||
@@ -132,0 +143,0 @@ } |
/* global ʎɐɹɔosǝʌɹǝs */ | ||
const { ClientSocket } = require('webpack-plugin-serve/lib/client/ClientSocket.js'); | ||
const { ClientSocket } = require('webpack-plugin-serve/lib/client/ClientSocket'); | ||
@@ -4,0 +4,0 @@ /** |
137617
43
3107
349