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

Options.cache does not prevent unchanged HTML pages from being rebuilt in watch mode #962

Closed
dwoznicki opened this issue May 31, 2018 · 8 comments

Comments

@dwoznicki
Copy link

dwoznicki commented May 31, 2018

Background

I'm using html-webpack-plugin to generate around 25 HTML files for my project. These pages are basically static and rarely need to be rebuilt.

Problem

When running webpack in watch mode, changes to any file causes all HTML files to be rebuilt, even when options.cache is set to true. This increases the build time from ~500ms to ~3000ms.

Cause

The cache check on line 132 of index.js is never reached because isCompilationCached always comes back false. This is because compilationResult.hash (line 81) changes on every recompile.

Possible fix

I can fix this behavior by removing the check for isCompilationCached on line 132.

//if (isCompilationCached && self.options.cache && assetJson === self.assetJson) {
if (self.options.cache && assetJson === self.assetJson) {

This solves the issue for my needs, but I'm not sure what the implications of making this change are.

Edit: This change causes the "HtmlWebpackPluginCaching should compile the webpack html if the template file was changed" test to fail. This never comes up for my specific use case as the template file does not change, but I'm thinking my use case might be more of a feature request.
Related: #963

Environment

Node.js v8.11.1
linux 4.12.0-041200rc1-generic
npm version 5.6.0
webpack@4.5.0
html-webpack-plugin@3.2.0
@wxlworkhard
Copy link

isCompilationCached is to mark if the template file is changed.
A HtmlWebpackPlugin instance correspond to a webpack chunk.
compilationResult.hash is this chunk's hash.

However after webpack upgrade to version 4,compilationResult.hash is always changes even I do not change template file, Why?

compilationResult.hash(chunk's hash) is generate by chunk.id chunk.ids chunk.name chunk._modules. You can see webpack/lib/Chunk.js file at line 407 the updateHash method.

In webpack@4, the id is change between 1 and 0 every time when you change any file. I know that id is always 0 in webpack@2.3.3. The same chunk's id should not change.

The chunk.id change lead to compilationResult.hash change and isCompilationCached is always false.

My suggestion is to provide an unit key when new HtmlWebpackPlugin and pass the key to new SingleEntryPlugin.

In html-webpack-plugin/index.js at line 37 file:

constructor (options) {
    this.options = _.extend({
      template: path.join(__dirname, 'default_index.ejs'),
      ...
      xhtml: false
    }, options, {
         // Add entryKey!!!
        entryKey: 'html-webpack-plugin' + Math.random().toFixed(5)
    });
  }

and in html-webpack-plugin/lib/compiler.js at line 55 file:

// Change undefined to entryKey!!!
new SingleEntryPlugin(this.context, template, htmlWebpackPlugin.options.entryKey).apply(childCompiler);

@jantimon
Copy link
Owner

jantimon commented Jun 1, 2018

Hey @dwoznicki @wxlworkhard

thanks for looking into the performance of the plugin - I am very very happy for your support.
I would love to ship an improved performance for the version 4.x of the plugin (#953).

For multiple html files the performance is quite low.
There are different reasons for that.

If you add multiple instances of the html-webpack-plugin the plugin attaches multiple child compiler to webpack. To suggestion on how we might improve:

1. Reduce the amount of child compilers

We could create a WeakMap which would store the ChildCompiler for the current compilation.

Pseudo code (just to illustrate the concept)

const htmlWebpackPluginCompilers = new WeakMap({});

// ...

// in the make phase compilation:
if (!htmlWebpackPluginCompiler[compilation]) {
   htmlWebpackPluginCompiler[compilation] = createChildCompiler(compilation);
}
// Add the current template path:
htmlWebpackPluginCompiler[compilation].addTemplate(options.template);

This would reduce the amount of child compilers to one even if there are many different templates.

2. Track the timestamps of the compilation instead of the hash

@sokra suggested that we might use the timestamps of all dependencies to check if we need to recompile at all like the normal module does: https://github.com/webpack/webpack/blob/3415a983301bbaeffd1bf250e3c7b139a392315b/lib/NormalModule.js#L463-L485

We could store all files of our dependency tree and the time of the compilation.
We can then check (once) if for the current compilation a dependent file has a newer timestamp.
Otherwise we won't have to recompile and would fix the performance issue described by @dwoznicki

@dwoznicki
Copy link
Author

dwoznicki commented Jun 3, 2018

See #965 for a possible solution to 2. Track the timestamps of the compilation instead of the hash

@jantimon
Copy link
Owner

jantimon commented Jun 3, 2018

I opened a pr #967 which managed to solve "1. Reduce the amount of child compilers" and still passes all tests.

It also knows which files where involved so maybe we can get "2. Track the timestamps of the compilation instead of the hash" also done.

@jantimon
Copy link
Owner

jantimon commented Jun 8, 2018

The second part is done in #972 - @dwoznicki could you please take a look? :)

@dwoznicki
Copy link
Author

@jantimon Build time drops from ~8000ms to ~1000ms with changes in #972. I'm considering this resolved pending the release of the webpack-4 branch.

@jantimon
Copy link
Owner

@lock
Copy link

lock bot commented Oct 11, 2018

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 11, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants