Skip to content

Commit

Permalink
Add experimental react-refresh support (#8582)
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Schmitz <[email protected]>
  • Loading branch information
charrondev and ianschmitz authored Apr 6, 2020
1 parent e0b179c commit c5b96c2
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 4 deletions.
1 change: 1 addition & 0 deletions docusaurus/docs/advanced-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ You can adjust various development and production settings by setting environmen
| INLINE_RUNTIME_CHUNK | 🚫 Ignored | ✅ Used | By default, Create React App will embed the runtime script into `index.html` during the production build. When set to `false`, the script will not be embedded and will be imported as usual. This is normally required when dealing with CSP. |
| IMAGE_INLINE_SIZE_LIMIT | 🚫 Ignored | ✅ Used | By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images. |
| EXTEND_ESLINT | ✅ Used | ✅ Used | When set to `true`, user provided ESLint configs will be used by `eslint-loader`. Note that any rules set to `"error"` will stop the application from building. |
| FAST_REFRESH | ✅ Used | 🚫 Ignored | When set to `true`, enables experimental support for fast refresh to allow you to tweak your components in real time without reloading the page. |
| TSC_COMPILE_ON_ERROR | ✅ Used | ✅ Used | When set to `true`, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console. |
5 changes: 4 additions & 1 deletion packages/react-dev-utils/webpackHotDevClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,10 @@ function tryApplyUpdates(onHotUpdateSuccess) {
}

function handleApplyUpdates(err, updatedModules) {
if (err || !updatedModules || hadRuntimeError) {
const hasReactRefresh = process.env.FAST_REFRESH;
const wantsForcedReload = err || !updatedModules || hadRuntimeError;
// React refresh can handle hot-reloading over errors.
if (!hasReactRefresh && wantsForcedReload) {
window.location.reload();
return;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/react-scripts/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ function getClientEnvironment(publicUrl) {
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
// Whether or not react-refresh is enabled.
// react-refresh is not 100% stable at this time,
// which is why it's disabled by default.
// It is defined here so it is available in the webpackHotDevClient.
FAST_REFRESH: process.env.FAST_REFRESH || false,
}
);
// Stringify all values so we can feed into webpack DefinePlugin
Expand Down
22 changes: 22 additions & 0 deletions packages/react-scripts/config/hotRefreshOverlayModuleStub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// This file is currently required because the error overlay has a bug preventing the its outright disabling.

'use strict';

function handleRuntimeError() {
// Stubbed out due to a bug.
}
function clearRuntimeErrors() {
// Stubbed out due to a bug.
}

module.exports = {
handleRuntimeError,
clearRuntimeErrors,
};
31 changes: 28 additions & 3 deletions packages/react-scripts/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const typescriptFormatter = require('react-dev-utils/typescriptFormatter');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
// @remove-on-eject-begin
const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier');
// @remove-on-eject-end
Expand All @@ -41,6 +42,11 @@ const appPackageJson = require(paths.appPackageJson);

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';

const webpackDevClientEntry = require.resolve(
'react-dev-utils/webpackHotDevClient'
);

// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
Expand Down Expand Up @@ -77,6 +83,8 @@ module.exports = function(webpackEnv) {
// Get environment variables to inject into our app.
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));

const shouldUseReactRefresh = env.raw.FAST_REFRESH;

// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
Expand Down Expand Up @@ -158,10 +166,13 @@ module.exports = function(webpackEnv) {
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
//
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
isEnvDevelopment &&
require.resolve('react-dev-utils/webpackHotDevClient'),
//
// When using the experimental react-refresh integration,
// the webpack plugin takes care of injecting the dev client for us.
isEnvDevelopment && !shouldUseReactRefresh && webpackDevClientEntry,
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
Expand Down Expand Up @@ -419,7 +430,10 @@ module.exports = function(webpackEnv) {
},
},
},
],
isEnvDevelopment &&
shouldUseReactRefresh &&
require.resolve('react-refresh/babel'),
].filter(Boolean),
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
Expand Down Expand Up @@ -607,6 +621,17 @@ module.exports = function(webpackEnv) {
new webpack.DefinePlugin(env.stringified),
// This is necessary to emit hot updates (currently CSS only):
isEnvDevelopment && new webpack.HotModuleReplacementPlugin(),
// Experimental hot reloading for React .
// https://github.com/facebook/react/tree/master/packages/react-refresh
isEnvDevelopment &&
shouldUseReactRefresh &&
new ReactRefreshWebpackPlugin({
overlay: {
entry: webpackDevClientEntry,
// TODO: This is just a stub module. Clean this up if possible.
module: require.resolve('./hotRefreshOverlayModuleStub'),
},
}),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebook/create-react-app/issues/240
Expand Down
2 changes: 2 additions & 0 deletions packages/react-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"types": "./lib/react-app.d.ts",
"dependencies": {
"@babel/core": "7.9.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.3.0-beta.1",
"@svgr/webpack": "4.3.3",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
Expand Down Expand Up @@ -68,6 +69,7 @@
"postcss-safe-parser": "4.0.1",
"react-app-polyfill": "^1.0.6",
"react-dev-utils": "^10.2.1",
"react-refresh": "^0.8.1",
"resolve": "1.15.0",
"resolve-url-loader": "3.1.1",
"sass-loader": "8.0.2",
Expand Down

0 comments on commit c5b96c2

Please sign in to comment.