webpack-dev-server: Page does not refresh on HTML change when HMR is on
- Operating System: OS X 10.11.6
- Node Version: 9.2.1
- NPM Version: 5.6.0
- webpack Version: 3.8.1
- webpack-dev-server Version: 2.10.1
- This is a bug
- This is a modification request
Code
https://github.com/andreyvolokitin/test-webpack-dev-server
Expected Behavior
Editing ./src/index.html should cause recompiling and page refresh in the browser
Actual Behavior
Recompiling is happening, but the page in the browser does not refresh
For Bugs; How can we reproduce the behavior?
git clone https://github.com/andreyvolokitin/test-webpack-dev-server && cd test-webpack-dev-servernpm install && npm start- Edit
./src/index.html— compiling is happening, but the page in the browser does not refresh - Open browser console and edit
./src/test.js— HMR works
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 18
- Comments: 39 (8 by maintainers)
Commits related to this issue
- Expose compiler to allow custom watch logic Details: https://github.com/webpack/webpack-dev-server/issues/1271 — committed to andreyvolokitin/webpack-dev-server by andreyvolokitin 6 years ago
- Fix HMR issue on html change See https://github.com/webpack/webpack-dev-server/issues/1271#issuecomment-379792541. — committed to jenkin/webpack-v4-scaffold by jenkin 5 years ago
Maybe, it’s some sort of a solution.
I’ve had good success using the private watch method provided by the Server.js
Although using an internal (private) method doesn’t seem like a good idea.
@andreyvolokitin we use this snippet for
php:I think I found a minimal change that can suit the need: simply expose compiler to
beforeandaftercallbacks. Then everything could be done within the custom handler, because apparently, it is possible to add multiple hooks for same compiler event (compiler.plugin('done', fn)):And for simple static files watching we again can use
beforeandchokidar, orwatchContentBase. Though probably in the future it would be worth to include all this withinwebpack-dev-server.I guess for now even this proposed minimal change can’t be added because it may qualify as a “new feature”, and there is a maintenance mode happening. Hope this will be resolved sooner or later…
The only concern is this quote from
CONTRIBUTING.md, as my custom handler usingcompiler.watchFileSystem:As @ripeshade wrote in 2018:
This is what the same config looks like in 2021:
Anyway, that’s what worked for me, using webpack 5.X and webpack-dev-server 4.X. No need to add
writeToDisk: true. This works perfectly in my dev environment.For those still relying on
"content-changed", I found out that, in newer versions, the following code does not work:server.sockWrite(server.sockets, "content-changed")Instead it should be
server.sendMessage(server.webSocketServer.clients, "content-changed")migration-v4 tells us about the change from
sockWritetosendMessage, but not aboutwebSocketServer.clients.clientis not added toserver.socketsas it can be seen from this line onwards:https://github.com/webpack/webpack-dev-server/blob/2ea510ca302f63d66eb4d5d79dac5f662cff3a82/lib/Server.js#L1590
For
server.sendMessage(server.socketsto work, I think athis.sockets.push(client)would be needed, but it’s not done. Note that I’m not suggesting that this omission is a bug, I’m merely trying to provide more context on this behavior for those who also had to change their setup after the version upgrade.@SassNinja in next major release we will implement
watchPathsoption for this cases, now you can use_watchmethod, it is legacy reasonI’m facing the same issue: changing my template doesn’t cause a reload in webpack-dev-server
The suggested solution of both, @avdd and @cloudratha, are working (thanks btw!) However none of them has 100% convinced me yet to use it for all my projects. Let me explain why:
What I really like about this one is the simplicity: only one line However I’m a bit afraid to rely on an internal method and am not sure how this exactly works internally and if there’s no risk of race conditions.
@evilebottnawi is there a specific reason why the
_watchmethod is not public (without underscore)?What I really like about this one is that it does not cause a reload when nothing has changed in the template (it’s probably not likely you save the template several times without any changes but nevertheless I like it). However this solution also has downsides:
compilation.hooks.htmlWebpackPluginAfterEmitwhat will probably break with next major updateI think for now I’m staying with the
server._watchsolution because it doesn’t require much additional code. But it will definitely be great if one solution gets integrated into the plugin (either in webpack-dev-server or in html-webpack-plugin) because this is a common use case imo.Original bug was in
html-webpack-pluginand fixed in the latest version, anyway for v4 (now in rc) we havewatchFiles, there you can specify files which will be trigger reload of the pageThis is currently working for me with html-webpack-plugin^4.1.5, webpack^5.20.1, webpack-dev-server^3.11.2:
Key part is the
writeToDisk: truesetting - this ensures webpack-dev-server outputs to my dist folder which serves as the content base.@evilebottnawi with
HtmlWebpackPluginthe page is not reloaded when.htmlchanges. There are numerous issues about this inhtml-webpack-pluginrepo (i.e. https://github.com/jantimon/html-webpack-plugin/issues/232), as well as this repo and probably others too. The example code from this issue is actually usinghtml-webpack-pluginand shows this (https://github.com/andreyvolokitin/test-webpack-dev-server). But it is clear that this issue comes fromwebpack-dev-serverwhich simply does not take.htmlchanges into account whenhot: true@evilebottnawi my
.htmlfiles are generated using PostHTML, so webpack is compiling them from the source during each recompilation (they are used byHtmlWebpackPluginin atemplateoption). This snippet is usingchokidarto watch.htmlfiles. Webpack is watching the same files. When files change — webpack starts a recompilation, and at the same timechokidaris executing its callback (server.sockWrite(server.sockets, "content-changed");). So webpack recompilation needs to complete before page refresh happens, so that newly generated HTML actually appears in the browser. Might this be a race condition, like if page refresh happens before webpack completes recompilation, so that refreshed page will contain old HTML?@evilebottnawi thanks! It works, but what about async issues — i.e. we pass a
content-changedto a socket, and at the same time webpack is starting to compile the same files. We need to reload the page after webpack compilation, but as far as I understand with this snippet there is no guarantee of that? Probably we can add some delay then, but we can not precisely know the exact current compilation time to accommodate it in a delay (and this may cause unwanted delay time). Or this is actually no-issue?@LeoniePhiline yes,
watchFileswill send changes only after compilation is done to prevent weird behaviorme too @ripeshade It seems to make HMR not work, even I just edit a style file (e.g. src/css/app.css) that triggers web browser a full reload/refresh. any changes in src/cs/app.js or src/js/app.js should trigger a HMR , src/index.html triggers a browser refresh is exact what I want.
I use the lastest stable webpack and follow the guides of official webpack website.
Maybe I need to change the contentBase to path.join(__dirname, path/to/your/html-template),
The solution proposed by @ripeshade isn’t working form me. The reload works, but i’ts a full reload.
Any update?
Hi, I have the same problem… any update on this?
@andreyvolokitin good catch. I’ve updated that snippet to compare with the previous emit.
@ripeshade watchContentBase this optional setting fixed the issue I have. Now I can use HMR and the HTML also can auto refresh. Thx mate. I think this might be the reason why webpack team did not fix the issue. Because there is a solution already!
Maybe add “onCompile” callback here and expose compiler and server to it? Then on each compile, it will be possible to get changed files with
compiler.watchFileSystem.watcher.mtimesand to do page reload withserver.sockWrite(server.sockets, "content-changed"):If it would be possible though to subscribe a one-time function to compiler event hook like “done” within
chokidarcallback insidedevServer.before(), then I could get a page reload guaranteed after compiling. But I am afraiddevServer.before()does not expose webpack compiler… And I guess there is no way do define a “once” callback on compiler@evilebottnawi Would it be a bad thing to add an option to
webpack-dev-server, containing a list of required file extensions (like['.html', '.jade']) which then would be used as described here: https://github.com/webpack/webpack-dev-server/issues/1271#issuecomment-359815525 ? I know I can watch source html files and reload the page on their changes, but it looks like a hack considering that my html is compiled. Page reload should be more like compilation callback and not a parallel process of compilation. And it is clear that this feature is needed either wayWhat I mean is there are two separate processes: webpack compilation of updated HTML and
chokidarcallback on this HTML changes. They need to complete one after another, but there is no guarantee for that@andreyvolokitin can you describe you issue on example? You can add own logic to snippet above, also you can use browser-sync plugin for webpack.