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

Hot Module Reloading (HMR) Not Working #864

Closed
bntzio opened this issue Apr 27, 2017 · 31 comments
Closed

Hot Module Reloading (HMR) Not Working #864

bntzio opened this issue Apr 27, 2017 · 31 comments

Comments

@bntzio
Copy link
Contributor

bntzio commented Apr 27, 2017

Gatsby version: 0.12.46
Node version: 6.4.0
OS version: OSX El Capitan 10.11.6

Some hours ago I noticed that the hot module reloading (HMR) wasn't working, when I run npm run develop to start developing and make a change in my component, I get this error and warning in the chrome console:

Error:

XMLHttpRequest cannot load http://0.0.0.0:8000/032760b3db0a507954fb.hot-update.json. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 404.

Warning:

[HMR] Update check failed: Error: Manifest request to http://0.0.0.0:8000/032760b3db0a507954fb.hot-update.json timed out.
    at XMLHttpRequest.request.onreadystatechange (http://localhost:8000/bundle.js?t=1493255843490:34:23)

I did some research and it seems that this issue has to do with webpack-dev-server as mentioned here.

A webpack-dev-server/middleware security issue found some days ago, and I think the update breaks some configuration on various projects.

I found these disscussion in the webpack-dev-server github issues as well:

It's strange, yesterday I was working with HMR without any problems.

Is anyone facing the same issue?

@KyleAMathews
Copy link
Contributor

Gahhh that explains it. There's been several people complaining about this and I couldn't figure out why. Thanks for the research!

So I think we just need to change https://github.com/gatsbyjs/gatsby/blob/master/lib/utils/develop.js#L167
to headers: { "Access-Control-Allow-Origin": "localhost:8000" }.

@bntzio
Copy link
Contributor Author

bntzio commented Apr 27, 2017

Yeah I've read that it should work by specifying that in the devServer configuration.

That said, it won't work for some people based on my research, for me that isn't working either, I just tested it and same error.

I'm going to continue digging into this.

@bntzio
Copy link
Contributor Author

bntzio commented Apr 27, 2017

Mm... I've tried using disableHostCheck: true as mentioned here but it didn't work, that should skip the security changes and be able to go back to normal, I just wanted to check if that way works, obviously it shouldn't be in production.

@bntzio
Copy link
Contributor Author

bntzio commented Apr 27, 2017

For the moment, developing on 0.0.0.0:8000 instead of the localhost version fixes the issue.

@michaeljdeeb
Copy link
Contributor

michaeljdeeb commented Apr 27, 2017

Hey! I haven't been up to date on the codebase in awhile, but a security vulnerability in a static site is such a rarity that I ended up catching up. Feel free to correct any of this if it's off.

From what I can see, gatsby actually uses hapi and hapi-webpack-plugin in lieu of webpack-dev-server so disableHostCheck: true isn't valid anywhere in develop.js

Looking at Usage 1), and gatsby's develop.js, I believe the headers object actually isn't doing anything right now. webpack-hot-middleware has minimal documentation, but doesn't mention headers and webpack-dev-middleware does and webpack-dev-server links to a webpack-dev-middleware release with a security fix related to Access-Control-Allow-Origin.

Placing the headers object as is under assets instead solved the errors for me and also exposed me to the attack being discussed. Changing * to localhost, localhost:8000, or http://localhost did not work, but http://localhost:8000 worked as expected. That said, everything still worked on 0.0.0.0:8000, which leads me to believe this solution is still vulnerable.

What I believe to be the secure solution to this is to run gatsby develop --host domain.local (or LAN IP) --port #### as the site then becomes unavailable over 0.0.0.0. Other options include exposing the header with a user config, and/or to just warn people of the risk when running gatsby develop without the host argument. A DNS rebinding attack will always be possible as long as the server is listening on anything routed to localhost (localhost, 0.0.0.0, 127.0.0.1).

You can check for vulnerability by running gatsby develop -p 3000 (the demo site expects port 3000), opening the browser web inspector, and going to dnsrebinder.net (leaving unlinked intentionally). Eventually you'll see a not_found come back with a 404 from your development server. The vulnerability is fixed if there is no status code associated with the request.

@fpaboim
Copy link

fpaboim commented Apr 27, 2017

It seems that webpack dev server is not recognizing 0.0.0.0 as localhost for hot module replacement.

running:

gatsby develop --host localhost --port 8000

seems to work though. Strange that this only happened to me with the bootstrap boilerplate, the default project creation seems to be working fine?

@KyleAMathews
Copy link
Contributor

KyleAMathews commented Apr 27, 2017 via email

@michaeljdeeb
Copy link
Contributor

Ah, right. webpack-dev-middleware passed 'Access-Control-Allow-Origin': '*' prior to 5 days ago.
webpack/webpack-dev-middleware@626a35a#diff-27e39f85634d9276821c67a9bbf764b4L64

If npm list webpack-dev-middleware shows a version earlier than v1.10.2 you don't have the breaking security change.

@KyleAMathews
Copy link
Contributor

Decided it'd be simplest to just use localhost as the default host 7cd0afb

The reason the default host was set to 0.0.0.0 in the past was so that Gatsby would work by default when developing on a remote server but that's a small convenience that we can drop.

@Daniel15
Copy link
Contributor

It seems that webpack dev server is not recognizing 0.0.0.0 as localhost for hot module replacement.

0.0.0.0 means "all IPs on the local machine". It doesn't actually represent a routable IP address - You're not supposed to hit 0.0.0.0 directly in your browser.

@KyleAMathews
Copy link
Contributor

@Daniel15 yeah, it was so the dev server would just work on local and remote hosts without having to explicitly set the IP but with the webpack change we had to drop that.

@ghost
Copy link

ghost commented May 22, 2017

@KyleAMathews - but the option to set the host with --host will remain intact? We need it to specify where to send the hot reloading requests and it is not always the localhost

@KyleAMathews
Copy link
Contributor

KyleAMathews commented May 22, 2017 via email

@webOS101
Copy link
Contributor

webOS101 commented May 22, 2017

I'm not certain the fix is better than the problem it solved. Sure, it works for localhost now, but it doesn't allow you to, say, allow a coworker to access your gatsby instance or test how things look on different devices (without specifying --host). Sadly, the bug did cost me lot of time the other day trying to find out why my app was no longer requesting local files when I inadvertently switch to localhost.

@michaeljdeeb
Copy link
Contributor

@webOS101 if you run gatsby develop --host <your-machine>.local you will get all of that functionality back.

@bntzio
Copy link
Contributor Author

bntzio commented May 22, 2017 via email

@matthewmcclatchie
Copy link

Even though this issue is long closed, I was having the same problem with localhost when following part one of the tutorial.

@fpaboim - Your suggestion works for me.

@rabidhadron
Copy link

Just wanted to add I also was having the same issue with HMR when accessing via the network. I found substituting --host xxx.xxx.xxx.xxx with the actual IP address of the server running Gatsby solved my problem.

@michaek
Copy link
Contributor

michaek commented Mar 15, 2018

It seems like specifying the LAN IP of your development machine as --host does thread the needle of letting your dev server be accessible on the network, while generating assets that refer to its network-accessible URLs.

However, since the dev server is no longer listening for connections on 127.0.0.1, that breaks any local reverse proxy you may have set up. Perhaps you have resolution for projectname.yourmachine.test and a local reverse proxy for that virtual host from say, 80 -> 8001 , so your colleagues (or your device library) can test any work in progress without having to know the details of your network address and port configuration. If that's the case, there's not currently a way to make it work (without reverse proxying to your LAN address instead of localhost).

The current approach to defining the HMR entry point assumes that the dev server hostname and port will always be public-facing. I'd suggest that it may be better to optionally configure the URL from which webpack looks for its bundles separately from the host/port that the dev server is running on, as they're not always the same.

@m-allanson
Copy link
Contributor

@michaek Would you be able to do this using Gatsby's custom webpack config hooks?

@michaek
Copy link
Contributor

michaek commented Mar 23, 2018

@m-allanson Yes, it's possible (and I'm doing it), it just seems to involve too much knowledge about the configuration internals to be something I'd recommend:

      // Hack to allow HMR to work on the LAN with a reverse proxy.
      if (process.env.PUBLIC_HOST) {
        config._config.entry.commons = config._config.entry.commons.map(point => point.replace('localhost:8000', process.env.PUBLIC_HOST))
      }

I think it would be better for for most people if Gatsby accepted a separate configuration option for the public host where assets will be requested from, rather than assuming that's the same as the dev server hostname and port.

@waspinator
Copy link

how would I get hot-reloading working if I'm running gatsby develop from within a docker container?

@crispamares
Copy link

@waspinator I launch gatsby from inside a container like this gatsby develop -H 0.0.0.0 and works fine. The problem comes when you want to access the web from other machine, like a mobile device.

Then my solucion si puting the next code inside gatsby-node.js

function modifyWebpackConfig(wp) {
	if (wp.stage == "develop") {
		let config = wp.config;
		console.log("OPEN THIS: ", "http://"+process.env.PUBLIC_HOST+':'+wp.program.port);
		if (process.env.PUBLIC_HOST) {
			config._config.output.publicPath = config._config.output.publicPath.replace('0.0.0.0', process.env.PUBLIC_HOST);
			config._config.entry.commons = config._config.entry.commons.map(point => {
				if (/webpack-hot-middleware/.test(point)) {
					point += '&dynamicPublicPath=true'
				}
				return point;
			})
		}
	}
}

module.exports = {modifyWebpackConfig}

The last thing is suppliying the PUBLIC_HOST env variable when you launch gatsby.develop

@sedlund
Copy link

sedlund commented Jun 18, 2018

@waspinator easiest way is to run the container with --net host. This will put the container on the host machines network. If the container is running on your local machine, you would be able to then connect to localhost:8000.

If it is a remote system you have ssh access to, then use SSH to forward the port over a tunnel. With openssh-client it would look like this:

ssh -L 8000:localhost:8000 userid@yourremoteserver

Then on your local machine you can go to http://localhost:8000 and it will forward over the ssh tunnel to the container.

@tylers-username
Copy link

Inspired by @crispamares, here is my working solution. The key change, other than refactoring for onCreateWebpackConfig is that I set publicPath to an empty string.

config.output.publicPath = '';

exports.onCreateWebpackConfig = ({ getConfig, stage, actions }) => {
  if (stage !== "develop") {
    return;
  }

  if (typeof process.env.LANDO === 'undefined') {
    return;
  }

  process.env.PUBLIC_HOST = 'docs.front.monin.lndo.site';
  let config = getConfig();

  if (typeof process.env.PUBLIC_HOST !== 'undefined' && typeof config.output !== 'undefined') {
    config.output.publicPath = '';
    config.entry.commons = config.entry.commons.map(point => {
      if (/webpack-hot-middleware/.test(point)) {
        point += '&dynamicPublicPath=true'
      }
      return point;
    });
  }
  console.log({ output: config.output, entry: config.entry });
  actions.setWebpackConfig({
    output: config.output, entry: config.entry, devServer: config.devServer
  });
}

@bezoris
Copy link

bezoris commented Apr 12, 2019

For the moment, developing on 0.0.0.0:8000 instead of the localhost version fixes the issue.

Thanks... I'm aware that this is a two-year old thread, but I just ran into the same issue. And switching to 0.0.0.0:8000 did indeed fix things. Strange.

@Daniel15
Copy link
Contributor

@bezoris - 0.0.0.0:8000 doesn't really make sense so it's surprising that it works... Try 127.0.0.1:8080 instead. It's possible localhost is using IPv6 but something is only listening on IPv4, or something similar.

@tylers-username
Copy link

tylers-username commented Apr 12, 2019 via email

@bezoris
Copy link

bezoris commented Apr 12, 2019

127... also refuses to connect. I think you're right though, something is tying up localhost.

EDIT: Resolution (at least for me)

A bit of process sniffing and Googling revealed that "irdmi" was stealing port 8000. I edited that in /etc/services and all is fine now.

The "Intel Remote Desktop Management Interface" is a defunct hardware service from the 90's that listens on 8000... this may also explain why it's present on my old - but still kicking - Thinkpad x220 dev-box.

Strangely, 8080 (set to http-alt for tcp/udp) still fails to connect. Ah well... a half-win then. Thanks @Daniel15, that sent me down the right track.

Best, Chris.

@eltonmarques96
Copy link

gatsby develop --host 0.0.0.0 --port 8000 works with me

@d1sco
Copy link

d1sco commented Apr 8, 2020

all praise gatsby develop --host 0.0.0.0 --port 8000

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