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

some small fix #162

Closed
wants to merge 3 commits into from
Closed

some small fix #162

wants to merge 3 commits into from

Conversation

anjianshi
Copy link
Contributor

No description provided.

The problem's trace:

for example, you use `new HtmlWebpackPlugin(...)` **two** times in webpack.config.js, so HtmlWebpackPlugin will register emitHandler to webpack compiler two times too

when webpack emit assets, it calls `this.applyPluginsAsync()` (see `Compiler.prototype.emitAssets()` in `webpack/lib/Compiler.js`), this method is from `Tapable.prototype.applyPluginsAsync` (https://github.com/webpack/tapable/blob/master/lib/Tapable.js), it will nested the two emitHandler registered by HtmlWebpackPlugin, so when the first emitHandler execute finish and call the callback, the second emitHandler will be called **inside** the first emitHandler.

```js
function emitHandler(compilation, callback) {
    Promise.resolve()
        .then(function() {
            // do some thing...
        })
        .then(callback);
}

var registeredPlugins = {"emit": [emitHandler, emitHandler]};

function applyPluginsAsync(name, ...args, finish) {
    var plugins = registeredPlugins[name];
    var i = -1;
    var next = function() {
        i++;
        if(i == plugins.length) {
            finish();
        } else {
            plugins[i](...args, next);
        }
    }
    next();
}

applyPluginsAsync(compilation, function finish() { /* do some thing... */ });
```

The simplified version is like this:

```js
function firstEmitHandler() {
    Promise.resolve().then(function firstInner() {
        secondHandler();
    });
}

function secondEmitHandler() {
    Promise.resolve().then(function secondInner() {
        finish();
    });
}

firstEmitHandler();
```

There's some promise created in `firstInner` (by `secondEmitHandler`), but the `firstInner` returns `undefined`.
So `Bluebird` thinks this may be a programmer error, and makes a warning.

To resolve this problem, just let `firstInner` return something other then `undefined`.
…urce available") in webpack watch mode.

example webpack.config.js:

```js
module.exports = {
    entry: {a: "./src/a.js", b: "./src/b.js"}
    debug: true,
    output: {
        path: "./var",
    },
    plugins: [
        new HtmlWebpackPlugin({filename: "a.html", template: "./src/template.html"}),   // a.html
        new HtmlWebpackPlugin({filename: "b.html", template: "./src/template.html"}),   // b.html
    ]
};
```

These html file use the same template.
In webpack watch mode, at first, they all can successful compile, but now if you edit `./src/template.html`, only `a.html` can successful compile again, `b.html`'s content will change to "HtmlWebpackPlugin Error: No source available".

I think this is because webpack cached the module (a `NormalModel`) of `a.html`, and when `b.html` going to compiling, it reused the cached one.
In the first compilation, everything is ok, but in second compilation, `b.html` was compiled **before** `a.html` (don't know why),
it used `a.html`'s module before the module fully initialized. So the `_source` property of this module is `null`, and the compilation of `b.html` was failed.

The trace is:

```
Compiler.runAsChild -> Compiler.compile -> this.applyPluginsParallel("make") -> Compilation.addEntry -> Compilation._addModuleChain -> this.addModule(module)
```

To resolve this problem, I created a queue: `compileQueue`.
If two or many child compiler use the same template, the second one will wait for first one compile complete, then start it's own compilation.

I don't know if this is a good solution, or if this is the real reason of causing this bug, what do you think?
@jantimon
Copy link
Owner

Please describe what you did and make sure that all tests pass.

@@ -13,6 +13,10 @@ var LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
var LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');

var compileQueue = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the global

@jantimon jantimon closed this Jan 11, 2016
@anjianshi
Copy link
Contributor Author

All descriptions are in the commit message.
https://github.com/ampedandwired/html-webpack-plugin/pull/162/commits

@anjianshi
Copy link
Contributor Author

@jantimon

@jantimon
Copy link
Owner

Oh okay sorry just read through it.

I have added a new test case which passes: 3f16e34

Right now I try to investigate how we could test the recompilation.

@jantimon jantimon reopened this Jan 11, 2016
@jantimon
Copy link
Owner

Okay the problem seems to be the "inParallel" this allows b to run before a in some cases.

@jantimon
Copy link
Owner

What do you think about 62d7cfb ?

@anjianshi
Copy link
Contributor Author

very nice! :)

@jantimon
Copy link
Owner

Cool 👍

@jantimon jantimon closed this Jan 11, 2016
@jantimon
Copy link
Owner

Hey @anjianshi - just wanted to let you know that sokras subcache #179 solved "HtmlWebpackPlugin Error: No source available" and we can drop the promise queue

@anjianshi
Copy link
Contributor Author

oh, thanks! happy to see this

@lock
Copy link

lock bot commented May 31, 2018

This pull request 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 May 31, 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

Successfully merging this pull request may close these issues.

2 participants