HMR and Hot Reloading with the webpack-dev-server
The webpack-dev-server provides:
- Speedy compilation of client side assets
- Optional HMR which means that the page will reload automatically when after compilation completes. Note, some developers do not like this, as you'll abruptly lose any tweaks within the Chrome development tools.
- Optional hot-reloading. The older
react-hot-loaderhas been deprecated in favor of fast-refresh. For use with Webpack, see Client Side rendering and HMR using react-refresh-webpack-plugin section below or visit react-refresh-webpack-plugin for additional details.
If you are not using server-side rendering (not using prerender: true),
then you can follow all the regular docs for using the bin/shakapacker-dev-server
during development.
Server Side Rendering with the Default shakacode/shakapacker bin/shakapacker-dev-server
If you are using server-side rendering, then you have a couple of options. The recommended technique is to have a different Webpack configuration for server rendering.
If you use the same Webpack setup for your server and client bundles
If you do use the webpack-dev-server for prerendering, be sure to set the
config/initializers/react_on_rails.rb setting of
config.same_bundle_for_client_and_server = truedev_server.hmr maps to devServer.hot.
This must be false if you're using the webpack-dev-server for client and server bundles.
dev_server.inline maps to devServer.inline.
This must also be false.
If you don't configure these two to false, you'll see errors like:
ReferenceError: window is not defined(ifhmris true)TypeError: Cannot read property 'prototype' of undefined(ifinlineis true)
Client-Side rendering with HMR using react-refresh-webpack-plugin
Basic installation
To enable the HMR functionality, you have to use ./bin/shakapacker-dev-server
-
In
config/shakapacker.ymlsethmrandinlinedev_serverproperties to true.dev_server: https: false host: localhost port: 3035 public: localhost:3035 hmr: true # Inline should be set to true if using HMR inline: true -
Add react-refresh packages:
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh -
HMR is for use with the
webpack-dev-server, so we only add this for thewebpack-dev-server.const { devServer } = require('shakapacker'); const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER; // plugins if (isWebpackDevServer) { environment.plugins.append( 'ReactRefreshWebpackPlugin', new ReactRefreshWebpackPlugin({ overlay: { sockPort: devServer.port, }, }), ); }We added
overlay.sockPortoption inReactRefreshWebpackPluginto match the webpack-dev-server port specified inconfig/shakapacker.yml. This makes SockJS works properly and fixes this error in browser console:GET http://localhost:[port]/sockjs-node/info?t=[xxxxxxxxxx] 404 (Not Found). When usingReactRefreshWebpackPluginwithv0.6.0and newer,overlay.sockPortis no longer supported and should be omitted from the configurations. -
Add the react-refresh plugin in
babel.config.jsmodule.exports = function (api) { return { plugins: [process.env.WEBPACK_DEV_SERVER && 'react-refresh/babel'].filter(Boolean), }; };
That's it :).
Now the browser should reflect changes in .js and .css files without reloading.
If for some reason the plugin doesn't work, you can revert the changes and leave only devServer hmr/inline set to true, affecting only CSS files.
These plugins are working and tested with
- babel 7
- webpacker 5
- bootstrap 4
- jest 26
- core-js 3
- node 12.10.0
- [email protected]
- react-refresh 0.8.3
- react_on_rails 11.1.4
configuration.