diff --git a/.gitignore b/.gitignore
index 66028cb2..206be3ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
# distribution
*dist
+*umd
# misc
.DS_Store
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36be6840..270569d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,10 @@
It was necessary to support WDS below `4.8.0` (published in April 2022),
but is no-longer needed as a direct integration with WDS is now possible.
+### Features
+
+- Added helper script to better support use cases where React and/or React-DOM are externalized (#852)
+
## 0.5.15 (3 Jun 2024)
### Fixes
diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md
index c4882566..e2295a0f 100644
--- a/docs/TROUBLESHOOTING.md
+++ b/docs/TROUBLESHOOTING.md
@@ -268,9 +268,21 @@ but do note that React DevTools does not inject hooks over a frame boundary (`if
**Externalise React Refresh**
If all solutions above are not applicable, you can also externalise `react-refresh/runtime` together with React.
+We provide an entrypoint to easily achieve this - `@pmmmwh/react-refresh-webpack-plugin/umd/client.min.js`.
-Using this, however, would require you to ensure the injected entry from this plugin is executed before React.
-You can check out [this sandbox](https://codesandbox.io/s/react-refresh-externals-14fpn) for an example on how this could be done.
+If you would like to use the provided script, ensure that it is loaded before React and/or React-DOM.
+You can load this script via any CDN for `npm`, such as `jsDelivr` and `unpkg`:
+
+```html
+
+
+
+
+
+```
+
+If you don't want to use the provided script,
+you can check out [this sandbox](https://codesandbox.io/s/react-refresh-externals-14fpn) for an example on how this could be done manually.
## Running multiple instances of React Refresh simultaneously
diff --git a/package.json b/package.json
index b4584f66..c3c21a06 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,8 @@
"options",
"overlay",
"sockets",
- "types"
+ "types",
+ "umd"
],
"packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610",
"scripts": {
@@ -54,8 +55,9 @@
"types:clean": "rimraf types",
"types:compile": "tsc -p tsconfig.json",
"types:prune-private": "del \"types/*/*\" \"!types/{lib,loader,options}/{index,types}.d.ts\"",
- "generate-types": "run-s types:clean types:compile types:prune-private \"format --loglevel silent\"",
- "prepublishOnly": "yarn generate-types"
+ "generate:client-external": "webpack",
+ "generate:types": "run-s types:clean types:compile types:prune-private \"format --log-level silent\"",
+ "prepublishOnly": "run-p generate:*"
},
"dependencies": {
"ansi-html": "^0.0.9",
@@ -97,6 +99,7 @@
"puppeteer": "^22.10.0",
"react-refresh": "^0.14.2",
"sourcemap-validator": "^2.1.0",
+ "terser-webpack-plugin": "^5.3.10",
"type-fest": "^4.18.3",
"typescript": "~5.4.5",
"webpack": "^5.91.0",
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 00000000..f685ac78
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,25 @@
+const path = require('node:path');
+const TerserPlugin = require('terser-webpack-plugin');
+
+module.exports = {
+ mode: 'production',
+ entry: {
+ client: './client/ReactRefreshEntry.js',
+ },
+ optimization: {
+ minimize: true,
+ minimizer: [
+ new TerserPlugin({
+ extractComments: false,
+ terserOptions: {
+ format: { comments: false },
+ },
+ }),
+ ],
+ nodeEnv: 'development',
+ },
+ output: {
+ filename: '[name].min.js',
+ path: path.resolve(__dirname, 'umd'),
+ },
+};