New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do I set up HMR for a React project using Shakapacker? #92
Comments
Hey @jameshibbard I think there's a piece of the puzzle missing - webpack plugin You can see how this is applied in the example repo (keep in mind there's few bits of additional config there so you might need to adjust this to your own usecase) I think after this it should all work but away from my laptop. Try this out and ping back if it still doesn't play ball and I'll take a closer look CC @justin808 - possibly one to improve in the docs! |
Also, I tried creating a custom config and importing that into // config/webpack.config.js
const { webpackConfig, merge } = require('shakapacker')
const vueConfig = require('./custom')
module.exports = merge(vueConfig, webpackConfig) And: // config/custom.js
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
mode: isDevelopment ? 'development' : 'production',
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean),
},
},
],
},
],
},
plugins: [isDevelopment && new ReactRefreshWebpackPlugin()].filter(Boolean),
}; |
@jameshibbard I think I figured it out! It's because you trying to edit root directly so the hot update bails out. For more info, see issue here and the comment pmmmwh/react-refresh-webpack-plugin#177 (comment) See the repo here for the implementation https://github.com/tomdracz/test-hmr-app/commits/main
|
Awesome! Thank you. That works now. Would you like me to send a PR updating the React config with more explicit steps? P.S. Sorry, I deleted my first reply, as I had also (kinda) figured it out and was going to post a more comprehensive update. |
@jameshibbard If you can get some updated docs going, it would be awesome! Might not all fit at https://github.com/shakacode/shakapacker/blob/master/docs/customizing_babel_config.md but we can find a good place for this to go when we have a copy! |
Sure thing. I'll see what I can do. |
Hi @tomdracz, As promised I wrote up some basic instructions. Please feel free to take as much, or as little from this as you want (e.g. not sure how much value the basic demo provides). I wrote this thinking that maybe one could link to it from here https://github.com/shakacode/shakapacker#react ? Thanks again for the help with my original issue. Basic SetupThese steps describe how to create a Rails/React app, using Shakapacker as the bundler. Before starting, ensure that you have Yarn installed: npm i -g yarn Create a new Rails app as per the installation instructions in the README. Add React, as well as the necessary libraries to enable CSS support in your application: yarn add react react-dom @babel/preset-react
yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin Update the Babel configuration in the package.json file: "babel": {
"presets": [
"./node_modules/shakapacker/package/babel/preset.js",
+ "@babel/preset-react"
]
}, And that's it. You can now create a React app using Enabling Hot Module Replacement (HMR)With HMR enabled, Shakapacker will automatically update only that part of the page that changed when it detects changes in your project files. This has the nice advantage of preserving your app’s state. To enable HMR in a React app, proceed as follows:. In Install the react-refresh package, as well as @pmmmwh/react-refresh-webpack-plugin: yarn add --dev react-refresh git+https://github.com/pmmmwh/react-refresh-webpack-plugin Note that this installs Alter const { webpackConfig, inliningCss } = require('shakapacker');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
if (isDevelopment && inliningCss) {
webpackConfig.plugins.push(
new ReactRefreshWebpackPlugin({
overlay: {
sockPort: webpackConfig.devServer.port,
},
})
);
}
module.exports = webpackConfig; This applies the plugin to the webpack configuration. Delete the Babel configuration from - "babel": {
- "presets": [
- "./node_modules/shakapacker/package/babel/preset.js",
- "@babel/preset-react"
- ]
- }, Then create a module.exports = function (api) {
const defaultConfigFunc = require('shakapacker/package/babel/preset.js')
const resultConfig = defaultConfigFunc(api)
const isDevelopmentEnv = api.env('development')
const isProductionEnv = api.env('production')
const isTestEnv = api.env('test')
const changesOnDefault = {
presets: [
[
'@babel/preset-react',
{
development: isDevelopmentEnv || isTestEnv,
useBuiltIns: true
}
]
].filter(Boolean),
plugins: [
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
{
removeImport: true
}
],
process.env.WEBPACK_SERVE && 'react-refresh/babel'
].filter(Boolean),
}
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ]
return resultConfig
} HMR for your React app is now enabled. 🚀 A Basic Demo AppTo test that all of the above is working, you can follow these instructions to create a basic React app using Shakapacker.
rails new myapp --skip-javascript
cd myapp
bundle add shakapacker --strict
./bin/bundle install
./bin/rails webpacker:install
yarn add react react-dom @babel/preset-react
yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin
rails g controller site index
echo '<div id="root"></div>' > app/views/site/index.html.erb
touch app/javascript/App.css app/javascript/App.js
import React from 'react';
import { createRoot } from 'react-dom/client';
import HelloMessage from './App';
const container = document.getElementById('root');
const root = createRoot(container);
document.addEventListener('DOMContentLoaded', () => {
root.render(<HelloMessage name="World" />);
});
import React from 'react';
import 'App.css';
const HelloMessage = ({ name }) => <h1>Hello, {name}!</h1>;
export default HelloMessage;
h1 { color: blue; }
hmr: true
yarn add --dev react-refresh git+https://github.com/pmmmwh/react-refresh-webpack-plugin
const { webpackConfig, inliningCss } = require('shakapacker');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const isDevelopment = process.env.NODE_ENV !== 'production';
if (isDevelopment && inliningCss) {
webpackConfig.plugins.push(
new ReactRefreshWebpackPlugin({
overlay: {
sockPort: webpackConfig.devServer.port,
},
})
);
}
module.exports = webpackConfig;
- "babel": {
- "presets": [
- "./node_modules/shakapacker/package/babel/preset.js"
- ]
- },
module.exports = function (api) {
const defaultConfigFunc = require('shakapacker/package/babel/preset.js')
const resultConfig = defaultConfigFunc(api)
const isDevelopmentEnv = api.env('development')
const isProductionEnv = api.env('production')
const isTestEnv = api.env('test')
const changesOnDefault = {
presets: [
[
'@babel/preset-react',
{
development: isDevelopmentEnv || isTestEnv,
useBuiltIns: true
}
]
].filter(Boolean),
plugins: [
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
{
removeImport: true
}
],
process.env.WEBPACK_SERVE && 'react-refresh/babel'
].filter(Boolean),
}
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets]
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins ]
return resultConfig
}
rails s
./bin/webpacker-dev-server
Note that HMR will not work if you edit |
@tomdracz @Judahmeek we should get this into the docs directory. |
It is now no longer necessary to install the react-refresh-webpack-plugin directly from GitHub, as they have published a new version (0.5.5) which plays nicely with the latest version of React. Would you like me to make a PR with the above instructions (updated to include the new version of react-refresh-webpack-plugin)? I'd create a new file under |
@jameshibbard YES! that would be fabulous! If you can submit a PR for updating https://github.com/shakacode/react_on_rails_demo_ssr_hmr, that would be great! |
Here ya go: #110 I'm afraid I'm not familiar with react_on_rails and it seems to have a lot of moving parts, so I'm probably not the best person to update that. |
Hi,
I'm having trouble setting up a React project with HMR.
I tried following the steps outlined here: https://github.com/shakacode/shakapacker/blob/master/docs/customizing_babel_config.md
Whenever I make a change to a CSS file, HMR happens as expected.
However, when I edit a React component, I see the following error message:
What am I doing wrong?
Is it possible to set things up so that when I edit a React component, the changes are reflected on the page without a full refresh and that no warning is shown in the console? I'm using Rails 7 and React 18 (although I was getting the same error under React 17)
Grateful for any help.
Steps to reproduce
rails new myapp --skip-javascript cd myapp bundle add shakapacker --strict ./bin/bundle install ./bin/rails webpacker:install yarn add react react-dom @babel/preset-react yarn add css-loader style-loader mini-css-extract-plugin css-minimizer-webpack-plugin yarn add --dev @pmmmwh/react-refresh-webpack-plugin react-refresh
app/javascript/application.js
:app/javascript/App.css
:package.json
babel.config.js
file in the root of project and add the sample config.application.js
and observe the error in the browser console.The text was updated successfully, but these errors were encountered: