use parser state instead of module to store harmony/dynamic exports state

this is important for incremental build
This commit is contained in:
Tobias Koppers 2019-12-07 01:04:38 +01:00
parent be92913e58
commit 3b4a7455df
11 changed files with 68 additions and 69 deletions

View File

@ -218,7 +218,7 @@ class AMDDefineDependencyParserPlugin {
default:
return;
}
DynamicExports.bailout(parser.state.module);
DynamicExports.bailout(parser.state);
let fnParams = null;
let fnParamsOffset = 0;
if (fn) {

View File

@ -64,20 +64,20 @@ class CommonJsExportsParserPlugin {
*/
apply(parser) {
const enableStructuredExports = () => {
DynamicExports.enable(parser.state.module);
DynamicExports.enable(parser.state);
};
const checkNamespace = (members, valueExpr) => {
if (!DynamicExports.isEnabled(parser.state.module)) return;
if (!DynamicExports.isEnabled(parser.state)) return;
if (members.length > 0 && members[0] === "__esModule") {
if (isTruthyLiteral(valueExpr)) {
DynamicExports.setFlagged(parser.state.module);
DynamicExports.setFlagged(parser.state);
} else {
DynamicExports.bailout(parser.state.module);
DynamicExports.bailout(parser.state);
}
}
};
const bailout = () => {
DynamicExports.bailout(parser.state.module);
DynamicExports.bailout(parser.state);
};
// metadata //
@ -92,7 +92,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.assignMemberChain
.for("exports")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
enableStructuredExports();
checkNamespace(members, expr.right);
const dep = new CommonJsExportsDependency(
@ -107,7 +107,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.assignMemberChain
.for("this")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
if (!parser.scope.topLevelScope) return;
enableStructuredExports();
checkNamespace(members, expr.right);
@ -123,7 +123,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.assignMemberChain
.for("module")
.tap("CommonJsExportsParserPlugin", (expr, members) => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
if (members[0] !== "exports" || members.length <= 1) return;
enableStructuredExports();
checkNamespace(members, expr.right);
@ -176,7 +176,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.expression
.for("exports")
.tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
bailout();
const dep = new CommonJsSelfReferenceDependency(
expr.range,
@ -190,7 +190,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.expression
.for("module.exports")
.tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
bailout();
const dep = new CommonJsSelfReferenceDependency(
expr.range,
@ -204,7 +204,7 @@ class CommonJsExportsParserPlugin {
parser.hooks.expression
.for("this")
.tap("CommonJsExportsParserPlugin", expr => {
if (HarmonyExports.isEnabled(parser.state.module)) return;
if (HarmonyExports.isEnabled(parser.state)) return;
if (!parser.scope.topLevelScope) return;
bailout();
const dep = new CommonJsSelfReferenceDependency(expr.range, "this", []);
@ -216,7 +216,7 @@ class CommonJsExportsParserPlugin {
// Bailouts //
parser.hooks.expression.for("module").tap("CommonJsPlugin", expr => {
bailout();
const isHarmony = HarmonyExports.isEnabled(parser.state.module);
const isHarmony = HarmonyExports.isEnabled(parser.state);
const dep = new ModuleDecoratorDependency(
isHarmony
? RuntimeGlobals.harmonyModuleDecorator

View File

@ -5,53 +5,53 @@
"use strict";
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../Parser").ParserState} ParserState */
/** @type {WeakMap<NormalModule, boolean>} */
const moduleExportsState = new WeakMap();
/** @type {WeakMap<ParserState, boolean>} */
const parserStateExportsState = new WeakMap();
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @returns {void}
*/
exports.bailout = module => {
const value = moduleExportsState.get(module);
moduleExportsState.set(module, false);
exports.bailout = parserState => {
const value = parserStateExportsState.get(parserState);
parserStateExportsState.set(parserState, false);
if (value === true) {
module.buildMeta.exportsType = undefined;
module.buildMeta.defaultObject = false;
parserState.module.buildMeta.exportsType = undefined;
parserState.module.buildMeta.defaultObject = false;
}
};
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @returns {void}
*/
exports.enable = module => {
const value = moduleExportsState.get(module);
exports.enable = parserState => {
const value = parserStateExportsState.get(parserState);
if (value === false) return;
moduleExportsState.set(module, true);
parserStateExportsState.set(parserState, true);
if (value !== true) {
module.buildMeta.exportsType = "default";
module.buildMeta.defaultObject = "redirect";
parserState.module.buildMeta.exportsType = "default";
parserState.module.buildMeta.defaultObject = "redirect";
}
};
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @returns {void}
*/
exports.setFlagged = module => {
const value = moduleExportsState.get(module);
exports.setFlagged = parserState => {
const value = parserStateExportsState.get(parserState);
if (value !== true) return;
module.buildMeta.exportsType = "flagged";
parserState.module.buildMeta.exportsType = "flagged";
};
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @returns {boolean} true, when enabled
*/
exports.isEnabled = module => {
const value = moduleExportsState.get(module);
exports.isEnabled = parserState => {
const value = parserStateExportsState.get(parserState);
return value === true;
};

View File

@ -50,8 +50,8 @@ module.exports = class HarmonyDetectionParserPlugin {
index: -3
};
module.addPresentationalDependency(compatDep);
DynamicExports.bailout(module);
HarmonyExports.enable(module, isStrictHarmony);
DynamicExports.bailout(parser.state);
HarmonyExports.enable(parser.state, isStrictHarmony);
parser.scope.isStrict = true;
module.buildMeta.async = isAsync;
}
@ -64,7 +64,7 @@ module.exports = class HarmonyDetectionParserPlugin {
"The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)"
);
}
if (!HarmonyExports.isEnabled(parser.state.module)) {
if (!HarmonyExports.isEnabled(parser.state)) {
throw new Error(
"Top-level-await is only supported in EcmaScript Modules"
);
@ -73,13 +73,13 @@ module.exports = class HarmonyDetectionParserPlugin {
});
const skipInHarmony = () => {
if (HarmonyExports.isEnabled(parser.state.module)) {
if (HarmonyExports.isEnabled(parser.state)) {
return true;
}
};
const nullInHarmony = () => {
if (HarmonyExports.isEnabled(parser.state.module)) {
if (HarmonyExports.isEnabled(parser.state)) {
return null;
}
};

View File

@ -5,36 +5,36 @@
"use strict";
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../Parser").ParserState} ParserState */
/** @type {WeakMap<NormalModule, boolean>} */
const moduleExportsState = new WeakMap();
/** @type {WeakMap<ParserState, boolean>} */
const parserStateExportsState = new WeakMap();
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @param {boolean} isStrictHarmony strict harmony mode should be enabled
* @returns {void}
*/
exports.enable = (module, isStrictHarmony) => {
const value = moduleExportsState.get(module);
exports.enable = (parserState, isStrictHarmony) => {
const value = parserStateExportsState.get(parserState);
if (value === false) return;
moduleExportsState.set(module, true);
parserStateExportsState.set(parserState, true);
if (value !== true) {
module.buildMeta.exportsType = "namespace";
module.buildInfo.strict = true;
module.buildInfo.exportsArgument = "__webpack_exports__";
parserState.module.buildMeta.exportsType = "namespace";
parserState.module.buildInfo.strict = true;
parserState.module.buildInfo.exportsArgument = "__webpack_exports__";
if (isStrictHarmony) {
module.buildMeta.strictHarmonyModule = true;
module.buildInfo.moduleArgument = "__webpack_module__";
parserState.module.buildMeta.strictHarmonyModule = true;
parserState.module.buildInfo.moduleArgument = "__webpack_module__";
}
}
};
/**
* @param {NormalModule} module the module
* @param {ParserState} parserState parser state
* @returns {boolean} true, when enabled
*/
exports.isEnabled = module => {
const value = moduleExportsState.get(module);
exports.isEnabled = parserState => {
const value = parserStateExportsState.get(parserState);
return value === true;
};

View File

@ -169,7 +169,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
hotAcceptCallback.tap(
"HarmonyImportDependencyParserPlugin",
(expr, requests) => {
if (!HarmonyExports.isEnabled(parser.state.module)) {
if (!HarmonyExports.isEnabled(parser.state)) {
// This is not a harmony module, skip it
return;
}
@ -193,7 +193,7 @@ module.exports = class HarmonyImportDependencyParserPlugin {
hotAcceptWithoutCallback.tap(
"HarmonyImportDependencyParserPlugin",
(expr, requests) => {
if (!HarmonyExports.isEnabled(parser.state.module)) {
if (!HarmonyExports.isEnabled(parser.state)) {
// This is not a harmony module, skip it
return;
}

View File

@ -14,7 +14,7 @@ class HarmonyTopLevelThisParserPlugin {
.for("this")
.tap("HarmonyTopLevelThisParserPlugin", node => {
if (!parser.scope.topLevelScope) return;
if (HarmonyExports.isEnabled(parser.state.module)) {
if (HarmonyExports.isEnabled(parser.state)) {
const dep = new ConstDependency("undefined", node.range, null);
dep.loc = node.loc;
parser.state.module.addPresentationalDependency(dep);

View File

@ -7,9 +7,8 @@
const ChunkGraph = require("../ChunkGraph");
const ModuleGraph = require("../ModuleGraph");
const NormalModule = require("../NormalModule");
const { STAGE_DEFAULT } = require("../OptimizationStages");
const HarmonyExports = require("../dependencies/HarmonyExports");
const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency");
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency");
const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency");
@ -114,9 +113,9 @@ class ModuleConcatenationPlugin {
if (
!module.buildMeta ||
module.buildMeta.exportsType !== "namespace" ||
!(
module instanceof NormalModule &&
HarmonyExports.isEnabled(module)
module.presentationalDependencies === undefined ||
!module.presentationalDependencies.some(
d => d instanceof HarmonyCompatibilityDependency
)
) {
setBailoutReason(module, "Module is not an ECMAScript module");

View File

@ -4,8 +4,8 @@ it("should abort when module is declined by parent", (done) => {
expect(a).toBe(1);
NEXT(require("../../update")((err) => {
try {
expect(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/.test(err.message)).toBe(true);
expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/.test(err.message)).toBe(true);
expect(err.message).toMatch(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/);
expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/);
done();
} catch(e) {
done(e);

View File

@ -4,8 +4,8 @@ it("should abort when module is declined by itself", (done) => {
expect(a).toBe(1);
NEXT(require("../../update")((err) => {
try {
expect(/Aborted because of self decline: \.\/a\.js/.test(err.message)).toBe(true);
expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/.test(err.message)).toBe(true);
expect(err.message).toMatch(/Aborted because of self decline: \.\/a\.js/);
expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/);
done();
} catch(e) {
done(e);

View File

@ -6,8 +6,8 @@ it("should abort when module is not accepted", (done) => {
expect(b).toBe(1);
NEXT(require("../../update")((err) => {
try {
expect(/Aborted because \.\/c\.js is not accepted/.test(err.message)).toBe(true);
expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/index\.js/.test(err.message)).toBe(true);
expect(err.message).toMatch(/Aborted because \.\/c\.js is not accepted/);
expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/index\.js/);
done();
} catch(e) { done(e); }
}));