Skip to content
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

Question: Enabling HRM Hot Module Replacement? #793

Closed
1 of 4 tasks
edelgado opened this issue Sep 27, 2017 · 14 comments
Closed
1 of 4 tasks

Question: Enabling HRM Hot Module Replacement? #793

edelgado opened this issue Sep 27, 2017 · 14 comments
Assignees
Labels
enhancement Hacktoberfest https://hacktoberfest.digitalocean.com/

Comments

@edelgado
Copy link
Contributor

Help us help you! Please choose one:

  • My app crashes with react-rails, so I've included the stack trace and the exact steps which make it crash.
  • My app doesn't crash, but I'm getting unexpected behavior. So, I've described the unexpected behavior and suggested a new behavior.
  • I'm trying to use react-rails with another library, but I'm having trouble. I've described my JavaScript management setup (eg, Sprockets, Webpack...), how I'm trying to use this other library, and why it's not working.
  • I have another issue to discuss.

Hi folks, I'm using Webpacker and react-rails and trying to get HRM Hot Module Replacement working on my project.

The webpack-dev-server.md doc in webpacker mentions that, in order to enable HMR for React we need add react-hot-loader as per these instructions.

I think I already did everything I need to do on the webpacker side of things: Step one, I did by adding the --hot option to the call of bin/webpack-dev-server in my Procfile. Additionally, I enabled the hmr setting in my webpacker.yml file.

I see in my console that HMR is enabled and it correctly listens to code changes. It's unable to hot-load modules tho, because the modules are not accepted:

image

The instructions for react-hot-loader says to modify your root container to accept HMR by changing the root React entry point from something like this:

import React from 'react';
import { render } from 'react-dom';
import RootContainer from './containers/rootContainer.js';

render(<RootContainer />, document.getElementById('react-root'));

To something like this:

 if (module.hot) {
   module.hot.accept('./containers/rootContainer.js', () => {
     const NextRootContainer = require('./containers/rootContainer.js').default;
     render(<NextRootContainer />, document.getElementById('react-root'));
   })
 }

But, how do I do that with react-rails? I use the react_component Rails view helper to integrate React components into Rails views.

I'm suspecting that HMR is not successful in my project because the React code is not setup to accept the hot modules. Where in my code can I add

Any help would be greatly appreciated!

@BookOfGreg
Copy link
Member

I actually spent a few hours looking into this myself last night, yep I could get HMR to initialize but I didn't make as much progress as you had done, I'll be honest I've never tried using the new HMR features of Webpacker 3 yet until you mentioned it so thanks for showing me something new and interesting 👍

Do you happen to know of any running example of HRM in the wild? Maybe a github example project of Webpacker + HMR working sould really help! That will make it infinitely easier for me to be building on a known good base than reinvent the wheel.

I'll make another attempt at getting a HMR component rendering in an example project when I have time.

@edelgado
Copy link
Contributor Author

Thanks for looking into it @BookOfGreg! Having HMR work with react-rails would be a huge time saver for developers as it would cut down on the amount of full-page refreshes we need to do when working on a component.

Here is an examples of HMR from from Dan himself: https://github.com/wkwiatek/react-hot-loader-minimal-boilerplate

More information can be found in http://gaearon.github.io/react-hot-loader/getstarted/

@edelgado
Copy link
Contributor Author

@BookOfGreg Also, this is a matching issue I created over at Webpacker, with some code hints from the authors there that may lead us in the right path: rails/webpacker#872

@BookOfGreg
Copy link
Member

BookOfGreg commented Oct 2, 2017

Thanks for the investigation work so far! Yep I totally can't get it working without modifying something.
I've been getting an example app stood up at BookOfGreg/react-rails-example-app to tinker with this. Currently if I switch on HMR and touch a file, the serverside rendering errors with SyntaxError: Unexpected token const so looks like there is some interesting work to do in this area.

Summoning @RiccardoMargiotta

@BookOfGreg BookOfGreg added this to the 2.5.0 milestone Nov 6, 2017
@BookOfGreg BookOfGreg self-assigned this Nov 6, 2017
@kkir
Copy link

kkir commented Jan 11, 2018

Putting ReactRailsUJS.mountComponents() did the trick for me

if (module.hot) {
  module.hot.accept('../src/App', () => {
    ReactRailsUJS.mountComponents();
  });
}

@BookOfGreg
Copy link
Member

@kkir That's good news! Could you share some example code, or PR onto https://github.com/bookofgreg/react-rails-example-app ? I've been unable to do it myself as of yet but I've never used HMR before either.

@AirWick219
Copy link

I am fighting with the HMR as well .. I was wondering where are we supposed to put the following code with respect too react-rails ?? is it in the javascript/packs/application.js where ReactRailsUJS.useContext ?? or the highest level components ?

if (module.hot) {
  module.hot.accept('../src/App', () => {
    ReactRailsUJS.mountComponents();
  });
}

@BookOfGreg
Copy link
Member

I think it's meant to go in the packs but I've still not had time to work on this.

@AirWick219
Copy link

AirWick219 commented Mar 23, 2018

I tried something like this but webpack-dev-serverd doesn't seem to like this and throw a bunch of warning

javascript/packs/application.js

const componentRequireContext = require.context('../components', true);
const ReactRailsUJS = require('react_ujs');

ReactRailsUJS.useContext(componentRequireContext);

if (module.hot) {
  module.hot.accept('../components', () => {
    ReactRailsUJS.mountComponents();
  });
}

@AirWick219
Copy link

I think I got it working without those code and just webpacker .. I do see module hot swapping without refreshing however, ran into an issue of module looking for a hot-update.json file with the content-type of text/html that's not there which caused a page reload.
See this for more details. rails/webpacker#1375

@BookOfGreg BookOfGreg added the Hacktoberfest https://hacktoberfest.digitalocean.com/ label Oct 1, 2018
@bishosilwal
Copy link

I got it working just adding hmr: true on dev_server in webpacker.yml.

@everaldo
Copy link

everaldo commented Jan 2, 2019

@bishosilwal , could you please give me more information on this?

Were you able to preserve state?

Did you just enabled hmr: true on dev_server in webpacker.yml or have you done more?

Thanks

@BookOfGreg BookOfGreg removed this from the 2.5.0 milestone Mar 31, 2019
@BookOfGreg
Copy link
Member

I've seen a few people using this in the wild now and I've put a link to one Stack Overflow answer on the topic in the Readme. #986
Going to close this PR.

@edelgado
Copy link
Contributor Author

edelgado commented Nov 7, 2019

As a follow-up, I was able to get HMR working with react-rails finally. It involves the use of the React Hot Loader NPM module and it's babel plugin. Each component needs to be exported in a way that is HMR-friendly. Here is a sample Rails app with HMR working:

https://github.com/edelgado/react-rails-hmr

One downside is that HMR and Server-Side Rendering do not seem to be playing along: #925

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Hacktoberfest https://hacktoberfest.digitalocean.com/
Projects
None yet
Development

No branches or pull requests

6 participants