-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Page does not refresh on HTML change when HMR is on #1271
Comments
I found that it is possible to get a list of changed files which caused recompilation. Would it be feasible to add some logic here, so that when the list of changed files contains certain extensions — we pass a flag to |
@andreyvolokitin we use this snippet for before(app, server) {
const chokidar = require("chokidar");
const files = [
// Refreshing php files
"**/*.php"
];
chokidar
.watch(files, {
alwaysStat: true,
atomic: false,
followSymlinks: false,
ignoreInitial: true,
ignorePermissionErrors: true,
ignored,
interval: typeof poll === "number" ? poll : null,
persistent: true,
usePolling: Boolean(poll)
})
.on("all", () => {
server.sockWrite(server.sockets, "content-changed");
});
} |
@shellscape what do you think about add to documentation example above? |
@evilebottnawi thanks! It works, but what about async issues — i.e. we pass a |
@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. |
@evilebottnawi my |
What I mean is there are two separate processes: webpack compilation of updated HTML and |
@andreyvolokitin |
@evilebottnawi with |
@evilebottnawi Would it be a bad thing to add an option to |
If it would be possible though to subscribe a one-time function to compiler event hook like "done" within |
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 devServer: {
hot: true,
onCompile(compiler, server) {
const watchFiles = ['.html', '.hbs'];
const changedFiles = Object.keys(compiler.watchFileSystem.watcher.mtimes);
if (
this.hot &&
changedFiles.some(filePath => watchFiles.includes(path.parse(filePath).ext))
) {
server.sockWrite(server.sockets, "content-changed");
}
}
} |
I think I found a minimal change that can suit the need: simply expose compiler to devServer: {
hot: true,
before(app, server, compiler) {
const watchFiles = ['.html', '.hbs'];
compiler.plugin('done', () => {
const changedFiles = Object.keys(compiler.watchFileSystem.watcher.mtimes);
if (
this.hot &&
changedFiles.some(filePath => watchFiles.includes(path.parse(filePath).ext))
) {
server.sockWrite(server.sockets, 'content-changed');
}
});
}
} And for simple static files watching we again can use 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
|
Maybe, it's some sort of a solution. |
I guess this is similar to the @evilebottnawi solution — server will start to watch files in |
@ripeshade |
@andreyvolokitin give this a try I don't think that contentBase is the right place to put HTML templates. |
@avdd, unfortunately, it breaks hot reloading: I suppose on each CSS/JS change |
@andreyvolokitin good catch. I've updated that snippet to compare with the previous emit. |
@avdd very nice, thanks! That's exactly what was needed: comparing previous and current HTML after compilation; if it changes, then we need to reload. Hope there are no hidden edge cases, will take my time to use and test it. Now the question remains: could this issue be relevant without |
I've had good success using the private watch method provided by the Server.js before(app, server) {
server._watch(`some/path/to/watch/*/**.html`);
} Although using an internal (private) method doesn't seem like a good idea. |
I'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!)
before(app, server) {
server._watch(`src/*/**.html`);
} What I really like about this one is the simplicity: only one line @evilebottnawi is there a specific reason why the
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html',
}),
reloadHtml
]
function reloadHtml() {
const cache = {}
const plugin = {name: 'CustomHtmlReloadPlugin'}
this.hooks.compilation.tap(plugin, compilation => {
compilation.hooks.htmlWebpackPluginAfterEmit.tap(plugin, data => {
const orig = cache[data.outputName];
const html = data.html.source();
if (orig && orig !== html) {
devServer.sockWrite(devServer.sockets, 'content-changed')
}
cache[data.outputName] = html;
});
});
} 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).
I think for now I'm staying with the |
@SassNinja in next major release we will implement |
good to hear there's going to be an option for this case :) |
Hi, I have the same problem... any update on this? |
I had the same issue. I'm using Sublime 3 and I fixed it by setting "atomic_save": false
|
This is hot reload html is absolute worked!!! Thank you man! |
The solution proposed by @ripeshade isn't working form me. The reload works, but i'ts a full reload. Any update? |
me too @ripeshade 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), |
Maybe this helps someone: This post shows some 2020 ( I needed to solve this scenario for integrating a single page application into a CMS page tree; in this case the TYPO3 CMS: The compiled index.html file is used as a CMS page template at the point in the page tree where the SPA should be located. The problem with My successful configuration to fix this issue was based on many comments here, but altered because the solutions posted above appear to be no longer compatible. I would have liked to extract the functionality into an actual plugin, but I did not find out how to gain access to the const fs = require('fs');
const path = require('path');
const { HotModuleReplacementPlugin } = require('webpack');
const WatchReportChangesPlugin = require('./webpack/plugins/watch-report-changes-plugin.js');
const BeforeCompileClearPageCachePlugin = require('./webpack/plugins/before-compile-clear-page-cache-plugin.js');
module.exports = {
publicPath: '/typo3conf/ext/my_sitepackage/Resources/Public/Build/SPA/',
outputDir: path.resolve(__dirname, '../../../Public/Build/SPA/'), // Used as TYPO3 `templateRootPaths.10`.
indexPath: 'Index.html',
configureWebpack: {
plugins: [
new WatchReportChangesPlugin(),
new BeforeCompileClearTYPO3PageCachePlugin(['spa_app']), // Tagged via TypoScript `stdWrap.addPageCacheTags`.
new HotModuleReplacementPlugin(),
]
},
devServer: {
// The dev server is running on the local host `https://mylocalmachine:8080/`.
// It is forced writing files to disk, to make sure that TYPO3
// can pick up the `Index.html` template for the SPA page,
// containing the initial assets. All assets changed during
// runtime are hot-reloaded through the webpack dev server.
//
// When changing the ./public/index.html Vue app base template,
// the `DelayedLiveReloadPlugin` below manually triggers a
// `liveReload` in the browser. The automatic `liveReload`
// is disabled, because it fires before any compilation
// has been done.
after: function(app, server, compiler) {
compiler.hooks.done.tapAsync(
'DelayedLiveReloadPlugin',
async (compilation, callback) => {
// Only look out for changed html files.
const watchFiles = ['.html'];
const changedFiles = Object.keys(
compiler.watchFileSystem.watcher.mtimes
);
// Send 'content-changed' socket message to manually tigger liveReload.
if (
this.hot &&
changedFiles.some(filePath => watchFiles.includes(path.parse(filePath).ext))
) {
server.sockWrite(server.sockets, "content-changed");
}
callback();
}
);
},
cert: fs.readFileSync('./webpack/tls/mylocalmachine.pem'), // `mkcert mylocalmachine`
disableHostCheck: true,
port: 8080,
host: '127.0.0.1',
hot: true,
https: true,
key: fs.readFileSync('./webpack/tls/mylocalmachine-key.pem'), // `mkcert mylocalmachine`
liveReload: false,
logLevel: 'debug',
writeToDisk: true, // Make sure TYPO3 can pick up the compiled file. By default webpack-dev-server does not emit.
}
}; Just for completeness, here's the const {
info,
execa,
} = require('@vue/cli-shared-utils');
class BeforeCompileClearTYPO3PageCachePlugin {
constructor(tags) {
this.tags = tags;
}
get tagsFormatted() {
return this.tags.join(', ');
}
apply(compiler) {
// Use async hook, so we can decide when the compilation should start.
compiler.hooks.beforeCompile.tapAsync(
'BeforeCompileClearTYPO3PageCachePlugin',
async (compilation, callback) => {
// Flush provided TYPO3 page cache tags before (re-)compiling source.
info(`Flush TYPO3 cache tags ${this.tagsFormatted}.`);
await execa(
'docker-compose',
[
'exec', '-T', 'www-php-cli', // Name of the php:7-cli-alpine docker-compose service.
'vendor/bin/typo3cms', 'cache:flushtags', this.tags.join(','),
'--groups', 'pages'
],
{
stdio: 'inherit',
}
);
// Start compilation now
callback();
}
);
}
}
module.exports = BeforeCompileClearTYPO3PageCachePlugin; Hope this helps someone. :) |
@LeoniePhiline It is under developers for v4, we will have |
@evilebottnawi Wow, fantastic news! Thanks for sharing. :) PS: The issue many here in this thread had was that in This might work well in cases where webpack-dev-server serves all files, including the index.html from memory, but it does not work in cases where you use E.g. my html-webpack-plugin template index.html contains not only tags like All I needed was to have the |
@LeoniePhiline yes, |
This is currently working for me with html-webpack-plugin^4.1.5, webpack^5.20.1, webpack-dev-server^3.11.2: devServer: {
watchContentBase: true,
contentBase: path.resolve(__dirname, 'dist'),
writeToDisk: true,
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './templates/home.html'
}), Key part is the |
@foxwoods369 for me this configuration just trigger the full reload of the page, it does not inject the changed code isn't HMR supposed to update the page without the full reload? |
Original bug was in |
For those still relying on
Instead it should be
migration-v4 tells us about the change from
webpack-dev-server/lib/Server.js Line 1590 in 2ea510c
For |
Thanks for sharing! |
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 |
You're missing the fact that since the initial issue was solved, we were looking for solutions where the generated html is consumed by a third party, like a content management system. |
Code
https://github.com/andreyvolokitin/test-webpack-dev-server
Expected Behavior
Editing
./src/index.html
should cause recompiling and page refresh in the browserActual 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-server
npm install && npm start
./src/index.html
— compiling is happening, but the page in the browser does not refresh./src/test.js
— HMR worksThe text was updated successfully, but these errors were encountered: