compilation error don't affect parent module

recover after syntax error
assume es6 module on syntax error

#2117
This commit is contained in:
Tobias Koppers 2016-07-03 13:13:01 +02:00
parent bd35d4f65d
commit 1ee3585fa1
17 changed files with 156 additions and 85 deletions

View File

@ -112,8 +112,9 @@ Compilation.prototype.findModule = function(identifier) {
return this._modules[identifier];
};
Compilation.prototype.buildModule = function(module, thisCallback) {
this.applyPlugins("build-module", module);
Compilation.prototype.buildModule = function(module, optional, origin, dependencies, thisCallback) {
var _this = this;
_this.applyPlugins("build-module", module);
if(module.building) return module.building.push(thisCallback);
var building = module.building = [thisCallback];
@ -123,22 +124,28 @@ Compilation.prototype.buildModule = function(module, thisCallback) {
cb(err);
});
}
module.build(this.options, this, this.resolvers.normal, this.inputFileSystem, function(err) {
module.build(_this.options, this, _this.resolvers.normal, _this.inputFileSystem, function(err) {
module.errors.forEach(function(err) {
this.errors.push(err);
err.origin = origin;
err.dependencies = dependencies;
if(optional)
_this.warnings.push(err);
else
_this.errors.push(err);
}, this);
module.warnings.forEach(function(err) {
this.warnings.push(err);
err.origin = origin;
err.dependencies = dependencies;
_this.warnings.push(err);
}, this);
module.dependencies.sort(Dependency.compare);
if(err) {
module.error = err;
this.applyPlugins("failed-module", module);
_this.applyPlugins("failed-module", module, err);
return callback(err);
}
this.applyPlugins("succeed-module", module);
_this.applyPlugins("succeed-module", module);
return callback();
}.bind(this));
});
};
Compilation.prototype.processModuleDependencies = function(module, callback) {
@ -186,9 +193,7 @@ Compilation.prototype.addModuleDependencies = function(module, dependencies, bai
var dependencies = item[1];
var errorAndCallback = function errorAndCallback(err) {
err.dependencies = dependencies;
err.origin = module;
module.dependenciesErrors.push(err);
_this.errors.push(err);
if(bail) {
callback(err);
@ -197,9 +202,7 @@ Compilation.prototype.addModuleDependencies = function(module, dependencies, bai
}
};
var warningAndCallback = function warningAndCallback(err) {
err.dependencies = dependencies;
err.origin = module;
module.dependenciesWarnings.push(err);
_this.warnings.push(err);
callback();
};
@ -220,7 +223,7 @@ Compilation.prototype.addModuleDependencies = function(module, dependencies, bai
}
}
if(err) {
return errorOrWarningAndCallback(new ModuleNotFoundError(module, err));
return errorOrWarningAndCallback(new ModuleNotFoundError(module, err, dependencies));
}
if(!dependentModule) {
return process.nextTick(callback);
@ -233,7 +236,7 @@ Compilation.prototype.addModuleDependencies = function(module, dependencies, bai
dependentModule.profile.factory = afterFactory - start;
}
dependentModule.issuer = module.identifier();
dependentModule.issuer = module;
var newModule = _this.addModule(dependentModule, cacheGroup);
if(!newModule) { // from cache
@ -294,7 +297,7 @@ Compilation.prototype.addModuleDependencies = function(module, dependencies, bai
dependentModule.addReason(module, dep);
});
_this.buildModule(dependentModule, function(err) {
_this.buildModule(dependentModule, isOptional(), module, dependencies, function(err) {
if(err) {
return errorOrWarningAndCallback(err);
}
@ -383,7 +386,7 @@ Compilation.prototype._addModuleChain = function process(context, dependency, on
onModule(module);
this.buildModule(module, function(err) {
this.buildModule(module, false, null, null, function(err) {
if(err) {
return errorAndCallback(err);
}
@ -455,7 +458,7 @@ Compilation.prototype.rebuildModule = function(module, thisCallback) {
});
}
var deps = module.dependencies.slice();
this.buildModule(module, function(err) {
this.buildModule(module, false, module, null, function(err) {
if(err) return callback(err);
this.processModuleDependencies(module, function(err) {
@ -658,10 +661,6 @@ Compilation.prototype.processDependenciesBlockForChunk = function processDepende
if(d.weak) {
return;
}
if(d.module.error) {
d.module = null;
return;
}
if(chunk.addModule(d.module)) {
d.module.addChunk(chunk);
this.processDependenciesBlockForChunk(d.module, chunk);

View File

@ -26,6 +26,7 @@ function Module() {
this.errors = [];
this.dependenciesErrors = [];
this.strict = false;
this.meta = {};
}
module.exports = Module;

View File

@ -2,7 +2,7 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
function ModuleNotFoundError(module, err) {
function ModuleNotFoundError(module, err, dependencies) {
Error.call(this);
Error.captureStackTrace(this, ModuleNotFoundError);
this.name = "ModuleNotFoundError";
@ -10,6 +10,8 @@ function ModuleNotFoundError(module, err) {
this.details = err.details;
this.missing = err.missing;
this.module = module;
this.origin = module;
this.dependencies = dependencies;
this.error = err;
}
module.exports = ModuleNotFoundError;

View File

@ -43,7 +43,6 @@ function NormalModule(request, userRequest, rawRequest, loaders, resource, parse
this.errors = [];
this.error = null;
this._source = null;
this.meta = {};
this.assets = {};
this.built = false;
this._cachedSource = null;
@ -135,8 +134,7 @@ NormalModule.prototype.doBuild = function doBuild(options, compilation, resolver
module.contextDependencies = result.contextDependencies;
}
if(err) {
module.error = err;
return callback(new ModuleBuildError(module, err));
return callback(module.error = new ModuleBuildError(module, err));
}
var resourceBuffer = result.resourceBuffer;
@ -144,8 +142,7 @@ NormalModule.prototype.doBuild = function doBuild(options, compilation, resolver
var sourceMap = result.result[1];
if(!Buffer.isBuffer(source) && typeof source !== "string") {
module.error = new Error("Final loader didn't return a Buffer or String");
return callback(new ModuleBuildError(module, module.error));
return callback(module.error = new ModuleBuildError(module, new Error("Final loader didn't return a Buffer or String")));
}
source = asString(source);
if(module.identifier && module.lineToLine && resourceBuffer) {
@ -168,41 +165,54 @@ NormalModule.prototype.disconnect = function disconnect() {
};
NormalModule.prototype.build = function build(options, compilation, resolver, fs, callback) {
this.buildTimestamp = new Date().getTime();
this.built = true;
return this.doBuild(options, compilation, resolver, fs, function(err) {
if(err) return callback(err);
this.dependencies.length = 0;
this.variables.length = 0;
this.blocks.length = 0;
this._cachedSource = null;
var _this = this;
_this.buildTimestamp = new Date().getTime();
_this.built = true;
_this._source = null;
_this.error = null;
return _this.doBuild(options, compilation, resolver, fs, function(err) {
_this.dependencies.length = 0;
_this.variables.length = 0;
_this.blocks.length = 0;
_this._cachedSource = null;
if(err) return setError(err);
if(options.module && options.module.noParse) {
function testRegExp(regExp) {
return typeof regExp === "string" ?
this.request.indexOf(regExp) === 0 :
regExp.test(this.request);
_this.request.indexOf(regExp) === 0 :
regExp.test(_this.request);
}
if(Array.isArray(options.module.noParse)) {
if(options.module.noParse.some(testRegExp, this))
if(options.module.noParse.some(testRegExp, _this))
return callback();
} else if(testRegExp.call(this, options.module.noParse)) {
} else if(testRegExp.call(_this, options.module.noParse)) {
return callback();
}
}
try {
this.parser.parse(this._source.source(), {
current: this,
module: this,
_this.parser.parse(_this._source.source(), {
current: _this,
module: _this,
compilation: compilation,
options: options
});
} catch(e) {
var source = this._source.source();
this._source = null;
return callback(new ModuleParseError(this, source, e));
var source = _this._source.source();
return setError(_this.error = new ModuleParseError(_this, source, e));
}
return callback();
}.bind(this));
});
function setError(err) {
_this.meta = null;
if(_this.error) {
_this.errors.push(_this.error);
_this._source = new RawSource("throw new Error(" + JSON.stringify(_this.error.message) + ");");
} else {
_this._source = new RawSource("throw new Error('Module build failed');");
}
callback();
}
};
NormalModule.prototype.source = function(dependencyTemplates, outputOptions, requestShortener) {

View File

@ -116,6 +116,11 @@ Stats.prototype.toJson = function toJson(options, forToString) {
text += " " + dep.loc.start.line + ":" + dep.loc.start.column + "-" +
(dep.loc.start.line !== dep.loc.end.line ? dep.loc.end.line + ":" : "") + dep.loc.end.column;
});
var current = e.origin;
while(current.issuer) {
current = current.issuer;
text += "\n @ " + current.readableIdentifier(requestShortener);
}
}
return text;
}
@ -203,7 +208,9 @@ Stats.prototype.toJson = function toJson(options, forToString) {
return chunk.id;
}),
assets: Object.keys(module.assets || {}),
issuer: module.issuer,
issuer: module.issuer && module.issuer.identifier(),
issuerId: module.issuer && module.issuer.id,
issuerName: module.issuer && module.issuer.readableIdentifier(requestShortener),
profile: module.profile,
failed: !!module.error,
errors: module.errors && module.dependenciesErrors && (module.errors.length + module.dependenciesErrors.length),
@ -465,17 +472,11 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
function processProfile(module) {
if(module.profile) {
colors.normal(" ");
var sum = 0,
allowSum = true;
var sum = 0;
var path = [];
var current = module;
while(current.issuer) {
if(!modulesByIdentifier["$" + current.issuer]) {
colors.normal(" ... ->");
allowSum = false;
break;
}
path.unshift(current = modulesByIdentifier["$" + current.issuer]);
path.unshift(current = current.issuer);
}
path.forEach(function(module) {
colors.normal(" [");
@ -495,10 +496,8 @@ Stats.jsonToString = function jsonToString(obj, useColors) {
coloredTime(time);
sum += time;
});
if(allowSum) {
colors.normal(" = ");
coloredTime(sum);
}
colors.normal(" = ");
coloredTime(sum);
newline();
}
}

View File

@ -63,7 +63,7 @@ HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep
content = "/* unused harmony reexport " + dep.name + " */\n";
} else if(!active) { // we want to reexport something but another exports overrides this one
content = "/* inactive harmony reexport " + (dep.name || "namespace") + " */\n";
} else if(dep.name && dep.id === "default" && !(importedModule && importedModule.meta && importedModule.meta.harmonyModule)) { // we want to reexport the default export from a non-hamory module
} else if(dep.name && dep.id === "default" && !(importedModule && (!importedModule.meta || importedModule.meta.harmonyModule))) { // we want to reexport the default export from a non-hamory module
content = "/* harmony reexport */ " + getReexportStatement(JSON.stringify(used), null) + "\n";
} else if(dep.name && dep.id) { // we want to reexport a key as new key
var idUsed = importedModule && importedModule.isUsed(dep.id);
@ -72,7 +72,7 @@ HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep
content = "/* harmony reexport */ " + getReexportStatement(JSON.stringify(used), "") + "\n";
} else if(Array.isArray(dep.originModule.usedExports)) { // we know which exports are used
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule);
var importIsHarmony = importedModule && importedModule.meta.harmonyModule;
var importIsHarmony = importedModule && (!importedModule.meta || importedModule.meta.harmonyModule);
var importActiveExports = importedModule && HarmonyModulesHelpers.getActiveExports(importedModule);
var items = dep.originModule.usedExports.map(function(id) {
if(id === "default") return;

View File

@ -25,7 +25,7 @@ HarmonyImportDependency.prototype.getReference = function() {
HarmonyImportDependency.prototype.updateHash = function updateHash(hash) {
ModuleDependency.prototype.updateHash.call(this, hash);
hash.update((this.module && this.module.meta && this.module.meta.harmonyModule) + "");
hash.update((this.module && (!this.module.meta || this.module.meta.harmonyModule)) + "");
};
HarmonyImportDependency.makeStatement = function(declare, dep, outputOptions, requestShortener) {

View File

@ -47,7 +47,7 @@ HarmonyImportSpecifierDependency.prototype.updateHash = function(hash) {
hash.update((importedModule && this.id) + "");
hash.update((importedModule && this.importedVar) + "");
hash.update((importedModule && this.id && importedModule.isUsed(this.id)) + "");
hash.update((importedModule && importedModule.meta && importedModule.meta.harmonyModule) + "");
hash.update((importedModule && (!importedModule.meta || importedModule.meta.harmonyModule)) + "");
hash.update((importedModule && (importedModule.used + JSON.stringify(importedModule.usedExports))) + "");
};
@ -56,7 +56,7 @@ HarmonyImportSpecifierDependency.Template = function HarmonyImportSpecifierDepen
HarmonyImportSpecifierDependency.Template.prototype.apply = function(dep, source) {
var content;
var importedModule = dep.importDependency.module;
var defaultImport = dep.id === "default" && !(importedModule && importedModule.meta && importedModule.meta.harmonyModule);
var defaultImport = dep.id === "default" && !(importedModule && (!importedModule.meta || importedModule.meta.harmonyModule));
if(defaultImport) {
content = dep.importedVar + "_default.a";
} else if(dep.id) {

View File

@ -77,8 +77,8 @@ describe("HotTestCases", function() {
var jsonStats = stats.toJson({
errorDetails: true
});
if(checkArrayExpectation(testDirectory, jsonStats, "error", "Error", done)) return;
if(checkArrayExpectation(testDirectory, jsonStats, "warning", "Warning", done)) return;
if(checkArrayExpectation(testDirectory, jsonStats, "error", "errors" + options.updateIndex, "Error", done)) return;
if(checkArrayExpectation(testDirectory, jsonStats, "warning", "warnings" + options.updateIndex, "Warning", done)) return;
if(callback) callback();
})
}

View File

@ -1,13 +1,18 @@
var fs = require("fs");
var path = require("path");
module.exports = function checkArrayExpectation(testDirectory, object, kind, upperCaseKind, done) {
module.exports = function checkArrayExpectation(testDirectory, object, kind, filename, upperCaseKind, done) {
if(!done) {
done = upperCaseKind;
upperCaseKind = filename;
filename = kind + "s";
}
var array = object[kind + "s"].slice().sort();
if(kind === "warning") array = array.filter(function(item) {
return !/from UglifyJs/.test(item);
});
if(fs.existsSync(path.join(testDirectory, kind + "s.js"))) {
var expected = require(path.join(testDirectory, kind + "s.js"));
if(fs.existsSync(path.join(testDirectory, filename + ".js"))) {
var expected = require(path.join(testDirectory, filename + ".js"));
if(expected.length < array.length)
return done(new Error("More " + kind + "s while compiling than expected:\n\n" + array.join("\n\n"))), true;
else if(expected.length > array.length)

View File

@ -0,0 +1,6 @@
export default 1;
---
export default 2;
throw new Error("Failed");
---
export default 3;

View File

@ -0,0 +1,20 @@
import a from "./a";
it("should abort when module is not accepted", function(done) {
a.should.be.eql(1);
NEXT(require("../../update")(done, {
ignoreErrored: true
}, function() {
a.should.be.eql(1);
NEXT(require("../../update")(done, {
ignoreErrored: true
}, function() {
a.should.be.eql(3);
done();
}));
}));
});
if(module.hot) {
module.hot.accept("./a");
}

View File

@ -0,0 +1,6 @@
export default 1;
---
]});
export default 2;
---
export default 3;

View File

@ -0,0 +1,3 @@
module.exports = [
[/Module parse failed/]
]

View File

@ -0,0 +1,20 @@
import a from "./a";
it("should abort when module is not accepted", function(done) {
a.should.be.eql(1);
NEXT(require("../../update")(done, {
ignoreErrored: true
}, function() {
a.should.be.eql(1);
NEXT(require("../../update")(done, {
ignoreErrored: true
}, function() {
a.should.be.eql(3);
done();
}));
}));
});
if(module.hot) {
module.hot.accept("./a");
}

View File

@ -9,41 +9,41 @@ chunk {0} bundle.js (main) 73 bytes [rendered]
> main [5] (webpack)/test/statsCases/chunks/index.js
[0] (webpack)/test/statsCases/chunks/a.js 22 bytes {0} [built]
cjs require ./a [5] (webpack)/test/statsCases/chunks/index.js 1:0-14
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[5] (webpack)/test/statsCases/chunks/index.js 51 bytes {0} [built]
factory:Xms building:Xms = Xms
chunk {1} 1.bundle.js 54 bytes {0} [rendered]
> [5] (webpack)/test/statsCases/chunks/index.js 3:0-16
[2] (webpack)/test/statsCases/chunks/c.js 54 bytes {1} [built]
amd require ./c [5] (webpack)/test/statsCases/chunks/index.js 3:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
chunk {2} 2.bundle.js 22 bytes {0} [rendered]
> [5] (webpack)/test/statsCases/chunks/index.js 2:0-16
[1] (webpack)/test/statsCases/chunks/b.js 22 bytes {2} [built]
amd require ./b [5] (webpack)/test/statsCases/chunks/index.js 2:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
chunk {3} 3.bundle.js 44 bytes {1} [rendered]
> [2] (webpack)/test/statsCases/chunks/c.js 1:0-52
[3] (webpack)/test/statsCases/chunks/d.js 22 bytes {3} [built]
require.ensure item ./d [2] (webpack)/test/statsCases/chunks/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[4] (webpack)/test/statsCases/chunks/e.js 22 bytes {3} [built]
require.ensure item ./e [2] (webpack)/test/statsCases/chunks/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[0] (webpack)/test/statsCases/chunks/a.js 22 bytes {0} [built]
cjs require ./a [5] (webpack)/test/statsCases/chunks/index.js 1:0-14
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[1] (webpack)/test/statsCases/chunks/b.js 22 bytes {2} [built]
amd require ./b [5] (webpack)/test/statsCases/chunks/index.js 2:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[2] (webpack)/test/statsCases/chunks/c.js 54 bytes {1} [built]
amd require ./c [5] (webpack)/test/statsCases/chunks/index.js 3:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[3] (webpack)/test/statsCases/chunks/d.js 22 bytes {3} [built]
require.ensure item ./d [2] (webpack)/test/statsCases/chunks/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[4] (webpack)/test/statsCases/chunks/e.js 22 bytes {3} [built]
require.ensure item ./e [2] (webpack)/test/statsCases/chunks/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[5] (webpack)/test/statsCases/chunks/index.js 51 bytes {0} [built]
factory:Xms building:Xms = Xms

View File

@ -8,21 +8,21 @@ main.js 5.28 kB 0 [emitted] main
chunk {0} main.js (main) 73 bytes [rendered]
[0] (webpack)/test/statsCases/preset-verbose/a.js 22 bytes {0} [built]
cjs require ./a [5] (webpack)/test/statsCases/preset-verbose/index.js 1:0-14
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[5] (webpack)/test/statsCases/preset-verbose/index.js 51 bytes {0} [built]
factory:Xms building:Xms = Xms
chunk {1} 1.js 54 bytes {0} [rendered]
[2] (webpack)/test/statsCases/preset-verbose/c.js 54 bytes {1} [built]
amd require ./c [5] (webpack)/test/statsCases/preset-verbose/index.js 3:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
chunk {2} 2.js 22 bytes {0} [rendered]
[1] (webpack)/test/statsCases/preset-verbose/b.js 22 bytes {2} [built]
amd require ./b [5] (webpack)/test/statsCases/preset-verbose/index.js 2:0-16
[5] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
chunk {3} 3.js 44 bytes {1} [rendered]
[3] (webpack)/test/statsCases/preset-verbose/d.js 22 bytes {3} [built]
require.ensure item ./d [2] (webpack)/test/statsCases/preset-verbose/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms
[4] (webpack)/test/statsCases/preset-verbose/e.js 22 bytes {3} [built]
require.ensure item ./e [2] (webpack)/test/statsCases/preset-verbose/c.js 1:0-52
[5] Xms -> [2] Xms -> factory:Xms building:Xms = Xms
[] -> factory:Xms building:Xms = Xms