'Webpack5 + react-refresh-webpack-plugin does not work
I wanted to setup react
with webpack
, babel
, and typescript
myself since I would like to know more and have a consistent boilerplate for development.
I have been trying to setup fast refreshing and hot reloading in react
with `webpack5 following the documentation for react-refresh-webpack-plugin. I was not getting anywhere and decided to make a minimal example that reproduces the error.
My expectation is that I should be able to make changes to my source folder and the should appear immediately or at least upon refresh. As of now, neither happens.
I made sure to follow the primary readme for react-refresh-webpack-plugin
as best I could. I will review it again and see what changes I can make according to it and report back here.
The file tree so far looks like :
├── babel.config.js
├── package-lock.json
├── package.json
├── src
│ ├── app.tsx
│ ├── index.html
│ └── index.tsx
├── tsconfig.json
└── webpack.config.js
my webpack config
// webpack.config.js
const path = require( 'path' )
const ReactRefreshPlugin = require( '@pmmmwh/react-refresh-webpack-plugin' )
const HTMLWebpackPlugin = require( 'html-webpack-plugin' )
// Ingredients
// Just to make things less ugly
const SRC = path.join( __dirname, 'src' )
const NODE_MODULES = /node_modules/
const MODE = 'development'
const INDEX = path.join( SRC, 'index.html' )
const ENTRY_POINT = path.join( SRC, 'index.tsx' )
// Objects nested within exports.
// Also to make things less ugly.
const PLUGINS = [
new ReactRefreshPlugin(),
new HTMLWebpackPlugin({
template : INDEX,
filname : './index.html'
})
]
const RESOLVE = { extensions : [
'.ts',
'.js',
'.tsx',
'.jsx'
]}
const RULES = [
// Babel
{
test : /\.tsx?$/,
exclude : NODE_MODULES,
include : SRC,
use : 'babel-loader'
}
]
// Prettier exports.
module.exports = ( env ) => {
const config = {
mode : MODE,
entry : ENTRY_POINT,
module : {
rules : RULES
},
plugins : PLUGINS,
resolve : RESOLVE
}
console.log( JSON.stringify( config, null, space = "\n" ) )
return config
}
and my babel config
// babel.config.js
// Variables
const PRODUCTION = 'production'
// Methods
const PRESETS = ( api ) => [
'@babel/preset-env',
'@babel/preset-typescript',
[
'@babel/preset-react',
{
development : !api.env( PRODUCTION ),
runtime : 'automatic'
}
]
]
const PLUGINS = ( api ) => [
api.env( PRODUCTION ) && 'react-refresh/babel'
].filter( Boolean )
module.exports = ( api ) => {
api.cache.using(
() => process.env.NODE_ENV
)
return {
presets : PRESETS( api ),
plugins : PLUGINS( api )
}
}
package.json
:
{
"name": "typescript-react-with-refresh",
"version": "1.0.0",
"description": "Trying to get hot reloading working with webpack5.",
"main": "index.js",
"scripts": {
"start": "webpack serve --hot",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.16.7",
"@babel/preset-env": "^7.16.7",
"@babel/preset-react": "^7.16.7",
"@babel/preset-typescript": "^7.16.7",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"babel-loader": "^8.2.3",
"html-webpack-plugin": "^5.5.0",
"react-refresh": "^0.11.0",
"typescript": "^4.5.4",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.2"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}
and finally the configuration for the typescript compiler:
// tsconfig.json
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "ESNext",
"moduleResolution": "node",
"outDir": "dist",
"target": "ESNext",
"sourceMap": true
},
"include": ["src"]
}
Finally, if index.html
or any other source files are required, I can provide those. For now I am not providing them to keep this post brief. Thank you in advance for any help!
Update
I found that I should have installed ts-node
and type-fest
as dev dependencies, and change webpack.config.js
to webpack.config.ts
. Nonetheless the problem persists.
Solution 1:[1]
Figured it out. It turns out that there was a similar issue on the react-refresh-webpack-plugin
issues page, see issue #334. Part of my solution was to restart since I decided I did not like the formatting. The problem was with externalization of react
. The fix in particular was to add the following amendments to the optimization
and entry
sections below files and merge them together:
const path = require('path');
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const SRC = path.join( __dirname, '..', 'src' )
const DIST = path.join(__dirname, '..', 'dist')
const PUBLIC = path.join( __dirname, '..', 'public' )
module.exports = (env) => {
return {
mode: 'development',
entry: {
reactRefreshSetup: '@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js',
main: path.join( SRC, 'index.tsx' ),
},
output: {
filename: '[name].js',
path: DIST,
},
module: {
rules: [
{
test: /\.tsx?$/,
include: SRC,
use: 'babel-loader',
},
{
test : /\.css$/,
use : [
'style-loader',
'css-loader'
]
},
],
},
plugins: [
new HtmlWebpackPlugin({
filename: './index.html',
template: path.join( PUBLIC, 'index.html' ),
}),
],
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx' ],
},
}
}
and the rest
module.exports = ( env ) => {
return {
devServer: {
hot: true,
port: 8080,
},
plugins : [
new ReactRefreshPlugin()
],
optimization: {
runtimeChunk: 'single',
// Ensure `react-refresh/runtime` is hoisted and shared
// Could be replicated via a vendors chunk
splitChunks: {
chunks: 'all',
name(_, __, cacheGroupKey) {
return cacheGroupKey;
},
},
}
}
}
Solution 2:[2]
This is an example that works:
devServer: {
hot: true,
open: true,
port: 7777,
static: {
directory: path.resolve(pRoot, 'public', 'assets'),
publicPath: '/public/assets/',
},
},
The key here is to remove these two fields, since their jobs are handled by the HMR plugin instead:
devServer: {
watchFiles: ['src', 'public'],
historyApiFallback: true,
// ...
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Kindred |