@pmmmwh/react-refresh-webpack-plugin
Advanced tools
Comparing version 0.4.1 to 0.4.2
@@ -0,1 +1,8 @@ | ||
## 0.4.2 (3 September 2020) | ||
### Fixes | ||
- Patched loader to use with Node.js global `fetch` polyfills (#193) | ||
- Patched default `include` and `exclude` options to be case-insensitive (#194) | ||
## 0.4.1 (28 July 2020) | ||
@@ -2,0 +9,0 @@ |
@@ -49,4 +49,4 @@ /** | ||
d(options, 'exclude', /node_modules/); | ||
d(options, 'include', /\.([jt]sx?|flow)$/); | ||
d(options, 'exclude', /node_modules/i); | ||
d(options, 'include', /\.([jt]sx?|flow)$/i); | ||
d(options, 'forceEnable'); | ||
@@ -53,0 +53,0 @@ |
@@ -0,1 +1,8 @@ | ||
// This is a patch for mozilla/source-map#349 - | ||
// internally, it uses the existence of the `fetch` global to toggle browser behaviours. | ||
// That check, however, will break when `fetch` polyfills are used for SSR setups. | ||
// We "reset" the polyfill here to ensure it won't interfere with source-map generation. | ||
const originalFetch = global.fetch; | ||
delete global.fetch; | ||
const { SourceMapConsumer, SourceMapGenerator, SourceNode } = require('source-map'); | ||
@@ -95,1 +102,6 @@ const { Template } = require('webpack'); | ||
module.exports = ReactRefreshLoader; | ||
// Restore the original value of the `fetch` global, if it exists | ||
if (originalFetch) { | ||
global.fetch = originalFetch; | ||
} |
{ | ||
"name": "@pmmmwh/react-refresh-webpack-plugin", | ||
"version": "0.4.1", | ||
"version": "0.4.2", | ||
"description": "An **EXPERIMENTAL** Webpack plugin to enable \"Fast Refresh\" (also previously known as _Hot Reloading_) for React components.", | ||
@@ -39,3 +39,3 @@ "keywords": [ | ||
"scripts": { | ||
"pretest": "patch-package && yarn link && yarn link \"@pmmmwh/react-refresh-webpack-plugin\"", | ||
"pretest": "yarn link && yarn link \"@pmmmwh/react-refresh-webpack-plugin\"", | ||
"posttest": "yarn unlink \"@pmmmwh/react-refresh-webpack-plugin\"", | ||
@@ -60,5 +60,5 @@ "test": "node scripts/test.js", | ||
"devDependencies": { | ||
"@babel/core": "^7.10.5", | ||
"@babel/core": "^7.11.0", | ||
"@types/json-schema": "^7.0.5", | ||
"@types/node": "^14.0.26", | ||
"@types/node": "^14.0.27", | ||
"@types/puppeteer": "^3.0.1", | ||
@@ -69,3 +69,3 @@ "@types/webpack": "^4.41.21", | ||
"cross-spawn": "^7.0.3", | ||
"eslint": "^7.5.0", | ||
"eslint": "^7.6.0", | ||
"eslint-config-prettier": "^6.11.0", | ||
@@ -75,10 +75,9 @@ "eslint-plugin-prettier": "^3.1.4", | ||
"get-port": "^5.1.1", | ||
"jest": "^26.1.0", | ||
"jest-circus": "^26.1.0", | ||
"jest-environment-node": "^26.1.0", | ||
"jest": "^26.2.2", | ||
"jest-circus": "^26.2.2", | ||
"jest-environment-node": "^26.2.0", | ||
"jest-junit": "^11.1.0", | ||
"jest-watch-typeahead": "^0.6.0", | ||
"memfs": "^3.2.0", | ||
"nanoid": "^3.1.11", | ||
"patch-package": "^6.2.2", | ||
"nanoid": "^3.1.12", | ||
"prettier": "^2.0.5", | ||
@@ -91,3 +90,3 @@ "puppeteer": "^5.2.1", | ||
"typescript": "3.9.7", | ||
"webpack": "^4.44.0", | ||
"webpack": "^4.44.1", | ||
"webpack-cli": "^3.3.12", | ||
@@ -94,0 +93,0 @@ "webpack-cli.beta": "npm:webpack-cli@^4.0.0-beta.8", |
264
README.md
@@ -5,2 +5,3 @@ # React Refresh Webpack Plugin | ||
[![Next Version](https://img.shields.io/npm/v/@pmmmwh/react-refresh-webpack-plugin/next)](https://www.npmjs.com/package/@pmmmwh/react-refresh-webpack-plugin/v/next) | ||
[![CircleCI](https://img.shields.io/circleci/project/github/pmmmwh/react-refresh-webpack-plugin/main)](https://app.circleci.com/pipelines/github/pmmmwh/react-refresh-webpack-plugin) | ||
[![License](https://img.shields.io/github/license/pmmmwh/react-refresh-webpack-plugin)](./LICENSE) | ||
@@ -10,7 +11,31 @@ | ||
## Prerequisites | ||
First and foremost, this plugin is not 100% stable. | ||
We're working towards a stable v1 release, and we've been testing the plugin quite extensively; | ||
but since it is still pretty young, there might still be some unknown edge cases. | ||
There are no breaking changes planned for the v1 release, | ||
but they might still happen if we hit some significant road blockers. | ||
Also, ensure that you are using the minimum supported versions of the plugin's peer dependencies - | ||
older versions unfortunately do not contain code to orchestrate "Fast Refresh", | ||
and thus cannot be made compatible. | ||
| Dependency | Minimum | Best | | ||
| ------------------ | -------------------------------------------------- | ---------- | | ||
| `react` | `16.9.0` | `16.13.0`+ | | ||
| `react-dom` | `16.9.0` | `16.13.0`+ | | ||
| `react-reconciler` | `0.22.0` | `0.25.0`+ | | ||
| `webpack` | `4.0.0` (for `0.3.x`)<br />`4.43.0` (for `0.4.x`+) | `4.43.0`+ | | ||
> You only need `react-dom` if you're rendering to the DOM. | ||
> You only need to check for `react-reconciler` if you use custom reconcilers like `react-three-fiber`. | ||
> You should check their `package.json` to make sure they use a compatible version instead of installing `react-reconciler` yourself. | ||
> If the reconcilers are not compatible, please create an issue at their repository. | ||
## Installation | ||
First - this plugin is not 100% stable. | ||
It works pretty reliably, and we have been testing it for some time, but there are still edge cases yet to be discovered. | ||
Please **DO NOT** use it if you cannot afford to face breaking changes in the future. | ||
With all prerequisites met, you can install the plugin with one of the commands below: | ||
@@ -23,45 +48,43 @@ ```sh | ||
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh | ||
# if you prefer pnpm | ||
pnpm add -D @pmmmwh/react-refresh-webpack-plugin react-refresh | ||
``` | ||
## Usage | ||
The plugin depends on a package from the React team - `react-refresh`, | ||
so you will have to install and configure it separately as demonstrated in the [Usage](#usage) section, too. | ||
First, apply the plugin in your Webpack configuration as follows: | ||
### TypeScript | ||
**webpack.config.js** | ||
TypeScript support is available out-of-the-box for those who use `webpack.config.ts` :tada:! | ||
```js | ||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); | ||
// ... your other imports | ||
For that you will have to install `type-fest` as a development peer dependency with one of the commands below: | ||
// You can tie this to whatever mechanisms you are using to detect a development environment. | ||
// For example, as shown here, is to tie that to `NODE_ENV` - | ||
// Then if you run `NODE_ENV=production webpack`, the constant will be set to false. | ||
const isDevelopment = process.env.NODE_ENV !== 'production'; | ||
```sh | ||
# if you prefer npm | ||
npm install -D type-fest | ||
module.exports = { | ||
// It is suggested to run the plugin in development mode only | ||
// If you are an advanced user and would like to setup Webpack yourselves, | ||
// you can also use the `none` mode, | ||
// but you will need to set `forceEnable: true` in the plugin options. | ||
mode: isDevelopment ? 'development' : 'production', | ||
// ... other configurations | ||
plugins: [ | ||
// ... other plugins | ||
// You could also keep the plugin in your production config, | ||
// It will simply do nothing. | ||
isDevelopment && new ReactRefreshWebpackPlugin(), | ||
].filter(Boolean), | ||
}; | ||
# if you prefer yarn | ||
yarn add -D type-fest | ||
# if you prefer pnpm | ||
pnpm add -D type-fest | ||
``` | ||
Then, update your Babel configuration. | ||
This can either be done in your Webpack config (via options of `babel-loader`), or in the form of a `.babelrc`/`babel.config.js`. | ||
## Usage | ||
**webpack.config.js** (if you choose to inline the config) | ||
The most basic setup to enable "Fast Refresh" is to update your `webpack.config.js` (or `.ts`) as follows: | ||
```js | ||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); | ||
const webpack = require('webpack'); | ||
// ... your other imports | ||
const isDevelopment = process.env.NODE_ENV !== 'production'; | ||
module.exports = { | ||
// DO NOT apply the plugin in production mode! | ||
// It is suggested to run both `react-refresh/babel` and the plugin in the `development` mode only, | ||
// even though both of them have optimisations in place to do nothing in the `production` mode. | ||
// If you would like to override Webpack's defaults for modes, you can also use the `none` mode - | ||
// you then will need to set `forceEnable: true` in the plugin's options. | ||
mode: isDevelopment ? 'development' : 'production', | ||
@@ -72,4 +95,3 @@ module: { | ||
{ | ||
// for TypeScript, change the following to "\.[jt]sx?" | ||
test: /\.jsx?$/, | ||
test: /\.[jt]sx?$/, | ||
exclude: /node_modules/, | ||
@@ -82,4 +104,6 @@ use: [ | ||
// ... other options | ||
// DO NOT apply the Babel plugin in production mode! | ||
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean), | ||
plugins: [ | ||
// ... other plugins | ||
isDevelopment && require.resolve('react-refresh/babel'), | ||
].filter(Boolean), | ||
}, | ||
@@ -91,164 +115,52 @@ }, | ||
}, | ||
plugins: [ | ||
// ... other plugins | ||
isDevelopment && new webpack.HotModuleReplacementPlugin(), | ||
isDevelopment && new ReactRefreshWebpackPlugin(), | ||
].filter(Boolean), | ||
// ... other configuration options | ||
}; | ||
``` | ||
**.babelrc.js** (if you choose to extract the config) | ||
You might want to further tweak the configuration to accommodate your setup: | ||
```js | ||
module.exports = (api) => { | ||
// This caches the Babel config by environment. | ||
api.cache.using(() => process.env.NODE_ENV); | ||
return { | ||
// ... other options | ||
plugins: [ | ||
// ... other plugins | ||
// Applies the react-refresh Babel plugin on non-production modes only | ||
!api.env('production') && 'react-refresh/babel', | ||
].filter(Boolean), | ||
}; | ||
}; | ||
``` | ||
- `isDevelopment` | ||
More sample projects for common Webpack development setups are available in the [examples](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/examples) directory. | ||
In this example we've shown the simple way of splitting up `development` and `production` builds with the `NODE_ENV` environment variable. | ||
It will default to `true` (i.e. `development` mode) when `NODE_ENV` is not available from the environment. | ||
> Note 1: If you use `webpack.config.ts`, please also install `type-fest` as a peer dependency. | ||
In practice though, you might want to wire this up differently, | ||
like [using a function config](https://webpack.js.org/configuration/configuration-types/#exporting-a-function) or using multiple configuration files. | ||
> Note 2: If you are using TypeScript (instead of Babel) as a transpiler, you will still need to use `babel-loader` to process your source code. | ||
> Check out this [sample project](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/examples/typescript-without-babel) on how to set this up. | ||
- `webpack.HotModuleReplacamentPlugin` | ||
### Caveats | ||
If you use `webpack-dev-server` or `webpack-plugin-serve`, | ||
you can set `devServer.hot`/`devServer.hotOnly` and `hmr` to `true` respectively, | ||
instead of adding the HMR plugin to your plugin list. | ||
- Class components will be re-mounted on hot update. | ||
See [this comment](https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/112#issuecomment-642491198) for more background on why this is the case. | ||
- Unnamed components will fallback to full refresh. | ||
See [this comment](https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/82#issuecomment-624590282) for more info and why this is generally a bad idea. | ||
> Note: If you are using TypeScript (instead of Babel) as a transpiler, you will still need to use `babel-loader` to process your source code. | ||
> Check out this [sample project](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/examples/typescript-without-babel) on how to set this up. | ||
### Polyfill for Older Browsers | ||
### Integration Support for Overlay | ||
If you need to develop on IE11, you will need to polyfill the DOM URL API. | ||
This can be done by adding the following before any of your code in the main entry (either one is fine): | ||
Officially, `webpack-dev-server`, `webpack-hot-middleware` and `webpack-plugin-serve` aer supported out of the box - | ||
you just have to set the [`overlay.sockIntegration`](docs/API.md#sockintegration) option to match what you're using. | ||
**Using `url-polyfill`** | ||
For each of the integrations listed above, | ||
you can also take a look at the corresponding [sample projects](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/examples) for a better understanding of how things should be wired up. | ||
```js | ||
import 'url-polyfill'; | ||
``` | ||
## API | ||
**Using `core-js`** | ||
Please refer to [the API docs](docs/API.md) for all available options. | ||
```js | ||
import 'core-js/features/url'; | ||
import 'core-js/features/url-search-params'; | ||
``` | ||
## FAQs and Troubleshooting | ||
**Using `react-app-polyfill`** | ||
Please refer to [the Troubleshooting guide](docs/TROUBLESHOOTING.md) for FAQs and resolutions to common issues. | ||
```js | ||
import 'react-app-polyfill/ie11'; | ||
import 'react-app-polyfill/stable'; | ||
``` | ||
## License | ||
## Options | ||
This project is licensed under the terms of the [MIT License](/LICENSE). | ||
This plugin accepts a few options that are specifically targeted for advanced users. | ||
### `options.forceEnable` | ||
Type: `boolean` | ||
Default: `false` | ||
Enables the plugin forcefully. | ||
Useful if you want to use the plugin in production, or if you are using Webpack's `none` mode without `NODE_ENV`, for example. | ||
### `options.overlay` | ||
Type: `boolean | ErrorOverlayOptions` | ||
Default: `undefined` | ||
Modifies how the error overlay integration works in the plugin. | ||
- If `options.overlay` is not provided or is `true`, the plugin will use the bundled error overlay interation. | ||
- If `options.overlay` is `false`, it will disable the error overlay integration. | ||
- If an `ErrorOverlayOptions` object is provided: | ||
(**NOTE**: This is an advanced option that exists mostly for tools like `create-react-app` or `Next.js`) | ||
- An optional `module` property could be defined. | ||
If it is not defined, the bundled error overlay will be used. | ||
If it is `false`, it will disable the error overlay integration. | ||
If defined, it should reference a JS file that exports at least two functions with footprints as follows: | ||
```ts | ||
function handleRuntimeError(error: Error) {} | ||
function clearRuntimeErrors() {} | ||
``` | ||
- 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. | ||
If it is `false`, no error overlay entry will be injected. | ||
It expects the `module` file to export two more functions: | ||
```ts | ||
function showCompileError(webpackErrorMessage: string) {} | ||
function clearCompileErrors() {} | ||
``` | ||
Note that `webpackErrorMessage` is ANSI encoded, so you will need logic to parse it. | ||
- An example configuration: | ||
```js | ||
const options = { | ||
overlay: { | ||
entry: 'some-webpack-entry-file', | ||
module: 'some-error-overlay-module', | ||
}, | ||
}; | ||
``` | ||
#### `options.overlay.sockHost` | ||
Type: `string` | ||
Default: `window.location.hostname` | ||
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.overlay.sockIntegration` | ||
Type: `wds`, `whm`, `wps`, `false` 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 `webpack-plugin-serve`, you should set this to `wps`. | ||
- If you use anything else, or if you want to customize the socket handling yourself, you will have to provide a path to a module that will accept a message handler function and initializes the socket connection. | ||
See the [`sockets`](https://github.com/pmmmwh/react-refresh-webpack-plugin/tree/main/sockets) directory for sample implementations. | ||
#### `options.overlay.sockPort` | ||
Type: `number` | ||
Default: `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.overlay.sockPath` | ||
Type: `string` | ||
Default: `/sockjs-node` | ||
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.overlay.useLegacyWDSSockets` | ||
Type: `boolean` | ||
Default: `false` | ||
Set this to true if you are using a `webpack-dev-server` version prior to 3.8 as it requires a custom SockJS implementation. | ||
If you use this feature, you will also need to install `sockjs-client` as a peer dependency. | ||
## Related Work | ||
- [Initial Implementation by @maisano](https://gist.github.com/maisano/441a4bc6b2954205803d68deac04a716) |
35
2507
104177
161