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

Breaking hotreloading #27

Closed
ChrisCinelli opened this issue Oct 14, 2016 · 5 comments
Closed

Breaking hotreloading #27

ChrisCinelli opened this issue Oct 14, 2016 · 5 comments

Comments

@ChrisCinelli
Copy link

ChrisCinelli commented Oct 14, 2016

Thank you very much for the great job with babel-watch.
Our restart time went way down since we started using it.

The problem that we still have is that the autowatch breaks the react-hot-loader in our universal configuration.

// .babelrc
{
  "presets": ["react", "es2015", "stage-0"],
  "plugins": ["react-hot-loader/babel"],
  "env": {
    "production": {
      "presets": ["es2015", "react", "react-optimize", "es2015-native-modules", "stage-0"]
    }
  }
}

// client/index.js - Client entry point

import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from './App';
import { configureStore } from './store';

// Initialize store
const store = configureStore(window.__INITIAL_STATE__);
const mountApp = document.getElementById('root');

render(
  <AppContainer>
    <App store={store} />
  </AppContainer>,
  mountApp
);

// For hot reloading of react components
if (module.hot) {
  module.hot.accept('./App', () => {
    // If you use Webpack 2 in ES modules mode, you can
    // use <App /> here rather than require() a <NextApp />.
    const NextApp = require('./App').default; // eslint-disable-line global-require
    render(
      <AppContainer>
        <NextApp store={store} />
      </AppContainer>,
      mountApp
    );
  });
}

If we run the process with just cross-env babel-watch -r dotenv/config index.js dotenv_config_silent=true, when a component is changed, the server restart. This breaks the socket connection of the hot reload (in the console we see: :8000/__webpack_hmr:1 GET http://localhost:8000/__webpack_hmr net::ERR_INCOMPLETE_CHUNKED_ENCODING )

The workaround that we found was adding -D --watch server that watches ONLY the server folder.

This is still less than ideal. Now the server does not restart if a component is changed but only when a file in the /server folder changes. The problem is that in order for the server to reload a component for a full page reload we have to manually Ctrl-C and restart the server.

Ideally when a component is updated, the server set a flag and on the next full page reload, the server is restarted.

I wonder if there is already a way to fix this or if babel-watch could expose a way for the process to detect if a file changes and delay the reload until an event is triggered (i.e. access to a react-router route).

@kmagiera
Copy link
Owner

kmagiera commented Nov 8, 2016

Hey @ChrisCinelli ! Sorry for getting back to you so late. In general I don't have any good idea on how babel-watch could support such a complex use-case. If you have any suggestion on how precisely this could work I'd be keen to listen.

I'm not entirely sure if I understand how your setup works, so I'm assuming you have webpack that bundles JS and then also serverside rendering that uses the same client code, right? If so I worked on an app with very similar setup and the way we solved it was by starting two processes: one with webpack and the second with server code. Webpack will handle client code updates and hot reloading (webpack will keep socket connection open when updating client JS files) whereas babel-watch will handle restarting the server

Let me know if that helps!

@ChrisCinelli
Copy link
Author

ChrisCinelli commented Nov 9, 2016

It is a little more tricky when you have isomorphic code. I.e. component code that is used both on the server and frontend. Splitting server and client process does not help.

Going back on what I was asking, I think the tricky part is to find a good way for the process to communicate to babel-watch. Maybe something like: http://stackoverflow.com/a/36995148/407245

So if you start babel-watch with --delay-restart, it does not restart the process until the child send a process.send('full_page_reload'). The babel-watch user will have to send process.send('full_page_reload') when a route with a full page reload is hit.

@kmagiera
Copy link
Owner

kmagiera commented Nov 9, 2016

@ChrisCinelli what do you mean by "more tricky"? I use the setup with two processes I described with isomorphic code (one process runs webpack, the other runs server code with server side rendering of react app)

Are you sure restarting the prcess whenever page reload is requested would solve your problem? If the server process dies when you're reloading your page the browser would get no response back. So in my opinion it is not sufficient to just wait with restart but I might be missing something...

@ChrisCinelli
Copy link
Author

I will try to be more clear. In an isomorphic app you have the code of components (that I keep in a "client" folder) that is shared and runs on both the server and the browser. Ideally you are able to modify HTML and CSS of the component and the react hot-reloader will be able to push the new version to the browser without restarting the server. The hot-reloader, though, does not push the code to the server. For that you need a server restart.

Now I tried 2 things:

  1. I restart the server whenever a file in the folders change, this breaks the hot reloader and in general add latency or hiccups if you do ajax requests because these requests cannot be completed until the server is restarted.
  2. I exclude the "client" folder from the watcher. But if I need to re-render the page from the backend after modifying component code in "client", I need to manually restart the process.

I am not sure how using 2 different processes can fix this problem. Both processes will have to detect changes in the "client" folder and once you modify a component file in it, they will both restart. Or am I misunderstanding what you suggested?

What I am suggesting is to have babel-watch to watch the server code (that includes the root page component) but when a file is changed, instead of restarting the server immediately, waits until there is full page reload (signaled by the code).
I think with the native implementation you will see an error because the connection is broken. A work around is to reload the page twice. For a full solution, either the parent process will proxy the request preserving the connection, or we issue a redirect to the same page URL before sending the signal to the parent.. The latter is a little more hacky but I think it should work.

jibingeo pushed a commit to jibingeo/babel-watch that referenced this issue Feb 9, 2017
@STRML
Copy link
Collaborator

STRML commented Jan 5, 2021

This is a pretty complex use case that we don't intend to actually support. However, I'd be happy to accept a PR that would wait for a signal to do the reload, if you'd like.

@STRML STRML closed this as completed Jan 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants