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: default:
return; return;
} }
DynamicExports.bailout(parser.state.module); DynamicExports.bailout(parser.state);
let fnParams = null; let fnParams = null;
let fnParamsOffset = 0; let fnParamsOffset = 0;
if (fn) { if (fn) {

View File

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

View File

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

View File

@ -50,8 +50,8 @@ module.exports = class HarmonyDetectionParserPlugin {
index: -3 index: -3
}; };
module.addPresentationalDependency(compatDep); module.addPresentationalDependency(compatDep);
DynamicExports.bailout(module); DynamicExports.bailout(parser.state);
HarmonyExports.enable(module, isStrictHarmony); HarmonyExports.enable(parser.state, isStrictHarmony);
parser.scope.isStrict = true; parser.scope.isStrict = true;
module.buildMeta.async = isAsync; 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)" "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( throw new Error(
"Top-level-await is only supported in EcmaScript Modules" "Top-level-await is only supported in EcmaScript Modules"
); );
@ -73,13 +73,13 @@ module.exports = class HarmonyDetectionParserPlugin {
}); });
const skipInHarmony = () => { const skipInHarmony = () => {
if (HarmonyExports.isEnabled(parser.state.module)) { if (HarmonyExports.isEnabled(parser.state)) {
return true; return true;
} }
}; };
const nullInHarmony = () => { const nullInHarmony = () => {
if (HarmonyExports.isEnabled(parser.state.module)) { if (HarmonyExports.isEnabled(parser.state)) {
return null; return null;
} }
}; };

View File

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

View File

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

View File

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

View File

@ -7,9 +7,8 @@
const ChunkGraph = require("../ChunkGraph"); const ChunkGraph = require("../ChunkGraph");
const ModuleGraph = require("../ModuleGraph"); const ModuleGraph = require("../ModuleGraph");
const NormalModule = require("../NormalModule");
const { STAGE_DEFAULT } = require("../OptimizationStages"); const { STAGE_DEFAULT } = require("../OptimizationStages");
const HarmonyExports = require("../dependencies/HarmonyExports"); const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency");
const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency"); const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency");
const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency"); const ModuleHotDeclineDependency = require("../dependencies/ModuleHotDeclineDependency");
@ -114,9 +113,9 @@ class ModuleConcatenationPlugin {
if ( if (
!module.buildMeta || !module.buildMeta ||
module.buildMeta.exportsType !== "namespace" || module.buildMeta.exportsType !== "namespace" ||
!( module.presentationalDependencies === undefined ||
module instanceof NormalModule && !module.presentationalDependencies.some(
HarmonyExports.isEnabled(module) d => d instanceof HarmonyCompatibilityDependency
) )
) { ) {
setBailoutReason(module, "Module is not an ECMAScript module"); 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); expect(a).toBe(1);
NEXT(require("../../update")((err) => { NEXT(require("../../update")((err) => {
try { try {
expect(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/.test(err.message)).toBe(true); expect(err.message).toMatch(/Aborted because of declined dependency: \.\/b\.js in \.\/a\.js/);
expect(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/.test(err.message)).toBe(true); expect(err.message).toMatch(/Update propagation: \.\/c\.js -> \.\/b\.js -> \.\/a\.js/);
done(); done();
} catch(e) { } catch(e) {
done(e); done(e);

View File

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

View File

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