refactor hop runtime helper

This commit is contained in:
Sergey Melyukov 2019-12-03 16:27:39 +03:00
parent ba306b6f2c
commit faf784b6ab
14 changed files with 429 additions and 386 deletions

View File

@ -204,4 +204,4 @@ exports.system = "__webpack_require__.System";
* the shorthand for Object.prototype.hasOwnProperty
* using of ot decreases the compiled bundle size
*/
exports.hasOwnProperty = "__webpack_require__.hop";
exports.hasOwnProperty = "__webpack_require__.o";

View File

@ -16,6 +16,7 @@ const EnsureChunkRuntimeModule = require("./runtime/EnsureChunkRuntimeModule");
const GetChunkFilenameRuntimeModule = require("./runtime/GetChunkFilenameRuntimeModule");
const GetMainFilenameRuntimeModule = require("./runtime/GetMainFilenameRuntimeModule");
const GlobalRuntimeModule = require("./runtime/GlobalRuntimeModule");
const HasOwnPropertyRuntimeModule = require("./runtime/HasOwnPropertyRuntimeModule");
const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
@ -45,6 +46,7 @@ const GLOBALS_ON_REQUIRE = [
];
const TREE_DEPENDENCIES = {
[RuntimeGlobals.definePropertyGetters]: [RuntimeGlobals.hasOwnProperty],
[RuntimeGlobals.compatGetDefaultExport]: [
RuntimeGlobals.definePropertyGetters
],
@ -113,6 +115,15 @@ class RuntimePlugin {
);
return true;
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hasOwnProperty)
.tap("RuntimePlugin", chunk => {
compilation.addRuntimeModule(
chunk,
new HasOwnPropertyRuntimeModule()
);
return true;
});
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.compatGetDefaultExport)
.tap("RuntimePlugin", chunk => {

View File

@ -65,6 +65,10 @@ class RuntimeTemplate {
: `function(${args}) {\n${Template.indent(body)}\n}`;
}
iife(args, body) {
return `(${this.basicFunction(args, body)})()`;
}
forEach(variable, array, body) {
return this.supportsForOf()
? `for(const ${variable} of ${array}) {\n${Template.indent(body)}\n}`
@ -184,9 +188,12 @@ class RuntimeTemplate {
case "statements":
return errorStatements;
case "promise":
return `Promise.resolve().then(function() { ${errorStatements} })`;
return `Promise.resolve().then(${this.basicFunction(
"",
errorStatements
)})`;
case "expression":
return `(function() { ${errorStatements} }())`;
return this.iife("", errorStatements);
}
}
@ -430,7 +437,10 @@ class RuntimeTemplate {
weak,
runtimeRequirements
});
getModuleFunction = `function() { ${header}return ${rawModule}; }`;
getModuleFunction = this.basicFunction(
"",
`${header}return ${rawModule}`
);
} else {
runtimeRequirements.add(RuntimeGlobals.require);
getModuleFunction = `__webpack_require__.bind(null, ${comment}${idExpr})`;
@ -438,21 +448,30 @@ class RuntimeTemplate {
} else if (strict) {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
if (header) {
getModuleFunction = `function() { ${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 1); }`;
getModuleFunction = this.basicFunction(
"",
`${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 1)`
);
} else {
getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 1)`;
}
} else if (exportsType === "default") {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
if (header) {
getModuleFunction = `function() { ${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 3); }`;
getModuleFunction = this.basicFunction(
"",
`${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 3)`
);
} else {
getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 3)`;
}
} else {
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
if (header) {
getModuleFunction = `function() { ${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 7); }`;
getModuleFunction = this.basicFunction(
"",
`${header}return ${RuntimeGlobals.createFakeNamespaceObject}(${moduleIdExpr}, 7)`
);
} else {
getModuleFunction = `${RuntimeGlobals.createFakeNamespaceObject}.bind(__webpack_require__, ${comment}${idExpr}, 7)`;
}

View File

@ -578,7 +578,10 @@ class JavascriptModulesPlugin {
const innerStrict = !allStrict && m.buildInfo.strict;
const iife = innerStrict || inlinedModules.size > 1 || chunkModules;
if (iife) {
if (runtimeTemplate.supportsArrowFunction()) {
if (
!runtimeRequirements.has(RuntimeGlobals.thisAsExports) &&
runtimeTemplate.supportsArrowFunction()
) {
source.add("(() => {\n");
if (innerStrict) source.add('"use strict";\n');
source.add(renderedModule);
@ -717,24 +720,6 @@ class JavascriptModulesPlugin {
buf.push("");
}
if (runtimeRequirements.has(RuntimeGlobals.hasOwnProperty)) {
buf.push("// the shorthand for Object.prototype.hasOwnProperty");
if (runtimeTemplate.supportsArrowFunction()) {
buf.push(
`${RuntimeGlobals.hasOwnProperty} = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);`
);
} else {
buf.push(`${RuntimeGlobals.hasOwnProperty} = function (obj, prop) {`);
buf.push(
Template.indent(
"return Object.prototype.hasOwnProperty.call(obj, prop);"
)
);
buf.push("};");
}
buf.push("");
}
if (
moduleFactories ||
runtimeRequirements.has(RuntimeGlobals.moduleFactoriesAddOnly)

View File

@ -21,11 +21,10 @@ class DefinePropertyGettersRuntimeModule extends HelperRuntimeModule {
const fn = RuntimeGlobals.definePropertyGetters;
return Template.asString([
"// define getter functions for harmony exports",
"var hasOwnProperty = Object.prototype.hasOwnProperty;",
`${fn} = ${runtimeTemplate.basicFunction("exports, definition", [
`for(var key in definition) {`,
Template.indent([
"if(hasOwnProperty.call(definition, key) && !hasOwnProperty.call(exports, key)) {",
`if(${RuntimeGlobals.hasOwnProperty}(definition, key) && !${RuntimeGlobals.hasOwnProperty}(exports, key)) {`,
Template.indent([
"Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });"
]),

View File

@ -17,9 +17,9 @@ class GlobalRuntimeModule extends RuntimeModule {
* @returns {string} runtime code
*/
generate() {
const { runtimeTemplate } = this.compilation;
return Template.asString([
`${RuntimeGlobals.global} = (function() {`,
Template.indent([
`${RuntimeGlobals.global} = ${runtimeTemplate.iife("", [
"if (typeof globalThis === 'object') return globalThis;",
"try {",
Template.indent(
@ -38,8 +38,7 @@ class GlobalRuntimeModule extends RuntimeModule {
// We return `undefined`, instead of nothing here, so it's
// easier to handle this case:
// if (!global) { … }
]),
"})();"
])};`
]);
}
}

View File

@ -0,0 +1,32 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Sergey Melyukov @smelukov
*/
"use strict";
const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
class HasOwnPropertyRuntimeModule extends RuntimeModule {
constructor() {
super("hasOwnProperty shorthand");
}
/**
* @returns {string} runtime code
*/
generate() {
const { runtimeTemplate } = this.compilation;
return Template.asString([
`${RuntimeGlobals.hasOwnProperty} = ${runtimeTemplate.returningFunction(
"Object.prototype.hasOwnProperty.call(obj, prop)",
"obj, prop"
)}`
]);
}
}
module.exports = HasOwnPropertyRuntimeModule;

View File

@ -18,7 +18,6 @@ class JsonpChunkLoadingRuntimeModule extends RuntimeModule {
this.jsonpScript = jsonpScript;
this.linkPreload = linkPreload;
this.linkPrefetch = linkPrefetch;
this.runtimeRequirements.add(RuntimeGlobals.hasOwnProperty);
}
/**

View File

@ -179,41 +179,33 @@ class JsonpTemplatePlugin {
: "",
"// create error before stack unwound to get useful stacktrace later",
"var error = new Error();",
runtimeTemplate.supportsArrowFunction()
? "onScriptComplete = event => {"
: "onScriptComplete = function (event) {",
Template.indent([
runtimeTemplate.supportsArrowFunction()
? "onScriptComplete = _ => _;"
: "onScriptComplete = function() {};",
"// avoid mem leaks in IE.",
"script.onerror = script.onload = null;",
"clearTimeout(timeout);",
"var reportError = loadingEnded();",
"if(reportError) {",
Template.indent([
"var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
"var realSrc = event && event.target && event.target.src;",
"error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';",
"error.name = 'ChunkLoadError';",
"error.type = errorType;",
"error.request = realSrc;",
"reportError(error);"
]),
"}"
]),
"};",
...(runtimeTemplate.supportsArrowFunction()
? [
`var timeout = setTimeout(_ => onScriptComplete({ type: 'timeout', target: script }), ${chunkLoadTimeout});`
]
: [
"var timeout = setTimeout(function(){",
"onScriptComplete = " +
runtimeTemplate.basicFunction(
"event",
Template.asString([
`onScriptComplete = ${runtimeTemplate.basicFunction("", "")}`,
"// avoid mem leaks in IE.",
"script.onerror = script.onload = null;",
"clearTimeout(timeout);",
"var reportError = loadingEnded();",
"if(reportError) {",
Template.indent([
"onScriptComplete({ type: 'timeout', target: script });"
"var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
"var realSrc = event && event.target && event.target.src;",
"error.message = 'Loading chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realSrc + ')';",
"error.name = 'ChunkLoadError';",
"error.type = errorType;",
"error.request = realSrc;",
"reportError(error);"
]),
`}, ${chunkLoadTimeout});`
]),
"}"
])
),
";",
`var timeout = setTimeout(${runtimeTemplate.basicFunction(
"",
"onScriptComplete({ type: 'timeout', target: script })"
)}, ${chunkLoadTimeout});`,
"script.onerror = script.onload = onScriptComplete;"
]);
});
@ -272,6 +264,7 @@ class JsonpTemplatePlugin {
if (onceForChunkSet.has(chunk)) return;
onceForChunkSet.add(chunk);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
set.add(RuntimeGlobals.hasOwnProperty);
compilation.addRuntimeModule(
chunk,
new JsonpChunkLoadingRuntimeModule(

View File

@ -12,7 +12,6 @@ class ImportScriptsChunkLoadingRuntimeModule extends RuntimeModule {
constructor(runtimeRequirements) {
super("importScripts chunk loading", 10);
this.runtimeRequirements = runtimeRequirements;
this.runtimeRequirements.add(RuntimeGlobals.hasOwnProperty);
}
/**

View File

@ -82,6 +82,7 @@ class WebWorkerTemplatePlugin {
if (onceForChunkSet.has(chunk)) return;
onceForChunkSet.add(chunk);
set.add(RuntimeGlobals.moduleFactoriesAddOnly);
set.add(RuntimeGlobals.hasOwnProperty);
compilation.addRuntimeModule(
chunk,
new ImportScriptsChunkLoadingRuntimeModule(set)

View File

@ -217,10 +217,10 @@ describe("Stats", () => {
"comparedForEmit": false,
"emitted": true,
"info": Object {
"size": 1940,
"size": 1881,
},
"name": "entryB.js",
"size": 1940,
"size": 1881,
},
],
"assetsByChunkName": Object {

File diff suppressed because it is too large Load Diff

View File

@ -9,5 +9,5 @@ it("should watch for changes", function() {
expect(require("./foo/" + WATCH_STEP)).toBe('This should be working.' + WATCH_STEP);
}
expect(STATS_JSON.modules.length).toBe(6 + Number(WATCH_STEP));
expect(STATS_JSON.modules.length).toBe(7 + Number(WATCH_STEP));
});