run prettier on existing code

This commit is contained in:
Bazyli Brzóska 2018-02-25 11:46:17 +01:00
parent d8e40aa6fc
commit 36e8e30875
289 changed files with 12515 additions and 8749 deletions

View File

@ -4,15 +4,17 @@ let webpackCliInstalled = false;
try {
require.resolve("webpack-cli");
webpackCliInstalled = true;
} catch(e) {
} catch (e) {
webpackCliInstalled = false;
}
if(webpackCliInstalled) {
if (webpackCliInstalled) {
require("webpack-cli"); // eslint-disable-line node/no-missing-require, node/no-extraneous-require, node/no-unpublished-require
} else {
console.error("The CLI moved into a separate package: webpack-cli.");
console.error("Please install 'webpack-cli' in addition to webpack itself to use the CLI.");
console.error(
"Please install 'webpack-cli' in addition to webpack itself to use the CLI."
);
console.error("-> When using npm: npm install webpack-cli -D");
console.error("-> When using yarn: yarn add webpack-cli -D");
process.exitCode = 1;

View File

@ -7,11 +7,10 @@ g = (function() {
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1,eval)("this");
} catch(e) {
g = g || Function("return this")() || (1, eval)("this");
} catch (e) {
// This works if the window reference is available
if(typeof window === "object")
g = window;
if (typeof window === "object") g = window;
}
// g can still be undefined, but nothing to do about it...

View File

@ -1,8 +1,8 @@
module.exports = function(originalModule) {
if(!originalModule.webpackPolyfill) {
if (!originalModule.webpackPolyfill) {
var module = Object.create(originalModule);
// module.parent = undefined by default
if(!module.children) module.children = [];
if (!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {
@ -16,7 +16,7 @@ module.exports = function(originalModule) {
}
});
Object.defineProperty(module, "exports", {
enumerable: true,
enumerable: true
});
module.webpackPolyfill = 1;
}

View File

@ -1,9 +1,9 @@
module.exports = function(module) {
if(!module.webpackPolyfill) {
if (!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
if(!module.children) module.children = [];
if (!module.children) module.children = [];
Object.defineProperty(module, "loaded", {
enumerable: true,
get: function() {

View File

@ -1,10 +1,12 @@
module.exports = {
// mode: "development || "production",
module: {
rules: [{
test: /\.coffee$/,
loader: "coffee-loader"
}]
rules: [
{
test: /\.coffee$/,
loader: "coffee-loader"
}
]
},
resolve: {
extensions: [".web.coffee", ".web.js", ".coffee", ".js"]

View File

@ -8,12 +8,12 @@ module.exports = {
output: {
filename: "vendor.js", // best use [hash] here too
path: path.resolve(__dirname, "dist"),
library: "vendor_lib_[hash]",
library: "vendor_lib_[hash]"
},
plugins: [
new webpack.DllPlugin({
name: "vendor_lib_[hash]",
path: path.resolve(__dirname, "dist/vendor-manifest.json"),
}),
],
path: path.resolve(__dirname, "dist/vendor-manifest.json")
})
]
};

View File

@ -7,12 +7,12 @@ module.exports = {
entry: "./example-app",
output: {
filename: "app.js",
path: path.resolve(__dirname, "dist"),
path: path.resolve(__dirname, "dist")
},
plugins: [
new webpack.DllReferencePlugin({
context: ".",
manifest: require("../0-vendor/dist/vendor-manifest.json"), // eslint-disable-line
}),
],
manifest: require("../0-vendor/dist/vendor-manifest.json") // eslint-disable-line
})
]
};

View File

@ -1,7 +1,6 @@
var path = require("path");
var webpack = require("../../");
module.exports = [
{
name: "vendor",
// mode: "development || "production",
@ -38,5 +37,4 @@ module.exports = [
})
]
}
];

View File

@ -6,7 +6,7 @@ module.exports = {
externals: [
"add",
{
"subtract": {
subtract: {
root: "subtract",
commonjs2: "./subtract",
commonjs: ["./math", "subtract"],

View File

@ -5,7 +5,7 @@ module.exports = {
// The entry points for the pages
// They also contains router
pageA: ["./aEntry", "./router"],
pageB: ["./bEntry", "./router"],
pageB: ["./bEntry", "./router"]
},
output: {
path: path.join(__dirname, "dist"),

View File

@ -1,8 +1,8 @@
var path = require("path");
var I18nPlugin = require("i18n-webpack-plugin");
var languages = {
"en": null,
"de": require("./de.json")
en: null,
de: require("./de.json")
};
module.exports = Object.keys(languages).map(function(language) {
return {
@ -13,10 +13,6 @@ module.exports = Object.keys(languages).map(function(language) {
path: path.join(__dirname, "dist"),
filename: language + ".output.js"
},
plugins: [
new I18nPlugin(
languages[language]
)
]
plugins: [new I18nPlugin(languages[language])]
};
});

View File

@ -1,9 +1,11 @@
module.exports = {
// mode: "development || "production",
module: {
rules: [{
test: /\.css$/,
loader: "css-loader"
}]
rules: [
{
test: /\.css$/,
loader: "css-loader"
}
]
}
};

View File

@ -1,7 +1,6 @@
var path = require("path");
var webpack = require("../../");
module.exports = [
{
name: "mobile",
// mode: "development || "production",
@ -31,5 +30,4 @@ module.exports = [
})
]
}
];

View File

@ -10,15 +10,15 @@ module.exports = [
"hidden-source-map",
"inline-source-map",
"nosources-source-map",
"source-map",
"source-map"
].map(devtool => ({
mode: "development",
entry: {
bundle: "coffee-loader!./example.coffee",
bundle: "coffee-loader!./example.coffee"
},
output: {
path: path.join(__dirname, "dist"),
filename: `./[name]-${devtool}.js`,
filename: `./[name]-${devtool}.js`
},
devtool,
optimization: {

View File

@ -5,10 +5,12 @@ module.exports = {
publicPath: "js/"
},
module: {
rules: [{
test: /\.wasm$/,
type: "webassembly/experimental"
}]
rules: [
{
test: /\.wasm$/,
type: "webassembly/experimental"
}
]
},
optimization: {
occurrenceOrder: true // To keep filename consistent between different modes (for example building only)

View File

@ -5,5 +5,4 @@
"rules": {
"node/exports-style": ["off"]
}
}

View File

@ -3,46 +3,54 @@
Author Tobias Koppers @sokra
*/
/*globals window __webpack_hash__ */
if(module.hot) {
if (module.hot) {
var lastHash;
var upToDate = function upToDate() {
return lastHash.indexOf(__webpack_hash__) >= 0;
};
var log = require("./log");
var check = function check() {
module.hot.check(true).then(function(updatedModules) {
if(!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)");
window.location.reload();
return;
}
module.hot
.check(true)
.then(function(updatedModules) {
if (!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log(
"warning",
"[HMR] (Probably because of restarting the webpack-dev-server)"
);
window.location.reload();
return;
}
if(!upToDate()) {
check();
}
if (!upToDate()) {
check();
}
require("./log-apply-result")(updatedModules, updatedModules);
require("./log-apply-result")(updatedModules, updatedModules);
if(upToDate()) {
log("info", "[HMR] App is up to date.");
}
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update. Need to do a full reload!");
log("warning", "[HMR] " + err.stack || err.message);
window.location.reload();
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
if (upToDate()) {
log("info", "[HMR] App is up to date.");
}
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log(
"warning",
"[HMR] Cannot apply update. Need to do a full reload!"
);
log("warning", "[HMR] " + err.stack || err.message);
window.location.reload();
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
};
var hotEmitter = require("./emitter");
hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash;
if(!upToDate() && module.hot.status() === "idle") {
if (!upToDate() && module.hot.status() === "idle") {
log("info", "[HMR] Checking for updates on the server...");
check();
}

View File

@ -8,19 +8,22 @@ module.exports = function(updatedModules, renewedModules) {
});
var log = require("./log");
if(unacceptedModules.length > 0) {
log("warning", "[HMR] The following modules couldn't be hot updated: (They would need a full reload!)");
if (unacceptedModules.length > 0) {
log(
"warning",
"[HMR] The following modules couldn't be hot updated: (They would need a full reload!)"
);
unacceptedModules.forEach(function(moduleId) {
log("warning", "[HMR] - " + moduleId);
});
}
if(!renewedModules || renewedModules.length === 0) {
if (!renewedModules || renewedModules.length === 0) {
log("info", "[HMR] Nothing hot updated.");
} else {
log("info", "[HMR] Updated modules:");
renewedModules.forEach(function(moduleId) {
if(typeof moduleId === "string" && moduleId.indexOf("!") !== -1) {
if (typeof moduleId === "string" && moduleId.indexOf("!") !== -1) {
var parts = moduleId.split("!");
log.groupCollapsed("info", "[HMR] - " + parts.pop());
log("info", "[HMR] - " + moduleId);
@ -32,7 +35,10 @@ module.exports = function(updatedModules, renewedModules) {
var numberIds = renewedModules.every(function(moduleId) {
return typeof moduleId === "number";
});
if(numberIds)
log("info", "[HMR] Consider using the NamedModulesPlugin for module names.");
if (numberIds)
log(
"info",
"[HMR] Consider using the NamedModulesPlugin for module names."
);
}
};

View File

@ -3,7 +3,8 @@ var logLevel = "info";
function dummy() {}
function shouldLog(level) {
var shouldLog = (logLevel === "info" && level === "info") ||
var shouldLog =
(logLevel === "info" && level === "info") ||
(["info", "warning"].indexOf(logLevel) >= 0 && level === "warning") ||
(["info", "warning", "error"].indexOf(logLevel) >= 0 && level === "error");
return shouldLog;
@ -11,19 +12,19 @@ function shouldLog(level) {
function logGroup(logFn) {
return function(level, msg) {
if(shouldLog(level)) {
if (shouldLog(level)) {
logFn(msg);
}
};
}
module.exports = function(level, msg) {
if(shouldLog(level)) {
if(level === "info") {
if (shouldLog(level)) {
if (level === "info") {
console.log(msg);
} else if(level === "warning") {
} else if (level === "warning") {
console.warn(msg);
} else if(level === "error") {
} else if (level === "error") {
console.error(msg);
}
}

View File

@ -3,65 +3,99 @@
Author Tobias Koppers @sokra
*/
/*globals __webpack_hash__ */
if(module.hot) {
if (module.hot) {
var lastHash;
var upToDate = function upToDate() {
return lastHash.indexOf(__webpack_hash__) >= 0;
};
var log = require("./log");
var check = function check() {
module.hot.check().then(function(updatedModules) {
if(!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log("warning", "[HMR] (Probably because of restarting the webpack-dev-server)");
return;
}
return module.hot.apply({
ignoreUnaccepted: true,
ignoreDeclined: true,
ignoreErrored: true,
onUnaccepted: function(data) {
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> "));
},
onDeclined: function(data) {
log("warning", "Ignored an update to declined module " + data.chain.join(" -> "));
},
onErrored: function(data) {
log("error", data.error);
log("warning", "Ignored an error while updating module " + data.moduleId + " (" + data.type + ")");
}
}).then(function(renewedModules) {
if(!upToDate()) {
check();
module.hot
.check()
.then(function(updatedModules) {
if (!updatedModules) {
log("warning", "[HMR] Cannot find update. Need to do a full reload!");
log(
"warning",
"[HMR] (Probably because of restarting the webpack-dev-server)"
);
return;
}
require("./log-apply-result")(updatedModules, renewedModules);
return module.hot
.apply({
ignoreUnaccepted: true,
ignoreDeclined: true,
ignoreErrored: true,
onUnaccepted: function(data) {
log(
"warning",
"Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
},
onDeclined: function(data) {
log(
"warning",
"Ignored an update to declined module " +
data.chain.join(" -> ")
);
},
onErrored: function(data) {
log("error", data.error);
log(
"warning",
"Ignored an error while updating module " +
data.moduleId +
" (" +
data.type +
")"
);
}
})
.then(function(renewedModules) {
if (!upToDate()) {
check();
}
if(upToDate()) {
log("info", "[HMR] App is up to date.");
require("./log-apply-result")(updatedModules, renewedModules);
if (upToDate()) {
log("info", "[HMR] App is up to date.");
}
});
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log(
"warning",
"[HMR] Cannot check for update. Need to do a full reload!"
);
log("warning", "[HMR] " + err.stack || err.message);
} else {
log(
"warning",
"[HMR] Update check failed: " + err.stack || err.message
);
}
});
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot check for update. Need to do a full reload!");
log("warning", "[HMR] " + err.stack || err.message);
} else {
log("warning", "[HMR] Update check failed: " + err.stack || err.message);
}
});
};
var hotEmitter = require("./emitter");
hotEmitter.on("webpackHotUpdate", function(currentHash) {
lastHash = currentHash;
if(!upToDate()) {
if (!upToDate()) {
var status = module.hot.status();
if(status === "idle") {
if (status === "idle") {
log("info", "[HMR] Checking for updates on the server...");
check();
} else if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update as a previous update " + status + "ed. Need to do a full reload!");
} else if (["abort", "fail"].indexOf(status) >= 0) {
log(
"warning",
"[HMR] Cannot apply update as a previous update " +
status +
"ed. Need to do a full reload!"
);
}
}
});

View File

@ -3,29 +3,32 @@
Author Tobias Koppers @sokra
*/
/*globals __resourceQuery */
if(module.hot) {
var hotPollInterval = +(__resourceQuery.substr(1)) || (10 * 60 * 1000);
if (module.hot) {
var hotPollInterval = +__resourceQuery.substr(1) || 10 * 60 * 1000;
var log = require("./log");
var checkForUpdate = function checkForUpdate(fromUpdate) {
if(module.hot.status() === "idle") {
module.hot.check(true).then(function(updatedModules) {
if(!updatedModules) {
if(fromUpdate) log("info", "[HMR] Update applied.");
return;
}
require("./log-apply-result")(updatedModules, updatedModules);
checkForUpdate(true);
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
if (module.hot.status() === "idle") {
module.hot
.check(true)
.then(function(updatedModules) {
if (!updatedModules) {
if (fromUpdate) log("info", "[HMR] Update applied.");
return;
}
require("./log-apply-result")(updatedModules, updatedModules);
checkForUpdate(true);
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
}
};
setInterval(checkForUpdate, hotPollInterval);

View File

@ -3,44 +3,54 @@
Author Tobias Koppers @sokra
*/
/*globals __resourceQuery */
if(module.hot) {
if (module.hot) {
var log = require("./log");
var checkForUpdate = function checkForUpdate(fromUpdate) {
module.hot.check().then(function(updatedModules) {
if(!updatedModules) {
if(fromUpdate)
log("info", "[HMR] Update applied.");
else
log("warning", "[HMR] Cannot find update.");
return;
}
module.hot
.check()
.then(function(updatedModules) {
if (!updatedModules) {
if (fromUpdate) log("info", "[HMR] Update applied.");
else log("warning", "[HMR] Cannot find update.");
return;
}
return module.hot.apply({
ignoreUnaccepted: true,
onUnaccepted: function(data) {
log("warning", "Ignored an update to unaccepted module " + data.chain.join(" -> "));
},
}).then(function(renewedModules) {
require("./log-apply-result")(updatedModules, renewedModules);
return module.hot
.apply({
ignoreUnaccepted: true,
onUnaccepted: function(data) {
log(
"warning",
"Ignored an update to unaccepted module " +
data.chain.join(" -> ")
);
}
})
.then(function(renewedModules) {
require("./log-apply-result")(updatedModules, renewedModules);
checkForUpdate(true);
return null;
checkForUpdate(true);
return null;
});
})
.catch(function(err) {
var status = module.hot.status();
if (["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
}).catch(function(err) {
var status = module.hot.status();
if(["abort", "fail"].indexOf(status) >= 0) {
log("warning", "[HMR] Cannot apply update.");
log("warning", "[HMR] " + err.stack || err.message);
log("warning", "[HMR] You need to restart the application!");
} else {
log("warning", "[HMR] Update failed: " + err.stack || err.message);
}
});
};
process.on(__resourceQuery.substr(1) || "SIGUSR2", function() {
if(module.hot.status() !== "idle") {
log("warning", "[HMR] Got signal but currently in " + module.hot.status() + " state.");
if (module.hot.status() !== "idle") {
log(
"warning",
"[HMR] Got signal but currently in " + module.hot.status() + " state."
);
log("warning", "[HMR] Need to be in idle state to start hot update.");
return;
}

View File

@ -33,23 +33,51 @@ const REPLACEMENT_TYPES = {
class APIPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("APIPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"APIPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = parser => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression.for(key).tap("APIPlugin", NO_WEBPACK_REQUIRE[key] ? ParserHelpers.toConstantDependency(parser, REPLACEMENTS[key]) : ParserHelpers.toConstantDependencyWithWebpackRequire(parser, REPLACEMENTS[key]));
parser.hooks.evaluateTypeof.for(key).tap("APIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key]));
});
};
const handler = parser => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression
.for(key)
.tap(
"APIPlugin",
NO_WEBPACK_REQUIRE[key]
? ParserHelpers.toConstantDependency(
parser,
REPLACEMENTS[key]
)
: ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
REPLACEMENTS[key]
)
);
parser.hooks.evaluateTypeof
.for(key)
.tap(
"APIPlugin",
ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])
);
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("APIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("APIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("APIPlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("APIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("APIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("APIPlugin", handler);
}
);
}
}

View File

@ -14,42 +14,56 @@ class AmdMainTemplatePlugin {
}
apply(compilation) {
const {
mainTemplate,
chunkTemplate
} = compilation;
const { mainTemplate, chunkTemplate } = compilation;
const onRenderWithEntry = (source, chunk, hash) => {
const externals = chunk.getModules().filter((m) => m.external);
const externalsDepsArray = JSON.stringify(externals.map((m) =>
typeof m.request === "object" ? m.request.amd : m.request
));
const externalsArguments = externals.map((m) =>
`__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
).join(", ");
const externals = chunk.getModules().filter(m => m.external);
const externalsDepsArray = JSON.stringify(
externals.map(
m => (typeof m.request === "object" ? m.request.amd : m.request)
)
);
const externalsArguments = externals
.map(
m => `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${m.id}`)}__`
)
.join(", ");
if(this.name) {
if (this.name) {
const name = mainTemplate.getAssetPath(this.name, {
hash,
chunk
});
return new ConcatSource(
`define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});"
`define(${JSON.stringify(name)}, ${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
);
} else if (externalsArguments) {
return new ConcatSource(
`define(${externalsDepsArray}, function(${
externalsArguments
}) { return `,
source,
"});"
);
} else if(externalsArguments) {
return new ConcatSource(`define(${externalsDepsArray}, function(${externalsArguments}) { return `, source, "});");
} else {
return new ConcatSource("define(function() { return ", source, "});");
}
};
for(const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap("AmdMainTemplatePlugin", onRenderWithEntry);
for (const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap(
"AmdMainTemplatePlugin",
onRenderWithEntry
);
}
mainTemplate.hooks.globalHashPaths.tap("AmdMainTemplatePlugin", paths => {
if(this.name) paths.push(this.name);
if (this.name) paths.push(this.name);
return paths;
});

View File

@ -25,9 +25,15 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
updateHash(hash) {
hash.update(this.chunkName || "");
hash.update(this.chunkGroup && this.chunkGroup.chunks.map(chunk => {
return chunk.id !== null ? chunk.id : "";
}).join(",") || "");
hash.update(
(this.chunkGroup &&
this.chunkGroup.chunks
.map(chunk => {
return chunk.id !== null ? chunk.id : "";
})
.join(",")) ||
""
);
super.updateHash(hash);
}

View File

@ -11,7 +11,9 @@ module.exports = class AsyncDependencyToInitialChunkError extends WebpackError {
super();
this.name = "AsyncDependencyToInitialChunkError";
this.message = `It's not allowed to load an initial chunk on demand. The chunk name "${chunkName}" is already used by an entrypoint.`;
this.message = `It's not allowed to load an initial chunk on demand. The chunk name "${
chunkName
}" is already used by an entrypoint.`;
this.module = module;
this.origin = module;
this.originLoc = loc;

View File

@ -10,13 +10,17 @@ const NormalModule = require("./NormalModule");
class AutomaticPrefetchPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("AutomaticPrefetchPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(PrefetchDependency, normalModuleFactory);
});
compiler.hooks.compilation.tap(
"AutomaticPrefetchPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
PrefetchDependency,
normalModuleFactory
);
}
);
let lastModules = null;
compiler.hooks.afterCompile.tap("AutomaticPrefetchPlugin", (compilation) => {
compiler.hooks.afterCompile.tap("AutomaticPrefetchPlugin", compilation => {
lastModules = compilation.modules
.filter(m => m instanceof NormalModule)
.map(m => ({
@ -24,12 +28,23 @@ class AutomaticPrefetchPlugin {
request: m.request
}));
});
compiler.hooks.make.tapAsync("AutomaticPrefetchPlugin", (compilation, callback) => {
if(!lastModules) return callback();
asyncLib.forEach(lastModules, (m, callback) => {
compilation.prefetch(m.context || compiler.context, new PrefetchDependency(m.request), callback);
}, callback);
});
compiler.hooks.make.tapAsync(
"AutomaticPrefetchPlugin",
(compilation, callback) => {
if (!lastModules) return callback();
asyncLib.forEach(
lastModules,
(m, callback) => {
compilation.prefetch(
m.context || compiler.context,
new PrefetchDependency(m.request),
callback
);
},
callback
);
}
);
}
}
module.exports = AutomaticPrefetchPlugin;

View File

@ -12,40 +12,50 @@ const Template = require("./Template");
const validateOptions = require("schema-utils");
const schema = require("../schemas/plugins/BannerPlugin.json");
const wrapComment = (str) => {
if(!str.includes("\n")) return Template.toComment(str);
return `/*!\n * ${str.replace(/\*\//g, "* /").split("\n").join("\n * ")}\n */`;
const wrapComment = str => {
if (!str.includes("\n")) return Template.toComment(str);
return `/*!\n * ${str
.replace(/\*\//g, "* /")
.split("\n")
.join("\n * ")}\n */`;
};
class BannerPlugin {
constructor(options) {
if(arguments.length > 1)
throw new Error("BannerPlugin only takes one argument (pass an options object)");
if (arguments.length > 1)
throw new Error(
"BannerPlugin only takes one argument (pass an options object)"
);
validateOptions(schema, options, "Banner Plugin");
if(typeof options === "string")
if (typeof options === "string")
options = {
banner: options
};
this.options = options || {};
this.banner = this.options.raw ? options.banner : wrapComment(options.banner);
this.banner = this.options.raw
? options.banner
: wrapComment(options.banner);
}
apply(compiler) {
const options = this.options;
const banner = this.banner;
const matchObject = ModuleFilenameHelpers.matchObject.bind(undefined, options);
const matchObject = ModuleFilenameHelpers.matchObject.bind(
undefined,
options
);
compiler.hooks.compilation.tap("BannerPlugin", (compilation) => {
compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", (chunks) => {
for(const chunk of chunks) {
if(options.entryOnly && !chunk.canBeInitial()) {
compiler.hooks.compilation.tap("BannerPlugin", compilation => {
compilation.hooks.optimizeChunkAssets.tap("BannerPlugin", chunks => {
for (const chunk of chunks) {
if (options.entryOnly && !chunk.canBeInitial()) {
continue;
}
for(const file of chunk.files) {
if(!matchObject(file)) {
for (const file of chunk.files) {
if (!matchObject(file)) {
continue;
}
@ -55,14 +65,14 @@ class BannerPlugin {
const hash = compilation.hash;
const querySplit = filename.indexOf("?");
if(querySplit >= 0) {
if (querySplit >= 0) {
query = filename.substr(querySplit);
filename = filename.substr(0, querySplit);
}
const lastSlashIndex = filename.lastIndexOf("/");
if(lastSlashIndex === -1) {
if (lastSlashIndex === -1) {
basename = filename;
} else {
basename = filename.substr(lastSlashIndex + 1);
@ -73,10 +83,14 @@ class BannerPlugin {
chunk,
filename,
basename,
query,
query
});
compilation.assets[file] = new ConcatSource(comment, "\n", compilation.assets[file]);
compilation.assets[file] = new ConcatSource(
comment,
"\n",
compilation.assets[file]
);
}
}
});

View File

@ -19,7 +19,6 @@ const TypeWrapped = 10;
const TypeTemplateString = 11;
class BasicEvaluatedExpression {
constructor() {
this.type = TypeUnknown;
this.range = null;
@ -90,19 +89,23 @@ class BasicEvaluatedExpression {
}
asBool() {
if(this.truthy) return true;
else if(this.falsy) return false;
else if(this.isBoolean()) return this.bool;
else if(this.isNull()) return false;
else if(this.isString()) return this.string !== "";
else if(this.isNumber()) return this.number !== 0;
else if(this.isRegExp()) return true;
else if(this.isArray()) return true;
else if(this.isConstArray()) return true;
else if(this.isWrapped()) return this.prefix && this.prefix.asBool() || this.postfix && this.postfix.asBool() ? true : undefined;
else if(this.isTemplateString()) {
for(const quasi of this.quasis) {
if(quasi.asBool()) return true;
if (this.truthy) return true;
else if (this.falsy) return false;
else if (this.isBoolean()) return this.bool;
else if (this.isNull()) return false;
else if (this.isString()) return this.string !== "";
else if (this.isNumber()) return this.number !== 0;
else if (this.isRegExp()) return true;
else if (this.isArray()) return true;
else if (this.isConstArray()) return true;
else if (this.isWrapped())
return (this.prefix && this.prefix.asBool()) ||
(this.postfix && this.postfix.asBool())
? true
: undefined;
else if (this.isTemplateString()) {
for (const quasi of this.quasis) {
if (quasi.asBool()) return true;
}
// can't tell if string will be empty without executing
}
@ -158,12 +161,11 @@ class BasicEvaluatedExpression {
}
addOptions(options) {
if(!this.options) {
if (!this.options) {
this.type = TypeConditional;
this.options = [];
}
for(const item of options)
this.options.push(item);
for (const item of options) this.options.push(item);
return this;
}
@ -201,7 +203,6 @@ class BasicEvaluatedExpression {
this.range = range;
return this;
}
}
module.exports = BasicEvaluatedExpression;

View File

@ -13,26 +13,29 @@ class CachePlugin {
}
apply(compiler) {
if(Array.isArray(compiler.compilers)) {
if (Array.isArray(compiler.compilers)) {
compiler.compilers.forEach((c, idx) => {
new CachePlugin(this.cache[idx] = this.cache[idx] || {}).apply(c);
new CachePlugin((this.cache[idx] = this.cache[idx] || {})).apply(c);
});
} else {
const registerCacheToCompiler = (compiler, cache) => {
compiler.hooks.thisCompilation.tap("CachePlugin", compilation => {
compilation.cache = cache;
compilation.hooks.childCompiler.tap("CachePlugin", (childCompiler, compilerName, compilerIndex) => {
if(cache) {
let childCache;
if(!cache.children) cache.children = {};
if(!cache.children[compilerName]) cache.children[compilerName] = [];
if(cache.children[compilerName][compilerIndex])
childCache = cache.children[compilerName][compilerIndex];
else
cache.children[compilerName].push(childCache = {});
registerCacheToCompiler(childCompiler, childCache);
compilation.hooks.childCompiler.tap(
"CachePlugin",
(childCompiler, compilerName, compilerIndex) => {
if (cache) {
let childCache;
if (!cache.children) cache.children = {};
if (!cache.children[compilerName])
cache.children[compilerName] = [];
if (cache.children[compilerName][compilerIndex])
childCache = cache.children[compilerName][compilerIndex];
else cache.children[compilerName].push((childCache = {}));
registerCacheToCompiler(childCompiler, childCache);
}
}
});
);
});
};
registerCacheToCompiler(compiler, this.cache);
@ -40,49 +43,52 @@ class CachePlugin {
this.watching = true;
});
compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => {
if(!compiler._lastCompilationFileDependencies) return callback();
if (!compiler._lastCompilationFileDependencies) return callback();
const fs = compiler.inputFileSystem;
const fileTs = compiler.fileTimestamps = new Map();
asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => {
fs.stat(file, (err, stat) => {
if(err) {
if(err.code === "ENOENT") return callback();
return callback(err);
const fileTs = (compiler.fileTimestamps = new Map());
asyncLib.forEach(
compiler._lastCompilationFileDependencies,
(file, callback) => {
fs.stat(file, (err, stat) => {
if (err) {
if (err.code === "ENOENT") return callback();
return callback(err);
}
if (stat.mtime) this.applyMtime(+stat.mtime);
fileTs.set(file, +stat.mtime || Infinity);
callback();
});
},
err => {
if (err) return callback(err);
for (const [file, ts] of fileTs) {
fileTs.set(file, ts + this.FS_ACCURACY);
}
if(stat.mtime)
this.applyMtime(+stat.mtime);
fileTs.set(file, +stat.mtime || Infinity);
callback();
});
}, err => {
if(err) return callback(err);
for(const [file, ts] of fileTs) {
fileTs.set(file, ts + this.FS_ACCURACY);
}
callback();
});
);
});
compiler.hooks.afterCompile.tap("CachePlugin", compilation => {
compilation.compiler._lastCompilationFileDependencies = compilation.fileDependencies;
compilation.compiler._lastCompilationContextDependencies = compilation.contextDependencies;
compilation.compiler._lastCompilationFileDependencies =
compilation.fileDependencies;
compilation.compiler._lastCompilationContextDependencies =
compilation.contextDependencies;
});
}
}
/* istanbul ignore next */
applyMtime(mtime) {
if(this.FS_ACCURACY > 1 && mtime % 2 !== 0)
this.FS_ACCURACY = 1;
else if(this.FS_ACCURACY > 10 && mtime % 20 !== 0)
this.FS_ACCURACY = 10;
else if(this.FS_ACCURACY > 100 && mtime % 200 !== 0)
if (this.FS_ACCURACY > 1 && mtime % 2 !== 0) this.FS_ACCURACY = 1;
else if (this.FS_ACCURACY > 10 && mtime % 20 !== 0) this.FS_ACCURACY = 10;
else if (this.FS_ACCURACY > 100 && mtime % 200 !== 0)
this.FS_ACCURACY = 100;
else if(this.FS_ACCURACY > 1000 && mtime % 2000 !== 0)
else if (this.FS_ACCURACY > 1000 && mtime % 2000 !== 0)
this.FS_ACCURACY = 1000;
}
}

View File

@ -28,24 +28,26 @@ ${modulesList}`;
a = a.identifier();
b = b.identifier();
/* istanbul ignore next */
if(a < b) return -1;
if (a < b) return -1;
/* istanbul ignore next */
if(a > b) return 1;
if (a > b) return 1;
/* istanbul ignore next */
return 0;
});
}
_moduleMessages(modules) {
return modules.map((m) => {
let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter((reason) => reason.module);
return modules
.map(m => {
let message = `* ${m.identifier()}`;
const validReasons = m.reasons.filter(reason => reason.module);
if(validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].module.identifier()}`;
}
return message;
}).join("\n");
if (validReasons.length > 0) {
message += `\n Used by ${validReasons.length} module(s), i. e.`;
message += `\n ${validReasons[0].module.identifier()}`;
}
return message;
})
.join("\n");
}
};

View File

@ -9,24 +9,25 @@ const SortableSet = require("./util/SortableSet");
const GraphHelpers = require("./GraphHelpers");
let debugId = 1000;
const ERR_CHUNK_ENTRY = "Chunk.entry was removed. Use hasRuntime()";
const ERR_CHUNK_INITIAL = "Chunk.initial was removed. Use canBeInitial/isOnlyInitial()";
const ERR_CHUNK_INITIAL =
"Chunk.initial was removed. Use canBeInitial/isOnlyInitial()";
const sortById = (a, b) => {
if(a.id < b.id) return -1;
if(b.id < a.id) return 1;
if (a.id < b.id) return -1;
if (b.id < a.id) return 1;
return 0;
};
const sortByIdentifier = (a, b) => {
if(a.identifier() > b.identifier()) return 1;
if(a.identifier() < b.identifier()) return -1;
if (a.identifier() > b.identifier()) return 1;
if (a.identifier() < b.identifier()) return -1;
return 0;
};
const getModulesIdent = set => {
set.sort();
let str = "";
for(const m of set) {
for (const m of set) {
str += m.identifier() + "#";
}
return str;
@ -36,14 +37,13 @@ const getArray = set => Array.from(set);
const getModulesSize = set => {
let count = 0;
for(const module of set) {
for (const module of set) {
count += module.size();
}
return count;
};
class Chunk {
constructor(name) {
this.id = null;
this.ids = null;
@ -77,7 +77,7 @@ class Chunk {
}
hasRuntime() {
for(const chunkGroup of this._groups) {
for (const chunkGroup of this._groups) {
// We only need to check the first one
return chunkGroup.isInitial() && chunkGroup.getRuntimeChunk() === this;
}
@ -85,18 +85,16 @@ class Chunk {
}
canBeInitial() {
for(const chunkGroup of this._groups) {
if(chunkGroup.isInitial())
return true;
for (const chunkGroup of this._groups) {
if (chunkGroup.isInitial()) return true;
}
return false;
}
isOnlyInitial() {
if(this._groups.size <= 0) return false;
for(const chunkGroup of this._groups) {
if(!chunkGroup.isInitial())
return false;
if (this._groups.size <= 0) return false;
for (const chunkGroup of this._groups) {
if (!chunkGroup.isInitial()) return false;
}
return true;
}
@ -106,7 +104,7 @@ class Chunk {
}
addModule(module) {
if(!this._modules.has(module)) {
if (!this._modules.has(module)) {
this._modules.add(module);
return true;
}
@ -114,7 +112,7 @@ class Chunk {
}
removeModule(module) {
if(this._modules.delete(module)) {
if (this._modules.delete(module)) {
module.removeChunk(this);
return true;
}
@ -134,15 +132,13 @@ class Chunk {
}
addGroup(chunkGroup) {
if(this._groups.has(chunkGroup))
return false;
if (this._groups.has(chunkGroup)) return false;
this._groups.add(chunkGroup);
return true;
}
removeGroup(chunkGroup) {
if(!this._groups.has(chunkGroup))
return false;
if (!this._groups.has(chunkGroup)) return false;
this._groups.delete(chunkGroup);
return true;
}
@ -162,18 +158,19 @@ class Chunk {
compareTo(otherChunk) {
this._modules.sort();
otherChunk._modules.sort();
if(this._modules.size > otherChunk._modules.size) return -1;
if(this._modules.size < otherChunk._modules.size) return 1;
if (this._modules.size > otherChunk._modules.size) return -1;
if (this._modules.size < otherChunk._modules.size) return 1;
const a = this._modules[Symbol.iterator]();
const b = otherChunk._modules[Symbol.iterator]();
while(true) { // eslint-disable-line
while (true) {
// eslint-disable-line
const aItem = a.next();
const bItem = b.next();
if(aItem.done) return 0;
if (aItem.done) return 0;
const aModuleIdentifier = aItem.value.identifier();
const bModuleIdentifier = bItem.value.identifier();
if(aModuleIdentifier > bModuleIdentifier) return -1;
if(aModuleIdentifier < bModuleIdentifier) return 1;
if (aModuleIdentifier > bModuleIdentifier) return -1;
if (aModuleIdentifier < bModuleIdentifier) return 1;
}
}
@ -192,10 +189,10 @@ class Chunk {
remove(reason) {
// cleanup modules
// Array.from is used here to create a clone, because removeChunk modifies this._modules
for(const module of Array.from(this._modules)) {
for (const module of Array.from(this._modules)) {
module.removeChunk(this);
}
for(const chunkGroup of this._groups) {
for (const chunkGroup of this._groups) {
chunkGroup.removeChunk(this);
}
}
@ -207,25 +204,28 @@ class Chunk {
}
integrate(otherChunk, reason) {
if(!this.canBeIntegrated(otherChunk)) {
if (!this.canBeIntegrated(otherChunk)) {
return false;
}
// Array.from is used here to create a clone, because moveModule modifies otherChunk._modules
for(const module of Array.from(otherChunk._modules)) {
for (const module of Array.from(otherChunk._modules)) {
otherChunk.moveModule(module, this);
}
otherChunk._modules.clear();
for(const chunkGroup of otherChunk._groups) {
for (const chunkGroup of otherChunk._groups) {
chunkGroup.replaceChunk(otherChunk, this);
this.addGroup(chunkGroup);
}
otherChunk._groups.clear();
if(this.name && otherChunk.name) {
if(this.name.length !== otherChunk.name.length)
this.name = this.name.length < otherChunk.name.length ? this.name : otherChunk.name;
if (this.name && otherChunk.name) {
if (this.name.length !== otherChunk.name.length)
this.name =
this.name.length < otherChunk.name.length
? this.name
: otherChunk.name;
else
this.name = this.name < otherChunk.name ? this.name : otherChunk.name;
}
@ -234,7 +234,7 @@ class Chunk {
}
split(newChunk) {
for(const chunkGroup of this._groups) {
for (const chunkGroup of this._groups) {
chunkGroup.insertChunk(newChunk, this);
newChunk.addGroup(chunkGroup);
}
@ -248,7 +248,7 @@ class Chunk {
hash.update(`${this.id} `);
hash.update(this.ids ? this.ids.join(",") : "");
hash.update(`${this.name || ""} `);
for(const m of this._modules) {
for (const m of this._modules) {
hash.update(m.hash);
}
}
@ -256,31 +256,32 @@ class Chunk {
canBeIntegrated(otherChunk) {
const isAvailable = (a, b) => {
const queue = new Set(b.groupsIterable);
for(const chunkGroup of queue) {
if(a.isInGroup(chunkGroup)) continue;
if(chunkGroup.isInitial()) return false;
for(const parent of chunkGroup.parentsIterable)
queue.add(parent);
for (const chunkGroup of queue) {
if (a.isInGroup(chunkGroup)) continue;
if (chunkGroup.isInitial()) return false;
for (const parent of chunkGroup.parentsIterable) queue.add(parent);
}
return true;
};
if(this.hasRuntime() !== otherChunk.hasRuntime()) {
if(this.hasRuntime()) {
if (this.hasRuntime() !== otherChunk.hasRuntime()) {
if (this.hasRuntime()) {
return isAvailable(this, otherChunk);
} else if(otherChunk.hasRuntime()) {
} else if (otherChunk.hasRuntime()) {
return isAvailable(otherChunk, this);
} else {
return false;
}
}
if(this.hasEntryModule() || otherChunk.hasEntryModule())
return false;
if (this.hasEntryModule() || otherChunk.hasEntryModule()) return false;
return true;
}
addMultiplierAndOverhead(size, options) {
const overhead = typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
const multiplicator = this.canBeInitial() ? (options.entryChunkMultiplicator || 10) : 1;
const overhead =
typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
const multiplicator = this.canBeInitial()
? options.entryChunkMultiplicator || 10
: 1;
return size * multiplicator + overhead;
}
@ -295,14 +296,14 @@ class Chunk {
integratedSize(otherChunk, options) {
// Chunk if it's possible to integrate this chunk
if(!this.canBeIntegrated(otherChunk)) {
if (!this.canBeIntegrated(otherChunk)) {
return false;
}
let integratedModulesSize = this.modulesSize();
// only count modules that do not exist in this chunk!
for(const otherModule of otherChunk._modules) {
if(!this._modules.has(otherModule)) {
for (const otherModule of otherChunk._modules) {
if (!this._modules.has(otherModule)) {
integratedModulesSize += otherModule.size();
}
}
@ -323,18 +324,15 @@ class Chunk {
const queue = new Set(this.groupsIterable);
const chunks = new Set();
for(const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks)
initialChunks.add(chunk);
for (const chunkGroup of queue) {
for (const chunk of chunkGroup.chunks) initialChunks.add(chunk);
}
for(const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks) {
if(!initialChunks.has(chunk))
chunks.add(chunk);
for (const chunkGroup of queue) {
for (const chunk of chunkGroup.chunks) {
if (!initialChunks.has(chunk)) chunks.add(chunk);
}
for(const child of chunkGroup.childrenIterable)
queue.add(child);
for (const child of chunkGroup.childrenIterable) queue.add(child);
}
return chunks;
@ -344,10 +342,9 @@ class Chunk {
const chunkHashMap = Object.create(null);
const chunkNameMap = Object.create(null);
for(const chunk of this.getAllAsyncChunks()) {
for (const chunk of this.getAllAsyncChunks()) {
chunkHashMap[chunk.id] = realHash ? chunk.hash : chunk.renderedHash;
if(chunk.name)
chunkNameMap[chunk.id] = chunk.name;
if (chunk.name) chunkNameMap[chunk.id] = chunk.name;
}
return {
@ -360,11 +357,11 @@ class Chunk {
const chunkModuleIdMap = Object.create(null);
const chunkModuleHashMap = Object.create(null);
for(const chunk of this.getAllAsyncChunks()) {
for (const chunk of this.getAllAsyncChunks()) {
let array;
for(const module of chunk.modulesIterable) {
if(filterFn(module)) {
if(array === undefined) {
for (const module of chunk.modulesIterable) {
if (filterFn(module)) {
if (array === undefined) {
array = [];
chunkModuleIdMap[chunk.id] = array;
}
@ -372,7 +369,7 @@ class Chunk {
chunkModuleHashMap[module.id] = module.renderedHash;
}
}
if(array !== undefined) {
if (array !== undefined) {
array.sort();
}
}
@ -387,19 +384,17 @@ class Chunk {
const queue = new Set(this.groupsIterable);
const chunksProcessed = new Set();
for(const chunkGroup of queue) {
for(const chunk of chunkGroup.chunks) {
if(!chunksProcessed.has(chunk)) {
for (const chunkGroup of queue) {
for (const chunk of chunkGroup.chunks) {
if (!chunksProcessed.has(chunk)) {
chunksProcessed.add(chunk);
if(!filterChunkFn || filterChunkFn(chunk)) {
for(const module of chunk.modulesIterable)
if(filterFn(module))
return true;
if (!filterChunkFn || filterChunkFn(chunk)) {
for (const module of chunk.modulesIterable)
if (filterFn(module)) return true;
}
}
}
for(const child of chunkGroup.childrenIterable)
queue.add(child);
for (const child of chunkGroup.childrenIterable) queue.add(child);
}
return false;
}
@ -462,7 +457,9 @@ Object.defineProperty(Chunk.prototype, "blocks", {
Object.defineProperty(Chunk.prototype, "entrypoints", {
configurable: false,
get() {
throw new Error("Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead");
throw new Error(
"Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead"
);
},
set() {
throw new Error("Chunk.entrypoints: Use Chunks.addGroup instead");

View File

@ -12,16 +12,16 @@ let debugId = 5000;
const getArray = set => Array.from(set);
const sortById = (a, b) => {
if(a.id < b.id) return -1;
if(b.id < a.id) return 1;
if (a.id < b.id) return -1;
if (b.id < a.id) return 1;
return 0;
};
const sortOrigin = (a, b) => {
const aIdent = a.module ? a.module.identifier() : "";
const bIdent = b.module ? b.module.identifier() : "";
if(aIdent < bIdent) return -1;
if(aIdent > bIdent) return 1;
if (aIdent < bIdent) return -1;
if (aIdent > bIdent) return 1;
return compareLocations(a.loc, b.loc);
};
@ -47,10 +47,10 @@ class ChunkGroup {
unshiftChunk(chunk) {
const oldIdx = this.chunks.indexOf(chunk);
if(oldIdx > 0) {
if (oldIdx > 0) {
this.chunks.splice(oldIdx, 1);
this.chunks.unshift(chunk);
} else if(oldIdx < 0) {
} else if (oldIdx < 0) {
this.chunks.unshift(chunk);
return true;
}
@ -60,13 +60,13 @@ class ChunkGroup {
insertChunk(chunk, before) {
const oldIdx = this.chunks.indexOf(chunk);
const idx = this.chunks.indexOf(before);
if(idx < 0) {
if (idx < 0) {
throw new Error("before chunk not found");
}
if(oldIdx >= 0 && oldIdx > idx) {
if (oldIdx >= 0 && oldIdx > idx) {
this.chunks.splice(oldIdx, 1);
this.chunks.splice(idx, 0, chunk);
} else if(oldIdx < 0) {
} else if (oldIdx < 0) {
this.chunks.splice(idx, 0, chunk);
return true;
}
@ -75,7 +75,7 @@ class ChunkGroup {
pushChunk(chunk) {
const oldIdx = this.chunks.indexOf(chunk);
if(oldIdx >= 0) {
if (oldIdx >= 0) {
return false;
}
this.chunks.push(chunk);
@ -84,16 +84,16 @@ class ChunkGroup {
replaceChunk(oldChunk, newChunk) {
const oldIdx = this.chunks.indexOf(oldChunk);
if(oldIdx < 0) return false;
if (oldIdx < 0) return false;
const newIdx = this.chunks.indexOf(newChunk);
if(newIdx < 0) {
if (newIdx < 0) {
this.chunks[oldIdx] = newChunk;
return true;
}
if(newIdx < oldIdx) {
if (newIdx < oldIdx) {
this.chunks.splice(oldIdx, 1);
return true;
} else if(newIdx !== oldIdx) {
} else if (newIdx !== oldIdx) {
this.chunks[oldIdx] = newChunk;
this.chunks.splice(newIdx, 1);
return true;
@ -102,7 +102,7 @@ class ChunkGroup {
removeChunk(chunk) {
const idx = this.chunks.indexOf(chunk);
if(idx >= 0) {
if (idx >= 0) {
this.chunks.splice(idx, 1);
return true;
}
@ -114,7 +114,7 @@ class ChunkGroup {
}
addChild(chunk) {
if(this._children.has(chunk)) {
if (this._children.has(chunk)) {
return false;
}
this._children.add(chunk);
@ -134,7 +134,7 @@ class ChunkGroup {
}
removeChild(chunk) {
if(!this._children.has(chunk)) {
if (!this._children.has(chunk)) {
return false;
}
@ -144,7 +144,7 @@ class ChunkGroup {
}
addParent(parentChunk) {
if(!this._parents.has(parentChunk)) {
if (!this._parents.has(parentChunk)) {
this._parents.add(parentChunk);
return true;
}
@ -157,8 +157,7 @@ class ChunkGroup {
setParents(newParents) {
this._parents.clear();
for(const p of newParents)
this._parents.add(p);
for (const p of newParents) this._parents.add(p);
}
getNumberOfParents() {
@ -174,7 +173,7 @@ class ChunkGroup {
}
removeParent(chunk) {
if(this._parents.delete(chunk)) {
if (this._parents.delete(chunk)) {
chunk.removeChunk(this);
return true;
}
@ -201,7 +200,7 @@ class ChunkGroup {
}
addBlock(block) {
if(!this._blocks.has(block)) {
if (!this._blocks.has(block)) {
this._blocks.add(block);
return true;
}
@ -217,21 +216,20 @@ class ChunkGroup {
}
containsModule(module) {
for(const chunk of this.chunks) {
if(chunk.containsModule(module))
return true;
for (const chunk of this.chunks) {
if (chunk.containsModule(module)) return true;
}
return false;
}
remove(reason) {
// cleanup parents
for(const parentChunkGroup of this._parents) {
for (const parentChunkGroup of this._parents) {
// remove this chunk from its parents
parentChunkGroup._children.delete(this);
// cleanup "sub chunks"
for(const chunkGroup of this._children) {
for (const chunkGroup of this._children) {
/**
* remove this chunk as "intermediary" and connect
* it "sub chunks" and parents directly
@ -249,18 +247,18 @@ class ChunkGroup {
* This can not be done in the above loop
* as it is not garuanteed that `this._parents` contains anything.
*/
for(const chunkGroup of this._children) {
for (const chunkGroup of this._children) {
// remove this as parent of every "sub chunk"
chunkGroup._parents.delete(this);
}
// cleanup blocks
for(const block of this._blocks) {
for (const block of this._blocks) {
block.chunkGroup = null;
}
// remove chunks
for(const chunk of this.chunks) {
for (const chunk of this.chunks) {
chunk.removeGroup(this);
}
}
@ -273,13 +271,21 @@ class ChunkGroup {
checkConstraints() {
const chunk = this;
for(const child of chunk._children) {
if(!child._parents.has(chunk))
throw new Error(`checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`);
for (const child of chunk._children) {
if (!child._parents.has(chunk))
throw new Error(
`checkConstraints: child missing parent ${chunk.debugId} -> ${
child.debugId
}`
);
}
for(const parentChunk of chunk._parents) {
if(!parentChunk._children.has(chunk))
throw new Error(`checkConstraints: parent missing child ${parentChunk.debugId} <- ${chunk.debugId}`);
for (const parentChunk of chunk._parents) {
if (!parentChunk._children.has(chunk))
throw new Error(
`checkConstraints: parent missing child ${parentChunk.debugId} <- ${
chunk.debugId
}`
);
}
}
}

View File

@ -14,11 +14,21 @@ module.exports = class ChunkTemplate extends Tapable {
this.outputOptions = outputOptions || {};
this.hooks = {
renderManifest: new SyncWaterfallHook(["result", "options"]),
modules: new SyncWaterfallHook(["source", "chunk", "moduleTemplate", "dependencyTemplates"]),
render: new SyncWaterfallHook(["source", "chunk", "moduleTemplate", "dependencyTemplates"]),
modules: new SyncWaterfallHook([
"source",
"chunk",
"moduleTemplate",
"dependencyTemplates"
]),
render: new SyncWaterfallHook([
"source",
"chunk",
"moduleTemplate",
"dependencyTemplates"
]),
renderWithEntry: new SyncWaterfallHook(["source", "chunk"]),
hash: new SyncHook(["hash"]),
hashForChunk: new SyncHook(["hash", "chunk"]),
hashForChunk: new SyncHook(["hash", "chunk"])
};
}

View File

@ -9,37 +9,55 @@ const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory");
class CompatibilityPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("CompatibilityPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"CompatibilityPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
normalModuleFactory.hooks.parser.for("javascript/auto").tap("CompatibilityPlugin", (parser, parserOptions) => {
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("CompatibilityPlugin", (parser, parserOptions) => {
if (
typeof parserOptions.browserify !== "undefined" &&
!parserOptions.browserify
)
return;
if(typeof parserOptions.browserify !== "undefined" && !parserOptions.browserify)
return;
parser.hooks.call.for("require").tap("CompatibilityPlugin", (expr) => {
// support for browserify style require delegator: "require(o, !0)"
if(expr.arguments.length !== 2) return;
const second = parser.evaluateExpression(expr.arguments[1]);
if(!second.isBoolean()) return;
if(second.asBool() !== true) return;
const dep = new ConstDependency("require", expr.callee.range);
dep.loc = expr.loc;
if(parser.state.current.dependencies.length > 1) {
const last = parser.state.current.dependencies[parser.state.current.dependencies.length - 1];
if(last.critical && last.options && last.options.request === "." && last.userRequest === "." && last.options.recursive)
parser.state.current.dependencies.pop();
}
parser.state.current.addDependency(dep);
return true;
});
});
});
parser.hooks.call
.for("require")
.tap("CompatibilityPlugin", expr => {
// support for browserify style require delegator: "require(o, !0)"
if (expr.arguments.length !== 2) return;
const second = parser.evaluateExpression(expr.arguments[1]);
if (!second.isBoolean()) return;
if (second.asBool() !== true) return;
const dep = new ConstDependency("require", expr.callee.range);
dep.loc = expr.loc;
if (parser.state.current.dependencies.length > 1) {
const last =
parser.state.current.dependencies[
parser.state.current.dependencies.length - 1
];
if (
last.critical &&
last.options &&
last.options.request === "." &&
last.userRequest === "." &&
last.options.recursive
)
parser.state.current.dependencies.pop();
}
parser.state.current.addDependency(dep);
return true;
});
});
}
);
}
}
module.exports = CompatibilityPlugin;

File diff suppressed because it is too large Load Diff

View File

@ -53,10 +53,10 @@ class Compiler extends Tapable {
afterEnvironment: new SyncHook([]),
afterPlugins: new SyncHook(["compiler"]),
afterResolvers: new SyncHook(["compiler"]),
entryOption: new SyncBailHook(["context", "entry"]),
entryOption: new SyncBailHook(["context", "entry"])
};
this._pluginCompat.tap("Compiler", options => {
switch(options.name) {
switch (options.name) {
case "additional-pass":
case "before-run":
case "run":
@ -87,64 +87,40 @@ class Compiler extends Tapable {
// TODO remove in webpack 5
this.resolvers = {
normal: {
plugins: util.deprecate(
(hook, fn) => {
this.resolverFactory.plugin("resolver normal", resolver => {
resolver.plugin(hook, fn);
});
},
"webpack: Using compiler.resolvers.normal is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver normal\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver normal", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.normal is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver normal\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
plugins: util.deprecate((hook, fn) => {
this.resolverFactory.plugin("resolver normal", resolver => {
resolver.plugin(hook, fn);
});
}, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
apply: util.deprecate((...args) => {
this.resolverFactory.plugin("resolver normal", resolver => {
resolver.apply(...args);
});
}, "webpack: Using compiler.resolvers.normal is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver normal", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
},
loader: {
plugins: util.deprecate(
(hook, fn) => {
this.resolverFactory.plugin("resolver loader", resolver => {
resolver.plugin(hook, fn);
});
},
"webpack: Using compiler.resolvers.loader is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver loader\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver loader", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.loader is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver loader\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
plugins: util.deprecate((hook, fn) => {
this.resolverFactory.plugin("resolver loader", resolver => {
resolver.plugin(hook, fn);
});
}, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
apply: util.deprecate((...args) => {
this.resolverFactory.plugin("resolver loader", resolver => {
resolver.apply(...args);
});
}, "webpack: Using compiler.resolvers.loader is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver loader", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
},
context: {
plugins: util.deprecate(
(hook, fn) => {
this.resolverFactory.plugin("resolver context", resolver => {
resolver.plugin(hook, fn);
});
},
"webpack: Using compiler.resolvers.context is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.plugin(/* ... */);\n}); instead."
),
apply: util.deprecate(
(...args) => {
this.resolverFactory.plugin("resolver context", resolver => {
resolver.apply(...args);
});
},
"webpack: Using compiler.resolvers.context is deprecated.\n" +
"Use compiler.resolverFactory.plugin(\"resolver context\", resolver => {\n resolver.apply(/* ... */);\n}); instead."
)
plugins: util.deprecate((hook, fn) => {
this.resolverFactory.plugin("resolver context", resolver => {
resolver.plugin(hook, fn);
});
}, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.plugin(/* ... */);\n}); instead.'),
apply: util.deprecate((...args) => {
this.resolverFactory.plugin("resolver context", resolver => {
resolver.apply(...args);
});
}, "webpack: Using compiler.resolvers.context is deprecated.\n" + 'Use compiler.resolverFactory.plugin("resolver context", resolver => {\n resolver.apply(/* ... */);\n}); instead.')
}
};
@ -165,33 +141,33 @@ class Compiler extends Tapable {
const startTime = Date.now();
const onCompiled = (err, compilation) => {
if(err) return callback(err);
if (err) return callback(err);
if(this.hooks.shouldEmit.call(compilation) === false) {
if (this.hooks.shouldEmit.call(compilation) === false) {
const stats = new Stats(compilation);
stats.startTime = startTime;
stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => {
if(err) return callback(err);
if (err) return callback(err);
return callback(null, stats);
});
return;
}
this.emitAssets(compilation, err => {
if(err) return callback(err);
if (err) return callback(err);
if(compilation.hooks.needAdditionalPass.call()) {
if (compilation.hooks.needAdditionalPass.call()) {
compilation.needAdditionalPass = true;
const stats = new Stats(compilation);
stats.startTime = startTime;
stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => {
if(err) return callback(err);
if (err) return callback(err);
this.hooks.additionalPass.callAsync(err => {
if(err) return callback(err);
if (err) return callback(err);
this.compile(onCompiled);
});
});
@ -199,13 +175,13 @@ class Compiler extends Tapable {
}
this.emitRecords(err => {
if(err) return callback(err);
if (err) return callback(err);
const stats = new Stats(compilation);
stats.startTime = startTime;
stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => {
if(err) return callback(err);
if (err) return callback(err);
return callback(null, stats);
});
});
@ -213,13 +189,13 @@ class Compiler extends Tapable {
};
this.hooks.beforeRun.callAsync(this, err => {
if(err) return callback(err);
if (err) return callback(err);
this.hooks.run.callAsync(this, err => {
if(err) return callback(err);
if (err) return callback(err);
this.readRecords(err => {
if(err) return callback(err);
if (err) return callback(err);
this.compile(onCompiled);
});
@ -229,14 +205,17 @@ class Compiler extends Tapable {
runAsChild(callback) {
this.compile((err, compilation) => {
if(err) return callback(err);
if (err) return callback(err);
this.parentCompilation.children.push(compilation);
for(const name of Object.keys(compilation.assets)) {
for (const name of Object.keys(compilation.assets)) {
this.parentCompilation.assets[name] = compilation.assets[name];
}
const entries = Array.from(compilation.entrypoints.values(), ep => ep.chunks).reduce((array, chunks) => {
const entries = Array.from(
compilation.entrypoints.values(),
ep => ep.chunks
).reduce((array, chunks) => {
return array.concat(chunks);
}, []);
@ -245,101 +224,114 @@ class Compiler extends Tapable {
}
purgeInputFileSystem() {
if(this.inputFileSystem && this.inputFileSystem.purge)
if (this.inputFileSystem && this.inputFileSystem.purge)
this.inputFileSystem.purge();
}
emitAssets(compilation, callback) {
let outputPath;
const emitFiles = (err) => {
if(err) return callback(err);
const emitFiles = err => {
if (err) return callback(err);
asyncLib.forEach(compilation.assets, (source, file, callback) => {
asyncLib.forEach(
compilation.assets,
(source, file, callback) => {
let targetFile = file;
const queryStringIdx = targetFile.indexOf("?");
if (queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx);
}
let targetFile = file;
const queryStringIdx = targetFile.indexOf("?");
if(queryStringIdx >= 0) {
targetFile = targetFile.substr(0, queryStringIdx);
}
const writeOut = err => {
if (err) return callback(err);
const targetPath = this.outputFileSystem.join(
outputPath,
targetFile
);
if (source.existsAt === targetPath) {
source.emitted = false;
return callback();
}
let content = source.source();
if (!Buffer.isBuffer(content)) {
content = Buffer.from(content, "utf8");
}
source.existsAt = targetPath;
source.emitted = true;
this.outputFileSystem.writeFile(targetPath, content, callback);
};
if (targetFile.match(/\/|\\/)) {
const dir = path.dirname(targetFile);
this.outputFileSystem.mkdirp(
this.outputFileSystem.join(outputPath, dir),
writeOut
);
} else writeOut();
},
err => {
if (err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, err => {
if (err) return callback(err);
const writeOut = (err) => {
if(err) return callback(err);
const targetPath = this.outputFileSystem.join(outputPath, targetFile);
if(source.existsAt === targetPath) {
source.emitted = false;
return callback();
}
let content = source.source();
if(!Buffer.isBuffer(content)) {
content = Buffer.from(content, "utf8");
}
source.existsAt = targetPath;
source.emitted = true;
this.outputFileSystem.writeFile(targetPath, content, callback);
};
if(targetFile.match(/\/|\\/)) {
const dir = path.dirname(targetFile);
this.outputFileSystem.mkdirp(this.outputFileSystem.join(outputPath, dir), writeOut);
} else writeOut();
}, err => {
if(err) return callback(err);
this.hooks.afterEmit.callAsync(compilation, err => {
if(err) return callback(err);
return callback();
});
});
});
}
);
};
this.hooks.emit.callAsync(compilation, err => {
if(err) return callback(err);
if (err) return callback(err);
outputPath = compilation.getPath(this.outputPath);
this.outputFileSystem.mkdirp(outputPath, emitFiles);
});
}
emitRecords(callback) {
if(!this.recordsOutputPath) return callback();
if (!this.recordsOutputPath) return callback();
const idx1 = this.recordsOutputPath.lastIndexOf("/");
const idx2 = this.recordsOutputPath.lastIndexOf("\\");
let recordsOutputPathDirectory = null;
if(idx1 > idx2) recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1);
if(idx1 < idx2) recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2);
if (idx1 > idx2)
recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx1);
if (idx1 < idx2)
recordsOutputPathDirectory = this.recordsOutputPath.substr(0, idx2);
const writeFile = () => {
this.outputFileSystem.writeFile(this.recordsOutputPath, JSON.stringify(this.records, undefined, 2), callback);
this.outputFileSystem.writeFile(
this.recordsOutputPath,
JSON.stringify(this.records, undefined, 2),
callback
);
};
if(!recordsOutputPathDirectory)
return writeFile();
if (!recordsOutputPathDirectory) return writeFile();
this.outputFileSystem.mkdirp(recordsOutputPathDirectory, err => {
if(err) return callback(err);
if (err) return callback(err);
writeFile();
});
}
readRecords(callback) {
if(!this.recordsInputPath) {
if (!this.recordsInputPath) {
this.records = {};
return callback();
}
this.inputFileSystem.stat(this.recordsInputPath, err => {
// It doesn't exist
// We can ignore this.
if(err) return callback();
if (err) return callback();
this.inputFileSystem.readFile(this.recordsInputPath, (err, content) => {
if(err) return callback(err);
if (err) return callback(err);
try {
this.records = JSON.parse(content.toString("utf-8"));
} catch(e) {
} catch (e) {
e.message = "Cannot parse records: " + e.message;
return callback(e);
}
@ -349,14 +341,30 @@ class Compiler extends Tapable {
});
}
createChildCompiler(compilation, compilerName, compilerIndex, outputOptions, plugins) {
createChildCompiler(
compilation,
compilerName,
compilerIndex,
outputOptions,
plugins
) {
const childCompiler = new Compiler(this.context);
if(Array.isArray(plugins)) {
for(const plugin of plugins) plugin.apply(childCompiler);
if (Array.isArray(plugins)) {
for (const plugin of plugins) plugin.apply(childCompiler);
}
for(const name in this.hooks) {
if(!["make", "compile", "emit", "afterEmit", "invalid", "done", "thisCompilation"].includes(name)) {
if(childCompiler.hooks[name])
for (const name in this.hooks) {
if (
![
"make",
"compile",
"emit",
"afterEmit",
"invalid",
"done",
"thisCompilation"
].includes(name)
) {
if (childCompiler.hooks[name])
childCompiler.hooks[name].taps = this.hooks[name].taps.slice();
}
}
@ -369,20 +377,24 @@ class Compiler extends Tapable {
childCompiler.contextTimestamps = this.contextTimestamps;
const relativeCompilerName = makePathsRelative(this.context, compilerName);
if(!this.records[relativeCompilerName]) this.records[relativeCompilerName] = [];
if(this.records[relativeCompilerName][compilerIndex])
if (!this.records[relativeCompilerName])
this.records[relativeCompilerName] = [];
if (this.records[relativeCompilerName][compilerIndex])
childCompiler.records = this.records[relativeCompilerName][compilerIndex];
else
this.records[relativeCompilerName].push(childCompiler.records = {});
else this.records[relativeCompilerName].push((childCompiler.records = {}));
childCompiler.options = Object.create(this.options);
childCompiler.options.output = Object.create(childCompiler.options.output);
for(const name in outputOptions) {
for (const name in outputOptions) {
childCompiler.options.output[name] = outputOptions[name];
}
childCompiler.parentCompilation = compilation;
compilation.hooks.childCompiler.call(childCompiler, compilerName, compilerIndex);
compilation.hooks.childCompiler.call(
childCompiler,
compilerName,
compilerIndex
);
return childCompiler;
}
@ -408,13 +420,20 @@ class Compiler extends Tapable {
}
createNormalModuleFactory() {
const normalModuleFactory = new NormalModuleFactory(this.options.context, this.resolverFactory, this.options.module || {});
const normalModuleFactory = new NormalModuleFactory(
this.options.context,
this.resolverFactory,
this.options.module || {}
);
this.hooks.normalModuleFactory.call(normalModuleFactory);
return normalModuleFactory;
}
createContextModuleFactory() {
const contextModuleFactory = new ContextModuleFactory(this.resolverFactory, this.inputFileSystem);
const contextModuleFactory = new ContextModuleFactory(
this.resolverFactory,
this.inputFileSystem
);
this.hooks.contextModuleFactory.call(contextModuleFactory);
return contextModuleFactory;
}
@ -431,22 +450,22 @@ class Compiler extends Tapable {
compile(callback) {
const params = this.newCompilationParams();
this.hooks.beforeCompile.callAsync(params, err => {
if(err) return callback(err);
if (err) return callback(err);
this.hooks.compile.call(params);
const compilation = this.newCompilation(params);
this.hooks.make.callAsync(compilation, err => {
if(err) return callback(err);
if (err) return callback(err);
compilation.finish();
compilation.seal(err => {
if(err) return callback(err);
if (err) return callback(err);
this.hooks.afterCompile.callAsync(compilation, err => {
if(err) return callback(err);
if (err) return callback(err);
return callback(null, compilation);
});

View File

@ -7,29 +7,27 @@ const ConstDependency = require("./dependencies/ConstDependency");
const NullFactory = require("./NullFactory");
const ParserHelpers = require("./ParserHelpers");
const getQuery = (request) => {
const getQuery = request => {
const i = request.indexOf("?");
return i !== -1 ? request.substr(i) : "";
};
const collectDeclaration = (declarations, pattern) => {
const stack = [pattern];
while(stack.length > 0) {
while (stack.length > 0) {
const node = stack.pop();
switch(node.type) {
switch (node.type) {
case "Identifier":
declarations.add(node.name);
break;
case "ArrayPattern":
for(const element of node.elements)
if(element) stack.push(element);
for (const element of node.elements) if (element) stack.push(element);
break;
case "AssignmentPattern":
stack.push(node.left);
break;
case "ObjectPattern":
for(const property of node.properties)
stack.push(property.value);
for (const property of node.properties) stack.push(property.value);
break;
case "RestElement":
stack.push(node.argument);
@ -41,17 +39,15 @@ const collectDeclaration = (declarations, pattern) => {
const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
const declarations = new Set();
const stack = [branch];
while(stack.length > 0) {
while (stack.length > 0) {
const node = stack.pop();
// Some node could be `null` or `undefined`.
if(!node)
continue;
switch(node.type) {
if (!node) continue;
switch (node.type) {
// Walk through control statements to look for hoisted declarations.
// Some branches are skipped since they do not allow declarations.
case "BlockStatement":
for(const stmt of node.body)
stack.push(stmt);
for (const stmt of node.body) stack.push(stmt);
break;
case "IfStatement":
stack.push(node.consequent);
@ -72,23 +68,21 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
stack.push(node.body);
break;
case "SwitchStatement":
for(const cs of node.cases)
for(const consequent of cs.consequent)
stack.push(consequent);
for (const cs of node.cases)
for (const consequent of cs.consequent) stack.push(consequent);
break;
case "TryStatement":
stack.push(node.block);
if(node.handler)
stack.push(node.handler.body);
if (node.handler) stack.push(node.handler.body);
stack.push(node.finalizer);
break;
case "FunctionDeclaration":
if(includeFunctionDeclarations)
if (includeFunctionDeclarations)
collectDeclaration(declarations, node.id);
break;
case "VariableDeclaration":
if(node.kind === "var")
for(const decl of node.declarations)
if (node.kind === "var")
for (const decl of node.declarations)
collectDeclaration(declarations, decl.id);
break;
}
@ -98,118 +92,150 @@ const getHoistedDeclarations = (branch, includeFunctionDeclarations) => {
class ConstPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("ConstPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"ConstPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = parser => {
parser.hooks.statementIf.tap("ConstPlugin", statement => {
const param = parser.evaluateExpression(statement.test);
const bool = param.asBool();
if(typeof bool === "boolean") {
if(statement.test.type !== "Literal") {
const dep = new ConstDependency(`${bool}`, param.range);
dep.loc = statement.loc;
parser.state.current.addDependency(dep);
}
const branchToRemove = bool ? statement.alternate : statement.consequent;
if(branchToRemove) {
// Before removing the dead branch, the hoisted declarations
// must be collected.
//
// Given the following code:
//
// if (true) f() else g()
// if (false) {
// function f() {}
// const g = function g() {}
// if (someTest) {
// let a = 1
// var x, {y, z} = obj
// }
// } else {
// …
// }
//
// the generated code is:
//
// if (true) f() else {}
// if (false) {
// var f, x, y, z; (in loose mode)
// var x, y, z; (in strict mode)
// } else {
// …
// }
//
// NOTE: When code runs in strict mode, `var` declarations
// are hoisted but `function` declarations don't.
//
let declarations;
if(parser.scope.isStrict) {
// If the code runs in strict mode, variable declarations
// using `var` must be hoisted.
declarations = getHoistedDeclarations(branchToRemove, false);
} else {
// Otherwise, collect all hoisted declaration.
declarations = getHoistedDeclarations(branchToRemove, true);
const handler = parser => {
parser.hooks.statementIf.tap("ConstPlugin", statement => {
const param = parser.evaluateExpression(statement.test);
const bool = param.asBool();
if (typeof bool === "boolean") {
if (statement.test.type !== "Literal") {
const dep = new ConstDependency(`${bool}`, param.range);
dep.loc = statement.loc;
parser.state.current.addDependency(dep);
}
let replacement;
if(declarations.length > 0) {
replacement = `{ var ${declarations.join(", ")}; }`;
} else {
replacement = "{}";
const branchToRemove = bool
? statement.alternate
: statement.consequent;
if (branchToRemove) {
// Before removing the dead branch, the hoisted declarations
// must be collected.
//
// Given the following code:
//
// if (true) f() else g()
// if (false) {
// function f() {}
// const g = function g() {}
// if (someTest) {
// let a = 1
// var x, {y, z} = obj
// }
// } else {
// …
// }
//
// the generated code is:
//
// if (true) f() else {}
// if (false) {
// var f, x, y, z; (in loose mode)
// var x, y, z; (in strict mode)
// } else {
// …
// }
//
// NOTE: When code runs in strict mode, `var` declarations
// are hoisted but `function` declarations don't.
//
let declarations;
if (parser.scope.isStrict) {
// If the code runs in strict mode, variable declarations
// using `var` must be hoisted.
declarations = getHoistedDeclarations(branchToRemove, false);
} else {
// Otherwise, collect all hoisted declaration.
declarations = getHoistedDeclarations(branchToRemove, true);
}
let replacement;
if (declarations.length > 0) {
replacement = `{ var ${declarations.join(", ")}; }`;
} else {
replacement = "{}";
}
const dep = new ConstDependency(
replacement,
branchToRemove.range
);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
}
const dep = new ConstDependency(replacement, branchToRemove.range);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
return bool;
}
return bool;
}
});
parser.hooks.expressionConditionalOperator.tap("ConstPlugin", expression => {
const param = parser.evaluateExpression(expression.test);
const bool = param.asBool();
if(typeof bool === "boolean") {
if(expression.test.type !== "Literal") {
const dep = new ConstDependency(` ${bool}`, param.range);
dep.loc = expression.loc;
parser.state.current.addDependency(dep);
});
parser.hooks.expressionConditionalOperator.tap(
"ConstPlugin",
expression => {
const param = parser.evaluateExpression(expression.test);
const bool = param.asBool();
if (typeof bool === "boolean") {
if (expression.test.type !== "Literal") {
const dep = new ConstDependency(` ${bool}`, param.range);
dep.loc = expression.loc;
parser.state.current.addDependency(dep);
}
// Expressions do not hoist.
// It is safe to remove the dead branch.
//
// Given the following code:
//
// false ? someExpression() : otherExpression();
//
// the generated code is:
//
// false ? undefined : otherExpression();
//
const branchToRemove = bool
? expression.alternate
: expression.consequent;
const dep = new ConstDependency(
"undefined",
branchToRemove.range
);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
return bool;
}
}
// Expressions do not hoist.
// It is safe to remove the dead branch.
//
// Given the following code:
//
// false ? someExpression() : otherExpression();
//
// the generated code is:
//
// false ? undefined : otherExpression();
//
const branchToRemove = bool ? expression.alternate : expression.consequent;
const dep = new ConstDependency("undefined", branchToRemove.range);
dep.loc = branchToRemove.loc;
parser.state.current.addDependency(dep);
return bool;
}
});
parser.hooks.evaluateIdentifier.for("__resourceQuery").tap("ConstPlugin", expr => {
if(!parser.state.module) return;
return ParserHelpers.evaluateToString(getQuery(parser.state.module.resource))(expr);
});
parser.hooks.expression.for("__resourceQuery").tap("ConstPlugin", () => {
if(!parser.state.module) return;
parser.state.current.addVariable("__resourceQuery", JSON.stringify(getQuery(parser.state.module.resource)));
return true;
});
};
);
parser.hooks.evaluateIdentifier
.for("__resourceQuery")
.tap("ConstPlugin", expr => {
if (!parser.state.module) return;
return ParserHelpers.evaluateToString(
getQuery(parser.state.module.resource)
)(expr);
});
parser.hooks.expression
.for("__resourceQuery")
.tap("ConstPlugin", () => {
if (!parser.state.module) return;
parser.state.current.addVariable(
"__resourceQuery",
JSON.stringify(getQuery(parser.state.module.resource))
);
return true;
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("ConstPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("ConstPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ConstPlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("ConstPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("ConstPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("ConstPlugin", handler);
}
);
}
}

View File

@ -6,8 +6,8 @@ class ContextExclusionPlugin {
}
apply(compiler) {
compiler.hooks.contextModuleFactory.tap("ContextExclusionPlugin", (cmf) => {
cmf.hooks.contextModuleFiles.tap("ContextExclusionPlugin", (files) => {
compiler.hooks.contextModuleFactory.tap("ContextExclusionPlugin", cmf => {
cmf.hooks.contextModuleFiles.tap("ContextExclusionPlugin", files => {
return files.filter(filePath => !this.negativeMatcher.test(filePath));
});
});

View File

@ -20,7 +20,7 @@ class ContextModule extends Module {
let resource;
let resourceQuery;
const queryIdx = options.resource.indexOf("?");
if(queryIdx >= 0) {
if (queryIdx >= 0) {
resource = options.resource.substr(0, queryIdx);
resourceQuery = options.resource.substr(queryIdx);
} else {
@ -36,13 +36,13 @@ class ContextModule extends Module {
resource: resource,
resourceQuery: resourceQuery
});
if(options.resolveOptions !== undefined)
if (options.resolveOptions !== undefined)
this.resolveOptions = options.resolveOptions;
// Info from Build
this._contextDependencies = new Set([this.context]);
if(typeof options.mode !== "string")
if (typeof options.mode !== "string")
throw new Error("options.mode is a required option");
}
@ -53,77 +53,66 @@ class ContextModule extends Module {
}
contextify(context, request) {
return request.split("!").map(subrequest => {
let rp = path.relative(context, subrequest);
if(path.sep === "\\")
rp = rp.replace(/\\/g, "/");
if(rp.indexOf("../") !== 0)
rp = "./" + rp;
return rp;
}).join("!");
return request
.split("!")
.map(subrequest => {
let rp = path.relative(context, subrequest);
if (path.sep === "\\") rp = rp.replace(/\\/g, "/");
if (rp.indexOf("../") !== 0) rp = "./" + rp;
return rp;
})
.join("!");
}
identifier() {
let identifier = this.context;
if(this.options.resourceQuery)
if (this.options.resourceQuery)
identifier += ` ${this.options.resourceQuery}`;
if(this.options.mode)
identifier += ` ${this.options.mode}`;
if(!this.options.recursive)
identifier += " nonrecursive";
if(this.options.addon)
identifier += ` ${this.options.addon}`;
if(this.options.regExp)
identifier += ` ${this.options.regExp}`;
if(this.options.include)
identifier += ` include: ${this.options.include}`;
if(this.options.exclude)
identifier += ` exclude: ${this.options.exclude}`;
if(this.options.namespaceObject === "strict")
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (!this.options.recursive) identifier += " nonrecursive";
if (this.options.addon) identifier += ` ${this.options.addon}`;
if (this.options.regExp) identifier += ` ${this.options.regExp}`;
if (this.options.include) identifier += ` include: ${this.options.include}`;
if (this.options.exclude) identifier += ` exclude: ${this.options.exclude}`;
if (this.options.namespaceObject === "strict")
identifier += " strict namespace object";
else if(this.options.namespaceObject)
identifier += " namespace object";
else if (this.options.namespaceObject) identifier += " namespace object";
return identifier;
}
readableIdentifier(requestShortener) {
let identifier = requestShortener.shorten(this.context);
if(this.options.resourceQuery)
if (this.options.resourceQuery)
identifier += ` ${this.options.resourceQuery}`;
if(this.options.mode)
identifier += ` ${this.options.mode}`;
if(!this.options.recursive)
identifier += " nonrecursive";
if(this.options.addon)
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (!this.options.recursive) identifier += " nonrecursive";
if (this.options.addon)
identifier += ` ${requestShortener.shorten(this.options.addon)}`;
if(this.options.regExp)
if (this.options.regExp)
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if(this.options.include)
if (this.options.include)
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if(this.options.exclude)
if (this.options.exclude)
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
if(this.options.namespaceObject === "strict")
if (this.options.namespaceObject === "strict")
identifier += " strict namespace object";
else if(this.options.namespaceObject)
identifier += " namespace object";
else if (this.options.namespaceObject) identifier += " namespace object";
return identifier;
}
libIdent(options) {
let identifier = this.contextify(options.context, this.context);
if(this.options.mode)
identifier += ` ${this.options.mode}`;
if(this.options.recursive)
identifier += " recursive";
if(this.options.addon)
if (this.options.mode) identifier += ` ${this.options.mode}`;
if (this.options.recursive) identifier += " recursive";
if (this.options.addon)
identifier += ` ${this.contextify(options.context, this.options.addon)}`;
if(this.options.regExp)
if (this.options.regExp)
identifier += ` ${this.prettyRegExp(this.options.regExp + "")}`;
if(this.options.include)
if (this.options.include)
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
if(this.options.exclude)
if (this.options.exclude)
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
return identifier;
@ -131,7 +120,7 @@ class ContextModule extends Module {
needRebuild(fileTimestamps, contextTimestamps) {
const ts = contextTimestamps.get(this.context);
if(!ts) {
if (!ts) {
return true;
}
@ -146,65 +135,74 @@ class ContextModule extends Module {
contextDependencies: this._contextDependencies
};
this.resolveDependencies(fs, this.options, (err, dependencies) => {
if(err) return callback(err);
if (err) return callback(err);
// abort if something failed
// this will create an empty context
if(!dependencies) {
if (!dependencies) {
callback();
return;
}
// enhance dependencies with meta info
for(const dep of dependencies) {
for (const dep of dependencies) {
dep.loc = dep.userRequest;
dep.request = this.options.addon + dep.request;
}
if(this.options.mode === "sync" || this.options.mode === "eager") {
if (this.options.mode === "sync" || this.options.mode === "eager") {
// if we have an sync or eager context
// just add all dependencies and continue
this.dependencies = dependencies;
} else if(this.options.mode === "lazy-once") {
} else if (this.options.mode === "lazy-once") {
// for the lazy-once mode create a new async dependency block
// and add that block to this context
if(dependencies.length > 0) {
const block = new AsyncDependenciesBlock(this.options.chunkName, this);
for(const dep of dependencies) {
if (dependencies.length > 0) {
const block = new AsyncDependenciesBlock(
this.options.chunkName,
this
);
for (const dep of dependencies) {
block.addDependency(dep);
}
this.addBlock(block);
}
} else if(this.options.mode === "weak" || this.options.mode === "async-weak") {
} else if (
this.options.mode === "weak" ||
this.options.mode === "async-weak"
) {
// we mark all dependencies as weak
for(const dep of dependencies) {
for (const dep of dependencies) {
dep.weak = true;
}
this.dependencies = dependencies;
} else if(this.options.mode === "lazy") {
} else if (this.options.mode === "lazy") {
// if we are lazy create a new async dependency block per dependency
// and add all blocks to this context
let index = 0;
for(const dep of dependencies) {
for (const dep of dependencies) {
let chunkName = this.options.chunkName;
if(chunkName) {
if(!/\[(index|request)\]/.test(chunkName))
chunkName += "[index]";
if (chunkName) {
if (!/\[(index|request)\]/.test(chunkName)) chunkName += "[index]";
chunkName = chunkName.replace(/\[index\]/g, index++);
chunkName = chunkName.replace(/\[request\]/g, Template.toPath(dep.userRequest));
chunkName = chunkName.replace(
/\[request\]/g,
Template.toPath(dep.userRequest)
);
}
const block = new AsyncDependenciesBlock(chunkName, dep.module, dep.loc, dep.userRequest);
const block = new AsyncDependenciesBlock(
chunkName,
dep.module,
dep.loc,
dep.userRequest
);
block.addDependency(dep);
this.addBlock(block);
}
} else {
callback(new Error(`Unsupported mode "${this.options.mode}" in context`));
callback(
new Error(`Unsupported mode "${this.options.mode}" in context`)
);
return;
}
callback();
@ -218,18 +216,19 @@ class ContextModule extends Module {
return dependencies
.filter(dependency => dependency.module)
.sort((a, b) => {
if(a.userRequest === b.userRequest) {
if (a.userRequest === b.userRequest) {
return 0;
}
return a.userRequest < b.userRequest ? -1 : 1;
}).reduce((map, dep) => {
})
.reduce((map, dep) => {
map[dep.userRequest] = dep.module.id;
return map;
}, Object.create(null));
}
getFakeMap(dependencies) {
if(!this.options.namespaceObject) return 1;
if (!this.options.namespaceObject) return 1;
// if we filter first we get a new array
// therefor we dont need to create a clone of dependencies explicitly
// therefore the order of this is !important!
@ -240,43 +239,52 @@ class ContextModule extends Module {
.filter(dependency => dependency.module)
.sort((a, b) => {
return b.module.id - a.module.id;
}).reduce((map, dep) => {
const exportsType = dep.module.buildMeta && dep.module.buildMeta.exportsType;
if(!exportsType) hasNonHarmony = true;
if(exportsType === "namespace") hasNamespace = true;
if(exportsType === "named") hasNamed = true;
map[dep.module.id] = {
namespace: 1,
named: 2
}[exportsType] || 0;
})
.reduce((map, dep) => {
const exportsType =
dep.module.buildMeta && dep.module.buildMeta.exportsType;
if (!exportsType) hasNonHarmony = true;
if (exportsType === "namespace") hasNamespace = true;
if (exportsType === "named") hasNamed = true;
map[dep.module.id] =
{
namespace: 1,
named: 2
}[exportsType] || 0;
return map;
}, Object.create(null));
if(!hasNamespace && hasNonHarmony && !hasNamed) return 0;
if(hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if(!hasNamespace && !hasNonHarmony && hasNamed) return 2;
if(!hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if (!hasNamespace && hasNonHarmony && !hasNamed) return 0;
if (hasNamespace && !hasNonHarmony && !hasNamed) return 1;
if (!hasNamespace && !hasNonHarmony && hasNamed) return 2;
if (!hasNamespace && !hasNonHarmony && !hasNamed) return 1;
return fakeMap;
}
getFakeMapInitStatement(fakeMap) {
return typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : "";
return typeof fakeMap === "object"
? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};`
: "";
}
getReturn(type) {
if(type === 1) return "module";
if(type === 2) return "Object.assign({/* fake namespace object */}, module, { \"default\": module })";
if(type === 0) {
if(this.options.namespaceObject === "strict") {
return "/* fake namespace object */ { \"default\": module }";
if (type === 1) return "module";
if (type === 2)
return 'Object.assign({/* fake namespace object */}, module, { "default": module })';
if (type === 0) {
if (this.options.namespaceObject === "strict") {
return '/* fake namespace object */ { "default": module }';
} else {
return "(typeof module === \"object\" && module && module.__esModule ? module : /* fake namespace object */ { \"default\": module })";
return '(typeof module === "object" && module && module.__esModule ? module : /* fake namespace object */ { "default": module })';
}
}
}
getReturnModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") {
if(typeof fakeMap === "number") return `return ${this.getReturn(fakeMap)};`;
return `return ${fakeMapDataExpression} === 1 ? ${this.getReturn(1)} : ${fakeMapDataExpression} ? ${this.getReturn(2)} : ${this.getReturn(0)};`;
if (typeof fakeMap === "number")
return `return ${this.getReturn(fakeMap)};`;
return `return ${fakeMapDataExpression} === 1 ? ${this.getReturn(1)} : ${
fakeMapDataExpression
} ? ${this.getReturn(2)} : ${this.getReturn(0)};`;
}
getSyncSource(dependencies, id) {
@ -387,12 +395,13 @@ module.exports = webpackAsyncContext;`;
getEagerSource(dependencies, id) {
const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies);
const thenFunction = fakeMap !== 1 ?
`function(id) {
const thenFunction =
fakeMap !== 1
? `function(id) {
var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)}
}` :
"__webpack_require__";
}`
: "__webpack_require__";
return `var map = ${JSON.stringify(map, null, "\t")};
${this.getFakeMapInitStatement(fakeMap)}
@ -427,12 +436,13 @@ module.exports = webpackAsyncContext;`;
});
const map = this.getUserRequestMap(dependencies);
const fakeMap = this.getFakeMap(dependencies);
const thenFunction = fakeMap !== 1 ?
`function(id) {
const thenFunction =
fakeMap !== 1
? `function(id) {
var module = __webpack_require__(id);
${this.getReturnModuleObjectSource(fakeMap)};
}` :
"__webpack_require__";
}`
: "__webpack_require__";
return `var map = ${JSON.stringify(map, null, "\t")};
${this.getFakeMapInitStatement(fakeMap)}
@ -464,32 +474,41 @@ module.exports = webpackAsyncContext;`;
const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0]));
const map = blocks
.filter(block => block.dependencies[0].module)
.map((block) => ({
.map(block => ({
dependency: block.dependencies[0],
block: block,
userRequest: block.dependencies[0].userRequest
})).sort((a, b) => {
if(a.userRequest === b.userRequest) return 0;
}))
.sort((a, b) => {
if (a.userRequest === b.userRequest) return 0;
return a.userRequest < b.userRequest ? -1 : 1;
}).reduce((map, item) => {
const chunks = item.block.chunkGroup && item.block.chunkGroup.chunks || [];
if(chunks.length !== 1) {
})
.reduce((map, item) => {
const chunks =
(item.block.chunkGroup && item.block.chunkGroup.chunks) || [];
if (chunks.length !== 1) {
hasMultipleOrNoChunks = true;
}
const arrayStart = [item.dependency.module.id];
if(typeof fakeMap === "object")
if (typeof fakeMap === "object")
arrayStart.push(fakeMap[item.dependency.module.id]);
map[item.userRequest] = arrayStart
.concat(chunks.map(chunk => chunk.id));
map[item.userRequest] = arrayStart.concat(
chunks.map(chunk => chunk.id)
);
return map;
}, Object.create(null));
const chunksStartPosition = typeof fakeMap === "object" ? 2 : 1;
const requestPrefix = hasMultipleOrNoChunks ?
`Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))` :
`__webpack_require__.e(ids[${chunksStartPosition}])`;
const returnModuleObject = this.getReturnModuleObjectSource(fakeMap, "ids[1]");
const requestPrefix = hasMultipleOrNoChunks
? `Promise.all(ids.slice(${
chunksStartPosition
}).map(__webpack_require__.e))`
: `__webpack_require__.e(ids[${chunksStartPosition}])`;
const returnModuleObject = this.getReturnModuleObjectSource(
fakeMap,
"ids[1]"
);
return `var map = ${JSON.stringify(map, null, "\t")};
function webpackAsyncContext(req) {
@ -542,44 +561,49 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
}
getSourceString(asyncMode, runtimeTemplate) {
if(asyncMode === "lazy") {
if(this.blocks && this.blocks.length > 0) {
if (asyncMode === "lazy") {
if (this.blocks && this.blocks.length > 0) {
return this.getLazySource(this.blocks, this.id);
}
return this.getSourceForEmptyAsyncContext(this.id);
}
if(asyncMode === "eager") {
if(this.dependencies && this.dependencies.length > 0) {
if (asyncMode === "eager") {
if (this.dependencies && this.dependencies.length > 0) {
return this.getEagerSource(this.dependencies, this.id);
}
return this.getSourceForEmptyAsyncContext(this.id);
}
if(asyncMode === "lazy-once") {
if (asyncMode === "lazy-once") {
const block = this.blocks[0];
if(block) {
return this.getLazyOnceSource(block, block.dependencies, this.id, runtimeTemplate);
if (block) {
return this.getLazyOnceSource(
block,
block.dependencies,
this.id,
runtimeTemplate
);
}
return this.getSourceForEmptyAsyncContext(this.id);
}
if(asyncMode === "async-weak") {
if(this.dependencies && this.dependencies.length > 0) {
if (asyncMode === "async-weak") {
if (this.dependencies && this.dependencies.length > 0) {
return this.getAsyncWeakSource(this.dependencies, this.id);
}
return this.getSourceForEmptyAsyncContext(this.id);
}
if(asyncMode === "weak") {
if(this.dependencies && this.dependencies.length > 0) {
if (asyncMode === "weak") {
if (this.dependencies && this.dependencies.length > 0) {
return this.getWeakSyncSource(this.dependencies, this.id);
}
}
if(this.dependencies && this.dependencies.length > 0) {
if (this.dependencies && this.dependencies.length > 0) {
return this.getSyncSource(this.dependencies, this.id);
}
return this.getSourceForEmptyContext(this.id);
}
getSource(sourceString) {
if(this.useSourceMap) {
if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier());
}
return new RawSource(sourceString);
@ -596,8 +620,10 @@ webpackEmptyAsyncContext.id = ${JSON.stringify(id)};`;
const initialSize = 160;
// if we dont have dependencies we stop here.
return this.dependencies
.reduce((size, dependency) => size + 5 + dependency.userRequest.length, initialSize);
return this.dependencies.reduce(
(size, dependency) => size + 5 + dependency.userRequest.length,
initialSize
);
}
}

View File

@ -25,7 +25,7 @@ module.exports = class ContextModuleFactory extends Tapable {
alternatives: new AsyncSeriesWaterfallHook(["modules"])
};
this._pluginCompat.tap("ContextModuleFactory", options => {
switch(options.name) {
switch (options.name) {
case "before-resolve":
case "after-resolve":
case "alternatives":
@ -41,72 +41,120 @@ module.exports = class ContextModuleFactory extends Tapable {
const dependencies = data.dependencies;
const resolveOptions = data.resolveOptions;
const dependency = dependencies[0];
this.hooks.beforeResolve.callAsync(Object.assign({
context: context,
dependencies: dependencies,
resolveOptions
}, dependency.options), (err, beforeResolveResult) => {
if(err) return callback(err);
// Ignored
if(!beforeResolveResult) return callback();
const context = beforeResolveResult.context;
const request = beforeResolveResult.request;
const resolveOptions = beforeResolveResult.resolveOptions;
let loaders, resource, loadersPrefix = "";
const idx = request.lastIndexOf("!");
if(idx >= 0) {
loaders = request.substr(0, idx + 1);
let i;
for(i = 0; i < loaders.length && loaders[i] === "!"; i++) {
loadersPrefix += "!";
}
loaders = loaders.substr(i).replace(/!+$/, "").replace(/!!+/g, "!");
if(loaders === "") loaders = [];
else loaders = loaders.split("!");
resource = request.substr(idx + 1);
} else {
loaders = [];
resource = request;
}
const contextResolver = this.resolverFactory.get("context", resolveOptions || EMPTY_RESOLVE_OPTIONS);
const loaderResolver = this.resolverFactory.get("loader", EMPTY_RESOLVE_OPTIONS);
asyncLib.parallel([
callback => {
contextResolver.resolve({}, context, resource, {}, (err, result) => {
if(err) return callback(err);
callback(null, result);
});
this.hooks.beforeResolve.callAsync(
Object.assign(
{
context: context,
dependencies: dependencies,
resolveOptions
},
callback => {
asyncLib.map(loaders, (loader, callback) => {
loaderResolver.resolve({}, context, loader, {}, (err, result) => {
if(err) return callback(err);
callback(null, result);
});
}, callback);
dependency.options
),
(err, beforeResolveResult) => {
if (err) return callback(err);
// Ignored
if (!beforeResolveResult) return callback();
const context = beforeResolveResult.context;
const request = beforeResolveResult.request;
const resolveOptions = beforeResolveResult.resolveOptions;
let loaders,
resource,
loadersPrefix = "";
const idx = request.lastIndexOf("!");
if (idx >= 0) {
loaders = request.substr(0, idx + 1);
let i;
for (i = 0; i < loaders.length && loaders[i] === "!"; i++) {
loadersPrefix += "!";
}
loaders = loaders
.substr(i)
.replace(/!+$/, "")
.replace(/!!+/g, "!");
if (loaders === "") loaders = [];
else loaders = loaders.split("!");
resource = request.substr(idx + 1);
} else {
loaders = [];
resource = request;
}
], (err, result) => {
if(err) return callback(err);
this.hooks.afterResolve.callAsync(Object.assign({
addon: loadersPrefix + result[1].join("!") + (result[1].length > 0 ? "!" : ""),
resource: result[0],
resolveDependencies: this.resolveDependencies.bind(this)
}, beforeResolveResult), (err, result) => {
if(err) return callback(err);
const contextResolver = this.resolverFactory.get(
"context",
resolveOptions || EMPTY_RESOLVE_OPTIONS
);
const loaderResolver = this.resolverFactory.get(
"loader",
EMPTY_RESOLVE_OPTIONS
);
// Ignored
if(!result) return callback();
asyncLib.parallel(
[
callback => {
contextResolver.resolve(
{},
context,
resource,
{},
(err, result) => {
if (err) return callback(err);
callback(null, result);
}
);
},
callback => {
asyncLib.map(
loaders,
(loader, callback) => {
loaderResolver.resolve(
{},
context,
loader,
{},
(err, result) => {
if (err) return callback(err);
callback(null, result);
}
);
},
callback
);
}
],
(err, result) => {
if (err) return callback(err);
return callback(null, new ContextModule(result.resolveDependencies, result));
});
});
});
this.hooks.afterResolve.callAsync(
Object.assign(
{
addon:
loadersPrefix +
result[1].join("!") +
(result[1].length > 0 ? "!" : ""),
resource: result[0],
resolveDependencies: this.resolveDependencies.bind(this)
},
beforeResolveResult
),
(err, result) => {
if (err) return callback(err);
// Ignored
if (!result) return callback();
return callback(
null,
new ContextModule(result.resolveDependencies, result)
);
}
);
}
);
}
);
}
resolveDependencies(fs, options, callback) {
@ -117,63 +165,76 @@ module.exports = class ContextModuleFactory extends Tapable {
let regExp = options.regExp;
let include = options.include;
let exclude = options.exclude;
if(!regExp || !resource)
return callback(null, []);
if (!regExp || !resource) return callback(null, []);
const addDirectory = (directory, callback) => {
fs.readdir(directory, (err, files) => {
if(err) return callback(err);
if (err) return callback(err);
files = cmf.hooks.contextModuleFiles.call(files);
if(!files || files.length === 0) return callback(null, []);
asyncLib.map(files.filter(p => p.indexOf(".") !== 0), (seqment, callback) => {
if (!files || files.length === 0) return callback(null, []);
asyncLib.map(
files.filter(p => p.indexOf(".") !== 0),
(seqment, callback) => {
const subResource = path.join(directory, seqment);
const subResource = path.join(directory, seqment);
if(!exclude || !subResource.match(exclude)) {
fs.stat(subResource, (err, stat) => {
if(err) {
if(err.code === "ENOENT") {
// ENOENT is ok here because the file may have been deleted between
// the readdir and stat calls.
return callback();
} else {
return callback(err);
if (!exclude || !subResource.match(exclude)) {
fs.stat(subResource, (err, stat) => {
if (err) {
if (err.code === "ENOENT") {
// ENOENT is ok here because the file may have been deleted between
// the readdir and stat calls.
return callback();
} else {
return callback(err);
}
}
}
if(stat.isDirectory()) {
if (stat.isDirectory()) {
if (!recursive) return callback();
addDirectory.call(this, subResource, callback);
} else if (
stat.isFile() &&
(!include || subResource.match(include))
) {
const obj = {
context: resource,
request:
"." +
subResource.substr(resource.length).replace(/\\/g, "/")
};
if(!recursive) return callback();
addDirectory.call(this, subResource, callback);
this.hooks.alternatives.callAsync(
[obj],
(err, alternatives) => {
if (err) return callback(err);
alternatives = alternatives
.filter(obj => regExp.test(obj.request))
.map(obj => {
const dep = new ContextElementDependency(
obj.request + resourceQuery,
obj.request
);
dep.optional = true;
return dep;
});
callback(null, alternatives);
}
);
} else callback();
});
} else callback();
},
(err, result) => {
if (err) return callback(err);
} else if(stat.isFile() && (!include || subResource.match(include))) {
if (!result) return callback(null, []);
const obj = {
context: resource,
request: "." + subResource.substr(resource.length).replace(/\\/g, "/")
};
this.hooks.alternatives.callAsync([obj], (err, alternatives) => {
if(err) return callback(err);
alternatives = alternatives.filter(obj => regExp.test(obj.request)).map(obj => {
const dep = new ContextElementDependency(obj.request + resourceQuery, obj.request);
dep.optional = true;
return dep;
});
callback(null, alternatives);
});
} else callback();
});
} else callback();
}, (err, result) => {
if(err) return callback(err);
if(!result) return callback(null, []);
callback(null, result.filter(Boolean).reduce((a, i) => a.concat(i), []));
});
callback(
null,
result.filter(Boolean).reduce((a, i) => a.concat(i), [])
);
}
);
});
};

View File

@ -8,26 +8,37 @@ const path = require("path");
const ContextElementDependency = require("./dependencies/ContextElementDependency");
class ContextReplacementPlugin {
constructor(resourceRegExp, newContentResource, newContentRecursive, newContentRegExp) {
constructor(
resourceRegExp,
newContentResource,
newContentRecursive,
newContentRegExp
) {
this.resourceRegExp = resourceRegExp;
if(typeof newContentResource === "function") {
if (typeof newContentResource === "function") {
this.newContentCallback = newContentResource;
} else if(typeof newContentResource === "string" && typeof newContentRecursive === "object") {
} else if (
typeof newContentResource === "string" &&
typeof newContentRecursive === "object"
) {
this.newContentResource = newContentResource;
this.newContentCreateContextMap = (fs, callback) => {
callback(null, newContentRecursive);
};
} else if(typeof newContentResource === "string" && typeof newContentRecursive === "function") {
} else if (
typeof newContentResource === "string" &&
typeof newContentRecursive === "function"
) {
this.newContentResource = newContentResource;
this.newContentCreateContextMap = newContentRecursive;
} else {
if(typeof newContentResource !== "string") {
if (typeof newContentResource !== "string") {
newContentRegExp = newContentRecursive;
newContentRecursive = newContentResource;
newContentResource = undefined;
}
if(typeof newContentRecursive !== "boolean") {
if (typeof newContentRecursive !== "boolean") {
newContentRegExp = newContentRecursive;
newContentRecursive = undefined;
}
@ -45,48 +56,48 @@ class ContextReplacementPlugin {
const newContentRegExp = this.newContentRegExp;
const newContentCreateContextMap = this.newContentCreateContextMap;
compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", (cmf) => {
cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", (result) => {
if(!result) return;
if(resourceRegExp.test(result.request)) {
if(typeof newContentResource !== "undefined")
compiler.hooks.contextModuleFactory.tap("ContextReplacementPlugin", cmf => {
cmf.hooks.beforeResolve.tap("ContextReplacementPlugin", result => {
if (!result) return;
if (resourceRegExp.test(result.request)) {
if (typeof newContentResource !== "undefined")
result.request = newContentResource;
if(typeof newContentRecursive !== "undefined")
if (typeof newContentRecursive !== "undefined")
result.recursive = newContentRecursive;
if(typeof newContentRegExp !== "undefined")
if (typeof newContentRegExp !== "undefined")
result.regExp = newContentRegExp;
if(typeof newContentCallback === "function") {
if (typeof newContentCallback === "function") {
newContentCallback(result);
} else {
for(const d of result.dependencies) {
if(d.critical)
d.critical = false;
for (const d of result.dependencies) {
if (d.critical) d.critical = false;
}
}
}
return result;
});
cmf.hooks.afterResolve.tap("ContextReplacementPlugin", (result) => {
if(!result) return;
if(resourceRegExp.test(result.resource)) {
if(typeof newContentResource !== "undefined")
cmf.hooks.afterResolve.tap("ContextReplacementPlugin", result => {
if (!result) return;
if (resourceRegExp.test(result.resource)) {
if (typeof newContentResource !== "undefined")
result.resource = path.resolve(result.resource, newContentResource);
if(typeof newContentRecursive !== "undefined")
if (typeof newContentRecursive !== "undefined")
result.recursive = newContentRecursive;
if(typeof newContentRegExp !== "undefined")
if (typeof newContentRegExp !== "undefined")
result.regExp = newContentRegExp;
if(typeof newContentCreateContextMap === "function")
result.resolveDependencies = createResolveDependenciesFromContextMap(newContentCreateContextMap);
if(typeof newContentCallback === "function") {
if (typeof newContentCreateContextMap === "function")
result.resolveDependencies = createResolveDependenciesFromContextMap(
newContentCreateContextMap
);
if (typeof newContentCallback === "function") {
const origResource = result.resource;
newContentCallback(result);
if(result.resource !== origResource) {
if (result.resource !== origResource) {
result.resource = path.resolve(origResource, result.resource);
}
} else {
for(const d of result.dependencies) {
if(d.critical)
d.critical = false;
for (const d of result.dependencies) {
if (d.critical) d.critical = false;
}
}
}
@ -96,12 +107,15 @@ class ContextReplacementPlugin {
}
}
const createResolveDependenciesFromContextMap = (createContextMap) => {
const createResolveDependenciesFromContextMap = createContextMap => {
const resolveDependenciesFromContextMap = (fs, options, callback) => {
createContextMap(fs, (err, map) => {
if(err) return callback(err);
const dependencies = Object.keys(map).map((key) => {
return new ContextElementDependency(map[key] + options.resourceQuery, key);
if (err) return callback(err);
const dependencies = Object.keys(map).map(key => {
return new ContextElementDependency(
map[key] + options.resourceQuery,
key
);
});
callback(null, dependencies);
});

View File

@ -10,18 +10,25 @@ const ParserHelpers = require("./ParserHelpers");
const NullFactory = require("./NullFactory");
const stringifyObj = obj => {
return "Object({" + Object.keys(obj).map((key) => {
const code = obj[key];
return JSON.stringify(key) + ":" + toCode(code);
}).join(",") + "})";
return (
"Object({" +
Object.keys(obj)
.map(key => {
const code = obj[key];
return JSON.stringify(key) + ":" + toCode(code);
})
.join(",") +
"})"
);
};
const toCode = code => {
if(code === null) return "null";
else if(code === undefined) return "undefined";
else if(code instanceof RegExp && code.toString) return code.toString();
else if(typeof code === "function" && code.toString) return "(" + code.toString() + ")";
else if(typeof code === "object") return stringifyObj(code);
if (code === null) return "null";
else if (code === undefined) return "undefined";
else if (code instanceof RegExp && code.toString) return code.toString();
else if (typeof code === "function" && code.toString)
return "(" + code.toString() + ")";
else if (typeof code === "object") return stringifyObj(code);
else return code + "";
};
@ -32,100 +39,159 @@ class DefinePlugin {
apply(compiler) {
const definitions = this.definitions;
compiler.hooks.compilation.tap("DefinePlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"DefinePlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const handler = (parser) => {
const walkDefinitions = (definitions, prefix) => {
Object.keys(definitions).forEach((key) => {
const code = definitions[key];
if(code && typeof code === "object" && !(code instanceof RegExp)) {
walkDefinitions(code, prefix + key + ".");
applyObjectDefine(prefix + key, code);
return;
const handler = parser => {
const walkDefinitions = (definitions, prefix) => {
Object.keys(definitions).forEach(key => {
const code = definitions[key];
if (
code &&
typeof code === "object" &&
!(code instanceof RegExp)
) {
walkDefinitions(code, prefix + key + ".");
applyObjectDefine(prefix + key, code);
return;
}
applyDefineKey(prefix, key);
applyDefine(prefix + key, code);
});
};
const applyDefineKey = (prefix, key) => {
const splittedKey = key.split(".");
splittedKey.slice(1).forEach((_, i) => {
const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
parser.hooks.canRename
.for(fullKey)
.tap("DefinePlugin", ParserHelpers.approve);
});
};
const applyDefine = (key, code) => {
const isTypeof = /^typeof\s+/.test(key);
if (isTypeof) key = key.replace(/^typeof\s+/, "");
let recurse = false;
let recurseTypeof = false;
code = toCode(code);
if (!isTypeof) {
parser.hooks.canRename
.for(key)
.tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier
.for(key)
.tap("DefinePlugin", expr => {
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "a": "b",
* "b": "a"
* });
*/
if (recurse) return;
recurse = true;
const res = parser.evaluate(code);
recurse = false;
res.setRange(expr.range);
return res;
});
parser.hooks.expression
.for(key)
.tap(
"DefinePlugin",
/__webpack_require__/.test(code)
? ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
code
)
: ParserHelpers.toConstantDependency(parser, code)
);
}
applyDefineKey(prefix, key);
applyDefine(prefix + key, code);
});
};
const applyDefineKey = (prefix, key) => {
const splittedKey = key.split(".");
splittedKey.slice(1).forEach((_, i) => {
const fullKey = prefix + splittedKey.slice(0, i + 1).join(".");
parser.hooks.canRename.for(fullKey).tap("DefinePlugin", ParserHelpers.approve);
});
};
const applyDefine = (key, code) => {
const isTypeof = /^typeof\s+/.test(key);
if(isTypeof) key = key.replace(/^typeof\s+/, "");
let recurse = false;
let recurseTypeof = false;
code = toCode(code);
if(!isTypeof) {
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => {
const typeofCode = isTypeof ? code : "typeof (" + code + ")";
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", expr => {
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "a": "b",
* "b": "a"
* "typeof a": "tyepof b",
* "typeof b": "typeof a"
* });
*/
if(recurse) return;
recurse = true;
const res = parser.evaluate(code);
recurse = false;
if (recurseTypeof) return;
recurseTypeof = true;
const res = parser.evaluate(typeofCode);
recurseTypeof = false;
res.setRange(expr.range);
return res;
});
parser.hooks.expression.for(key).tap("DefinePlugin", /__webpack_require__/.test(code) ? ParserHelpers.toConstantDependencyWithWebpackRequire(parser, code) : ParserHelpers.toConstantDependency(parser, code));
}
const typeofCode = isTypeof ? code : "typeof (" + code + ")";
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", (expr) => {
/**
* this is needed in case there is a recursion in the DefinePlugin
* to prevent an endless recursion
* e.g.: new DefinePlugin({
* "typeof a": "tyepof b",
* "typeof b": "typeof a"
* });
*/
if(recurseTypeof) return;
recurseTypeof = true;
const res = parser.evaluate(typeofCode);
recurseTypeof = false;
res.setRange(expr.range);
return res;
});
parser.hooks.typeof.for(key).tap("DefinePlugin", (expr) => {
const res = parser.evaluate(typeofCode);
if(!res.isString()) return;
return ParserHelpers.toConstantDependency(parser, JSON.stringify(res.string)).bind(parser)(expr);
});
parser.hooks.typeof.for(key).tap("DefinePlugin", expr => {
const res = parser.evaluate(typeofCode);
if (!res.isString()) return;
return ParserHelpers.toConstantDependency(
parser,
JSON.stringify(res.string)
).bind(parser)(expr);
});
};
const applyObjectDefine = (key, obj) => {
const code = stringifyObj(obj);
parser.hooks.canRename
.for(key)
.tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier
.for(key)
.tap("DefinePlugin", expr =>
new BasicEvaluatedExpression().setTruthy().setRange(expr.range)
);
parser.hooks.evaluateTypeof
.for(key)
.tap("DefinePlugin", ParserHelpers.evaluateToString("object"));
parser.hooks.expression
.for(key)
.tap(
"DefinePlugin",
/__webpack_require__/.test(code)
? ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
code
)
: ParserHelpers.toConstantDependency(parser, code)
);
parser.hooks.typeof
.for(key)
.tap(
"DefinePlugin",
ParserHelpers.toConstantDependency(
parser,
JSON.stringify("object")
)
);
};
walkDefinitions(definitions, "");
};
const applyObjectDefine = (key, obj) => {
const code = stringifyObj(obj);
parser.hooks.canRename.for(key).tap("DefinePlugin", ParserHelpers.approve);
parser.hooks.evaluateIdentifier.for(key).tap("DefinePlugin", (expr) => new BasicEvaluatedExpression().setTruthy().setRange(expr.range));
parser.hooks.evaluateTypeof.for(key).tap("DefinePlugin", ParserHelpers.evaluateToString("object"));
parser.hooks.expression.for(key).tap("DefinePlugin", /__webpack_require__/.test(code) ? ParserHelpers.toConstantDependencyWithWebpackRequire(parser, code) : ParserHelpers.toConstantDependency(parser, code));
parser.hooks.typeof.for(key).tap("DefinePlugin", ParserHelpers.toConstantDependency(parser, JSON.stringify("object")));
};
walkDefinitions(definitions, "");
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("DefinePlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("DefinePlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("DefinePlugin", handler);
}
);
}
}
module.exports = DefinePlugin;

View File

@ -25,11 +25,15 @@ class DelegatedModule extends Module {
}
libIdent(options) {
return typeof this.originalRequest === "string" ? this.originalRequest : this.originalRequest.libIdent(options);
return typeof this.originalRequest === "string"
? this.originalRequest
: this.originalRequest.libIdent(options);
}
identifier() {
return `delegated ${JSON.stringify(this.request)} from ${this.sourceRequest}`;
return `delegated ${JSON.stringify(this.request)} from ${
this.sourceRequest
}`;
}
readableIdentifier() {
@ -45,7 +49,9 @@ class DelegatedModule extends Module {
this.buildMeta = Object.assign({}, this.delegateData.buildMeta);
this.buildInfo = {};
this.addDependency(new DelegatedSourceDependency(this.sourceRequest));
this.addDependency(new DelegatedExportsDependency(this, this.delegateData.exports || true));
this.addDependency(
new DelegatedExportsDependency(this, this.delegateData.exports || true)
);
callback();
}
@ -54,7 +60,7 @@ class DelegatedModule extends Module {
const sourceModule = dep.module;
let str;
if(!sourceModule) {
if (!sourceModule) {
str = WebpackMissingModule.moduleCode(this.sourceRequest);
} else {
str = `module.exports = (${runtime.moduleExports({
@ -62,7 +68,7 @@ class DelegatedModule extends Module {
request: dep.request
})})`;
switch(this.type) {
switch (this.type) {
case "require":
str += `(${JSON.stringify(this.request)})`;
break;
@ -74,7 +80,7 @@ class DelegatedModule extends Module {
str += ";";
}
if(this.useSourceMap) {
if (this.useSourceMap) {
return new OriginalSource(str, this.identifier());
} else {
return new RawSource(str);

View File

@ -20,39 +20,69 @@ class DelegatedModuleFactoryPlugin {
apply(normalModuleFactory) {
const scope = this.options.scope;
if(scope) {
normalModuleFactory.hooks.factory.tap("DelegatedModuleFactoryPlugin", factory => (data, callback) => {
const dependency = data.dependencies[0];
const request = dependency.request;
if(request && request.indexOf(scope + "/") === 0) {
const innerRequest = "." + request.substr(scope.length);
let resolved;
if(innerRequest in this.options.content) {
resolved = this.options.content[innerRequest];
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, innerRequest, request));
}
for(let i = 0; i < this.options.extensions.length; i++) {
const extension = this.options.extensions[i];
const requestPlusExt = innerRequest + extension;
if(requestPlusExt in this.options.content) {
resolved = this.options.content[requestPlusExt];
return callback(null, new DelegatedModule(this.options.source, resolved, this.options.type, requestPlusExt, request + extension));
if (scope) {
normalModuleFactory.hooks.factory.tap(
"DelegatedModuleFactoryPlugin",
factory => (data, callback) => {
const dependency = data.dependencies[0];
const request = dependency.request;
if (request && request.indexOf(scope + "/") === 0) {
const innerRequest = "." + request.substr(scope.length);
let resolved;
if (innerRequest in this.options.content) {
resolved = this.options.content[innerRequest];
return callback(
null,
new DelegatedModule(
this.options.source,
resolved,
this.options.type,
innerRequest,
request
)
);
}
for (let i = 0; i < this.options.extensions.length; i++) {
const extension = this.options.extensions[i];
const requestPlusExt = innerRequest + extension;
if (requestPlusExt in this.options.content) {
resolved = this.options.content[requestPlusExt];
return callback(
null,
new DelegatedModule(
this.options.source,
resolved,
this.options.type,
requestPlusExt,
request + extension
)
);
}
}
}
return factory(data, callback);
}
return factory(data, callback);
});
);
} else {
normalModuleFactory.hooks.module.tap("DelegatedModuleFactoryPlugin", module => {
if(module.libIdent) {
const request = module.libIdent(this.options);
if(request && request in this.options.content) {
const resolved = this.options.content[request];
return new DelegatedModule(this.options.source, resolved, this.options.type, request, module);
normalModuleFactory.hooks.module.tap(
"DelegatedModuleFactoryPlugin",
module => {
if (module.libIdent) {
const request = module.libIdent(this.options);
if (request && request in this.options.content) {
const resolved = this.options.content[request];
return new DelegatedModule(
this.options.source,
resolved,
this.options.type,
request,
module
);
}
}
return module;
}
return module;
});
);
}
}
}

View File

@ -16,16 +16,21 @@ class DelegatedPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("DelegatedPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory);
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory());
});
compiler.hooks.compilation.tap(
"DelegatedPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
DelegatedSourceDependency,
normalModuleFactory
);
compilation.dependencyFactories.set(
DelegatedExportsDependency,
new NullFactory()
);
}
);
compiler.hooks.compile.tap("DelegatedPlugin", ({
normalModuleFactory
}) => {
compiler.hooks.compile.tap("DelegatedPlugin", ({ normalModuleFactory }) => {
new DelegatedModuleFactoryPlugin(this.options).apply(normalModuleFactory);
});
}

View File

@ -19,12 +19,14 @@ class DependenciesBlock {
}
addVariable(name, expression, dependencies) {
for(let v of this.variables) {
if(v.name === name && v.expression === expression) {
for (let v of this.variables) {
if (v.name === name && v.expression === expression) {
return;
}
}
this.variables.push(new DependenciesBlockVariable(name, expression, dependencies));
this.variables.push(
new DependenciesBlockVariable(name, expression, dependencies)
);
}
addDependency(dependency) {
@ -33,59 +35,47 @@ class DependenciesBlock {
removeDependency(dependency) {
const idx = this.dependencies.indexOf(dependency);
if(idx >= 0)
this.dependencies.splice(idx, 1);
if (idx >= 0) this.dependencies.splice(idx, 1);
}
updateHash(hash) {
for(const dep of this.dependencies)
dep.updateHash(hash);
for(const block of this.blocks)
block.updateHash(hash);
for(const variable of this.variables)
variable.updateHash(hash);
for (const dep of this.dependencies) dep.updateHash(hash);
for (const block of this.blocks) block.updateHash(hash);
for (const variable of this.variables) variable.updateHash(hash);
}
disconnect() {
for(const dep of this.dependencies)
dep.disconnect();
for(const block of this.blocks)
block.disconnect();
for(const variable of this.variables)
variable.disconnect();
for (const dep of this.dependencies) dep.disconnect();
for (const block of this.blocks) block.disconnect();
for (const variable of this.variables) variable.disconnect();
}
unseal() {
for(const block of this.blocks)
block.unseal();
for (const block of this.blocks) block.unseal();
}
hasDependencies(filter) {
if(filter) {
for(const dep of this.dependencies) {
if(filter(dep))
return true;
if (filter) {
for (const dep of this.dependencies) {
if (filter(dep)) return true;
}
} else {
if(this.dependencies.length > 0) {
if (this.dependencies.length > 0) {
return true;
}
}
for(const block of this.blocks) {
if(block.hasDependencies(filter))
return true;
for (const block of this.blocks) {
if (block.hasDependencies(filter)) return true;
}
for(const variable of this.variables) {
if(variable.hasDependencies(filter))
return true;
for (const variable of this.variables) {
if (variable.hasDependencies(filter)) return true;
}
return false;
}
sortItems() {
for(const block of this.blocks)
block.sortItems();
for (const block of this.blocks) block.sortItems();
}
}

View File

@ -17,32 +17,33 @@ class DependenciesBlockVariable {
updateHash(hash) {
hash.update(this.name);
hash.update(this.expression);
for(const d of this.dependencies) {
for (const d of this.dependencies) {
d.updateHash(hash);
}
}
expressionSource(dependencyTemplates, runtimeTemplate) {
const source = new ReplaceSource(new RawSource(this.expression));
for(const dep of this.dependencies) {
for (const dep of this.dependencies) {
const template = dependencyTemplates.get(dep.constructor);
if(!template) throw new Error(`No template for dependency: ${dep.constructor.name}`);
if (!template)
throw new Error(`No template for dependency: ${dep.constructor.name}`);
template.apply(dep, source, runtimeTemplate, dependencyTemplates);
}
return source;
}
disconnect() {
for(const d of this.dependencies) {
for (const d of this.dependencies) {
d.disconnect();
}
}
hasDependencies(filter) {
if(filter) {
if(this.dependencies.some(filter)) return true;
if (filter) {
if (this.dependencies.some(filter)) return true;
} else {
if(this.dependencies.length > 0) return true;
if (this.dependencies.length > 0) return true;
}
return false;
}

View File

@ -18,11 +18,11 @@ class Dependency {
// Returns the referenced module and export
getReference() {
if(!this.module) return null;
if (!this.module) return null;
return {
module: this.module,
weak: this.weak,
importedNames: true, // true: full object, false: only sideeffects/no export, array of strings: the exports with this names
importedNames: true // true: full object, false: only sideeffects/no export, array of strings: the exports with this names
};
}

View File

@ -16,19 +16,34 @@ class DllEntryPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("DllEntryPlugin", (compilation, {
normalModuleFactory
}) => {
const dllModuleFactory = new DllModuleFactory();
compilation.dependencyFactories.set(DllEntryDependency, dllModuleFactory);
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
});
compiler.hooks.compilation.tap(
"DllEntryPlugin",
(compilation, { normalModuleFactory }) => {
const dllModuleFactory = new DllModuleFactory();
compilation.dependencyFactories.set(
DllEntryDependency,
dllModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("DllEntryPlugin", (compilation, callback) => {
compilation.addEntry(this.context, new DllEntryDependency(this.entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`;
return dep;
}), this.name), this.name, callback);
compilation.addEntry(
this.context,
new DllEntryDependency(
this.entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
dep.loc = `${this.name}:${idx}`;
return dep;
}),
this.name
),
this.name,
callback
);
});
}
}

View File

@ -14,7 +14,15 @@ class DllModuleFactory extends Tapable {
}
create(data, callback) {
const dependency = data.dependencies[0];
callback(null, new DllModule(data.context, dependency.dependencies, dependency.name, dependency.type));
callback(
null,
new DllModule(
data.context,
dependency.dependencies,
dependency.name,
dependency.type
)
);
}
}

View File

@ -20,12 +20,10 @@ class DllPlugin {
apply(compiler) {
compiler.hooks.entryOption.tap("DllPlugin", (context, entry) => {
const itemToPlugin = (item, name) => {
if(Array.isArray(item))
return new DllEntryPlugin(context, item, name);
else
throw new Error("DllPlugin: supply an Array as entry");
if (Array.isArray(item)) return new DllEntryPlugin(context, item, name);
else throw new Error("DllPlugin: supply an Array as entry");
};
if(typeof entry === "object" && !Array.isArray(entry)) {
if (typeof entry === "object" && !Array.isArray(entry)) {
Object.keys(entry).forEach(name => {
itemToPlugin(entry[name], name).apply(compiler);
});

View File

@ -20,39 +20,54 @@ class DllReferencePlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("DllReferencePlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(DelegatedSourceDependency, normalModuleFactory);
compilation.dependencyFactories.set(DelegatedExportsDependency, new NullFactory());
});
compiler.hooks.beforeCompile.tapAsync("DllReferencePlugin", (params, callback) => {
const manifest = this.options.manifest;
if(typeof manifest === "string") {
params.compilationDependencies.add(manifest);
compiler.inputFileSystem.readFile(manifest, (err, result) => {
if(err) return callback(err);
params["dll reference " + manifest] = JSON.parse(result.toString("utf-8"));
return callback();
});
} else {
return callback();
compiler.hooks.compilation.tap(
"DllReferencePlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
DelegatedSourceDependency,
normalModuleFactory
);
compilation.dependencyFactories.set(
DelegatedExportsDependency,
new NullFactory()
);
}
});
);
compiler.hooks.compile.tap("DllReferencePlugin", (params) => {
compiler.hooks.beforeCompile.tapAsync(
"DllReferencePlugin",
(params, callback) => {
const manifest = this.options.manifest;
if (typeof manifest === "string") {
params.compilationDependencies.add(manifest);
compiler.inputFileSystem.readFile(manifest, (err, result) => {
if (err) return callback(err);
params["dll reference " + manifest] = JSON.parse(
result.toString("utf-8")
);
return callback();
});
} else {
return callback();
}
}
);
compiler.hooks.compile.tap("DllReferencePlugin", params => {
let manifest = this.options.manifest;
if(typeof manifest === "string") {
if (typeof manifest === "string") {
manifest = params["dll reference " + manifest];
}
const name = this.options.name || manifest.name;
const sourceType = this.options.sourceType || (manifest && manifest.type) || "var";
const sourceType =
this.options.sourceType || (manifest && manifest.type) || "var";
const externals = {};
const source = "dll-reference " + name;
externals[source] = name;
const normalModuleFactory = params.normalModuleFactory;
new ExternalModuleFactoryPlugin(sourceType, externals).apply(normalModuleFactory);
new ExternalModuleFactoryPlugin(sourceType, externals).apply(
normalModuleFactory
);
new DelegatedModuleFactoryPlugin({
source: source,
type: this.options.type,

View File

@ -17,44 +17,55 @@ class DynamicEntryPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("DynamicEntryPlugin", (compilation, {
normalModuleFactory
}) => {
const multiModuleFactory = new MultiModuleFactory();
compiler.hooks.compilation.tap(
"DynamicEntryPlugin",
(compilation, { normalModuleFactory }) => {
const multiModuleFactory = new MultiModuleFactory();
compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory);
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
});
compilation.dependencyFactories.set(
MultiEntryDependency,
multiModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("DynamicEntryPlugin", (compilation, callback) => {
const addEntry = (entry, name) => {
const dep = DynamicEntryPlugin.createDependency(entry, name);
return new Promise((resolve, reject) => {
compilation.addEntry(this.context, dep, name, (err) => {
if(err) return reject(err);
resolve();
compiler.hooks.make.tapAsync(
"DynamicEntryPlugin",
(compilation, callback) => {
const addEntry = (entry, name) => {
const dep = DynamicEntryPlugin.createDependency(entry, name);
return new Promise((resolve, reject) => {
compilation.addEntry(this.context, dep, name, err => {
if (err) return reject(err);
resolve();
});
});
});
};
};
Promise.resolve(this.entry()).then((entry) => {
if(typeof entry === "string" || Array.isArray(entry)) {
addEntry(entry, "main").then(() => callback(), callback);
} else if(typeof entry === "object") {
Promise.all(Object.keys(entry).map((name) => {
return addEntry(entry[name], name);
})).then(() => callback(), callback);
}
});
});
Promise.resolve(this.entry()).then(entry => {
if (typeof entry === "string" || Array.isArray(entry)) {
addEntry(entry, "main").then(() => callback(), callback);
} else if (typeof entry === "object") {
Promise.all(
Object.keys(entry).map(name => {
return addEntry(entry[name], name);
})
).then(() => callback(), callback);
}
});
}
);
}
}
module.exports = DynamicEntryPlugin;
DynamicEntryPlugin.createDependency = (entry, name) => {
if(Array.isArray(entry))
if (Array.isArray(entry))
return MultiEntryPlugin.createDependency(entry, name);
else
return SingleEntryPlugin.createDependency(entry, name);
else return SingleEntryPlugin.createDependency(entry, name);
};

View File

@ -9,7 +9,7 @@ const MultiEntryPlugin = require("./MultiEntryPlugin");
const DynamicEntryPlugin = require("./DynamicEntryPlugin");
const itemToPlugin = (context, item, name) => {
if(Array.isArray(item)) {
if (Array.isArray(item)) {
return new MultiEntryPlugin(context, item, name);
}
return new SingleEntryPlugin(context, item, name);
@ -18,13 +18,13 @@ const itemToPlugin = (context, item, name) => {
module.exports = class EntryOptionPlugin {
apply(compiler) {
compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => {
if(typeof entry === "string" || Array.isArray(entry)) {
if (typeof entry === "string" || Array.isArray(entry)) {
itemToPlugin(context, entry, "main").apply(compiler);
} else if(typeof entry === "object") {
for(const name of Object.keys(entry)) {
} else if (typeof entry === "object") {
for (const name of Object.keys(entry)) {
itemToPlugin(context, entry[name], name).apply(compiler);
}
} else if(typeof entry === "function") {
} else if (typeof entry === "function") {
new DynamicEntryPlugin(context, entry).apply(compiler);
}
return true;

View File

@ -19,8 +19,8 @@ class Entrypoint extends ChunkGroup {
getFiles() {
const files = new Set();
for(const chunk of this.chunks) {
for(const file of chunk.files) {
for (const chunk of this.chunks) {
for (const file of chunk.files) {
files.add(file);
}
}

View File

@ -7,15 +7,16 @@
const DefinePlugin = require("./DefinePlugin");
const needsEnvVarFix = ["8", "9"].indexOf(process.versions.node.split(".")[0]) >= 0 &&
const needsEnvVarFix =
["8", "9"].indexOf(process.versions.node.split(".")[0]) >= 0 &&
process.platform === "win32";
class EnvironmentPlugin {
constructor(...keys) {
if(keys.length === 1 && Array.isArray(keys[0])) {
if (keys.length === 1 && Array.isArray(keys[0])) {
this.keys = keys[0];
this.defaultValues = {};
} else if(keys.length === 1 && keys[0] && typeof keys[0] === "object") {
} else if (keys.length === 1 && keys[0] && typeof keys[0] === "object") {
this.keys = Object.keys(keys[0]);
this.defaultValues = keys[0];
} else {
@ -31,16 +32,21 @@ class EnvironmentPlugin {
// affecting Node 8 & 9 by performing an OS-level
// operation that always succeeds before reading
// environment variables:
if(needsEnvVarFix) require("os").cpus();
if (needsEnvVarFix) require("os").cpus();
const value = process.env[key] !== undefined ? process.env[key] : this.defaultValues[key];
const value =
process.env[key] !== undefined
? process.env[key]
: this.defaultValues[key];
if(value === undefined) {
compiler.hooks.thisCompilation.tap("EnvironmentPlugin", (compilation) => {
if (value === undefined) {
compiler.hooks.thisCompilation.tap("EnvironmentPlugin", compilation => {
const error = new Error(
`EnvironmentPlugin - ${key} environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example."
`EnvironmentPlugin - ${
key
} environment variable is undefined.\n\n` +
"You can pass an object with default values to suppress this warning.\n" +
"See https://webpack.js.org/plugins/environment-plugin for example."
);
error.name = "EnvVariableNotDefinedError";
@ -48,7 +54,8 @@ class EnvironmentPlugin {
});
}
defs[`process.env.${key}`] = typeof value === "undefined" ? "undefined" : JSON.stringify(value);
defs[`process.env.${key}`] =
typeof value === "undefined" ? "undefined" : JSON.stringify(value);
return defs;
}, {});

View File

@ -10,26 +10,33 @@ const webpackOptionsFlag = "WEBPACK_OPTIONS";
exports.cutOffByFlag = (stack, flag) => {
stack = stack.split("\n");
for(let i = 0; i < stack.length; i++)
if(stack[i].includes(flag))
stack.length = i;
for (let i = 0; i < stack.length; i++)
if (stack[i].includes(flag)) stack.length = i;
return stack.join("\n");
};
exports.cutOffLoaderExecution = (stack) => exports.cutOffByFlag(stack, loaderFlag);
exports.cutOffLoaderExecution = stack =>
exports.cutOffByFlag(stack, loaderFlag);
exports.cutOffWebpackOptinos = (stack) => exports.cutOffByFlag(stack, webpackOptionsFlag);
exports.cutOffWebpackOptinos = stack =>
exports.cutOffByFlag(stack, webpackOptionsFlag);
exports.cutOffMultilineMessage = (stack, message) => {
stack = stack.split("\n");
message = message.split("\n");
return stack.reduce((acc, line, idx) => line.includes(message[idx]) ? acc : acc.concat(line), []).join("\n");
return stack
.reduce(
(acc, line, idx) =>
line.includes(message[idx]) ? acc : acc.concat(line),
[]
)
.join("\n");
};
exports.cutOffMessage = (stack, message) => {
const nextLine = stack.indexOf("\n");
if(nextLine === -1) {
if (nextLine === -1) {
return stack === message ? "" : stack;
} else {
const firstLine = stack.substr(0, nextLine);

View File

@ -14,7 +14,7 @@ class EvalDevToolModulePlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("EvalDevToolModulePlugin", (compilation) => {
compiler.hooks.compilation.tap("EvalDevToolModulePlugin", compilation => {
new EvalDevToolModuleTemplatePlugin({
sourceUrlComment: this.sourceUrlComment,
moduleFilenameTemplate: this.moduleFilenameTemplate,

View File

@ -11,24 +11,45 @@ const cache = new WeakMap();
class EvalDevToolModuleTemplatePlugin {
constructor(options) {
this.sourceUrlComment = options.sourceUrlComment || "\n//# sourceURL=[url]";
this.moduleFilenameTemplate = options.moduleFilenameTemplate || "webpack://[namespace]/[resourcePath]?[loaders]";
this.moduleFilenameTemplate =
options.moduleFilenameTemplate ||
"webpack://[namespace]/[resourcePath]?[loaders]";
this.namespace = options.namespace || "";
}
apply(moduleTemplate) {
moduleTemplate.hooks.module.tap("EvalDevToolModuleTemplatePlugin", (source, module) => {
const cacheEntry = cache.get(source);
if(cacheEntry !== undefined) return cacheEntry;
const content = source.source();
const str = ModuleFilenameHelpers.createFilename(module, {
moduleFilenameTemplate: this.moduleFilenameTemplate,
namespace: this.namespace
}, moduleTemplate.runtimeTemplate.requestShortener);
const footer = "\n" + this.sourceUrlComment.replace(/\[url\]/g, encodeURI(str).replace(/%2F/g, "/").replace(/%20/g, "_").replace(/%5E/g, "^").replace(/%5C/g, "\\").replace(/^\//, ""));
const result = new RawSource(`eval(${JSON.stringify(content + footer)});`);
cache.set(source, result);
return result;
});
moduleTemplate.hooks.module.tap(
"EvalDevToolModuleTemplatePlugin",
(source, module) => {
const cacheEntry = cache.get(source);
if (cacheEntry !== undefined) return cacheEntry;
const content = source.source();
const str = ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: this.moduleFilenameTemplate,
namespace: this.namespace
},
moduleTemplate.runtimeTemplate.requestShortener
);
const footer =
"\n" +
this.sourceUrlComment.replace(
/\[url\]/g,
encodeURI(str)
.replace(/%2F/g, "/")
.replace(/%20/g, "_")
.replace(/%5E/g, "^")
.replace(/%5C/g, "\\")
.replace(/^\//, "")
);
const result = new RawSource(
`eval(${JSON.stringify(content + footer)});`
);
cache.set(source, result);
return result;
}
);
moduleTemplate.hooks.hash.tap("EvalDevToolModuleTemplatePlugin", hash => {
hash.update("EvalDevToolModuleTemplatePlugin");
hash.update("2");

View File

@ -10,8 +10,11 @@ const ModuleFilenameHelpers = require("./ModuleFilenameHelpers");
class EvalSourceMapDevToolModuleTemplatePlugin {
constructor(compilation, options) {
this.compilation = compilation;
this.sourceMapComment = options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]";
this.moduleFilenameTemplate = options.moduleFilenameTemplate || "webpack://[namespace]/[resource-path]?[hash]";
this.sourceMapComment =
options.append || "//# sourceURL=[module]\n//# sourceMappingURL=[url]";
this.moduleFilenameTemplate =
options.moduleFilenameTemplate ||
"webpack://[namespace]/[resource-path]?[hash]";
this.namespace = options.namespace || "";
this.options = options;
}
@ -19,61 +22,84 @@ class EvalSourceMapDevToolModuleTemplatePlugin {
apply(moduleTemplate) {
const self = this;
const options = this.options;
const matchModule = ModuleFilenameHelpers.matchObject.bind(ModuleFilenameHelpers, options);
moduleTemplate.hooks.module.tap("EvalSourceMapDevToolModuleTemplatePlugin", (source, module) => {
if(source.__EvalSourceMapDevToolData)
const matchModule = ModuleFilenameHelpers.matchObject.bind(
ModuleFilenameHelpers,
options
);
moduleTemplate.hooks.module.tap(
"EvalSourceMapDevToolModuleTemplatePlugin",
(source, module) => {
if (source.__EvalSourceMapDevToolData)
return source.__EvalSourceMapDevToolData;
if (!matchModule(module.resource)) {
return source;
}
let sourceMap;
let content;
if (source.sourceAndMap) {
const sourceAndMap = source.sourceAndMap(options);
sourceMap = sourceAndMap.map;
content = sourceAndMap.source;
} else {
sourceMap = source.map(options);
content = source.source();
}
if (!sourceMap) {
return source;
}
// Clone (flat) the sourcemap to ensure that the mutations below do not persist.
sourceMap = Object.keys(sourceMap).reduce((obj, key) => {
obj[key] = sourceMap[key];
return obj;
}, {});
const modules = sourceMap.sources.map(source => {
const module = self.compilation.findModule(source);
return module || source;
});
let moduleFilenames = modules.map(module => {
return ModuleFilenameHelpers.createFilename(
module,
{
moduleFilenameTemplate: self.moduleFilenameTemplate,
namespace: self.namespace
},
moduleTemplate.runtimeTemplate.requestShortener
);
});
moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(
moduleFilenames,
(filename, i, n) => {
for (let j = 0; j < n; j++) filename += "*";
return filename;
}
);
sourceMap.sources = moduleFilenames;
sourceMap.sourceRoot = options.sourceRoot || "";
sourceMap.file = `${module.id}.js`;
const footer =
self.sourceMapComment.replace(
/\[url\]/g,
`data:application/json;charset=utf-8;base64,${Buffer.from(
JSON.stringify(sourceMap),
"utf8"
).toString("base64")}`
) + `\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug
source.__EvalSourceMapDevToolData = new RawSource(
`eval(${JSON.stringify(content + footer)});`
);
return source.__EvalSourceMapDevToolData;
if(!matchModule(module.resource)) {
return source;
}
let sourceMap;
let content;
if(source.sourceAndMap) {
const sourceAndMap = source.sourceAndMap(options);
sourceMap = sourceAndMap.map;
content = sourceAndMap.source;
} else {
sourceMap = source.map(options);
content = source.source();
);
moduleTemplate.hooks.hash.tap(
"EvalSourceMapDevToolModuleTemplatePlugin",
hash => {
hash.update("eval-source-map");
hash.update("2");
}
if(!sourceMap) {
return source;
}
// Clone (flat) the sourcemap to ensure that the mutations below do not persist.
sourceMap = Object.keys(sourceMap).reduce((obj, key) => {
obj[key] = sourceMap[key];
return obj;
}, {});
const modules = sourceMap.sources.map(source => {
const module = self.compilation.findModule(source);
return module || source;
});
let moduleFilenames = modules.map(module => {
return ModuleFilenameHelpers.createFilename(module, {
moduleFilenameTemplate: self.moduleFilenameTemplate,
namespace: self.namespace
}, moduleTemplate.runtimeTemplate.requestShortener);
});
moduleFilenames = ModuleFilenameHelpers.replaceDuplicates(moduleFilenames, (filename, i, n) => {
for(let j = 0; j < n; j++)
filename += "*";
return filename;
});
sourceMap.sources = moduleFilenames;
sourceMap.sourceRoot = options.sourceRoot || "";
sourceMap.file = `${module.id}.js`;
const footer = self.sourceMapComment.replace(/\[url\]/g, `data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(sourceMap), "utf8").toString("base64")}`) +
`\n//# sourceURL=webpack-internal:///${module.id}\n`; // workaround for chrome bug
source.__EvalSourceMapDevToolData = new RawSource(`eval(${JSON.stringify(content + footer)});`);
return source.__EvalSourceMapDevToolData;
});
moduleTemplate.hooks.hash.tap("EvalSourceMapDevToolModuleTemplatePlugin", hash => {
hash.update("eval-source-map");
hash.update("2");
});
);
}
}
module.exports = EvalSourceMapDevToolModuleTemplatePlugin;

View File

@ -9,23 +9,31 @@ const SourceMapDevToolModuleOptionsPlugin = require("./SourceMapDevToolModuleOpt
class EvalSourceMapDevToolPlugin {
constructor(options) {
if(arguments.length > 1)
throw new Error("EvalSourceMapDevToolPlugin only takes one argument (pass an options object)");
if(typeof options === "string") {
if (arguments.length > 1)
throw new Error(
"EvalSourceMapDevToolPlugin only takes one argument (pass an options object)"
);
if (typeof options === "string") {
options = {
append: options
};
}
if(!options) options = {};
if (!options) options = {};
this.options = options;
}
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap("EvalSourceMapDevToolPlugin", (compilation) => {
new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
new EvalSourceMapDevToolModuleTemplatePlugin(compilation, options).apply(compilation.moduleTemplates.javascript);
});
compiler.hooks.compilation.tap(
"EvalSourceMapDevToolPlugin",
compilation => {
new SourceMapDevToolModuleOptionsPlugin(options).apply(compilation);
new EvalSourceMapDevToolModuleTemplatePlugin(
compilation,
options
).apply(compilation.moduleTemplates.javascript);
}
);
}
}

View File

@ -16,18 +16,18 @@ class ExportPropertyMainTemplatePlugin {
}
apply(compilation) {
const {
mainTemplate,
chunkTemplate
} = compilation;
const { mainTemplate, chunkTemplate } = compilation;
const onRenderWithEntry = (source, chunk, hash) => {
const postfix = `${accessorToObjectAccess([].concat(this.property))}`;
return new ConcatSource(source, postfix);
};
for(const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap("ExportPropertyMainTemplatePlugin", onRenderWithEntry);
for (const template of [mainTemplate, chunkTemplate]) {
template.hooks.renderWithEntry.tap(
"ExportPropertyMainTemplatePlugin",
onRenderWithEntry
);
}
mainTemplate.hooks.hash.tap("ExportPropertyMainTemplatePlugin", hash => {

View File

@ -20,36 +20,64 @@ const REPLACEMENT_TYPES = {
class ExtendedAPIPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("ExtendedAPIPlugin", (compilation, {
normalModuleFactory
}) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compiler.hooks.compilation.tap(
"ExtendedAPIPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.requireExtensions.tap("ExtendedAPIPlugin", (source, chunk, hash) => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push("");
buf.push("// __webpack_chunkname__");
buf.push(`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`);
return Template.asString(buf);
});
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true);
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.requireExtensions.tap(
"ExtendedAPIPlugin",
(source, chunk, hash) => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(`${mainTemplate.requireFn}.h = ${JSON.stringify(hash)};`);
buf.push("");
buf.push("// __webpack_chunkname__");
buf.push(
`${mainTemplate.requireFn}.cn = ${JSON.stringify(chunk.name)};`
);
return Template.asString(buf);
}
);
mainTemplate.hooks.globalHash.tap("ExtendedAPIPlugin", () => true);
const handler = (parser, parserOptions) => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression.for(key).tap("ExtendedAPIPlugin", ParserHelpers.toConstantDependencyWithWebpackRequire(parser, REPLACEMENTS[key]));
parser.hooks.evaluateTypeof.for(key).tap("ExtendedAPIPlugin", ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key]));
});
};
const handler = (parser, parserOptions) => {
Object.keys(REPLACEMENTS).forEach(key => {
parser.hooks.expression
.for(key)
.tap(
"ExtendedAPIPlugin",
ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
REPLACEMENTS[key]
)
);
parser.hooks.evaluateTypeof
.for(key)
.tap(
"ExtendedAPIPlugin",
ParserHelpers.evaluateToString(REPLACEMENT_TYPES[key])
);
});
};
normalModuleFactory.hooks.parser.for("javascript/auto").tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/esm").tap("ExtendedAPIPlugin", handler);
});
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("ExtendedAPIPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/esm")
.tap("ExtendedAPIPlugin", handler);
}
);
}
}

View File

@ -48,64 +48,92 @@ class ExternalModule extends Module {
}
getSourceForGlobalVariableExternal(variableName, type) {
if(!Array.isArray(variableName)) {
if (!Array.isArray(variableName)) {
// make it an array as the look up works the same basically
variableName = [variableName];
}
// needed for e.g. window["some"]["thing"]
const objectLookup = variableName.map(r => `[${JSON.stringify(r)}]`).join("");
const objectLookup = variableName
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `(function() { module.exports = ${type}${objectLookup}; }());`;
}
getSourceForCommonJsExternal(moduleAndSpecifiers) {
if(!Array.isArray(moduleAndSpecifiers)) {
return `module.exports = require(${JSON.stringify(moduleAndSpecifiers)});`;
if (!Array.isArray(moduleAndSpecifiers)) {
return `module.exports = require(${JSON.stringify(
moduleAndSpecifiers
)});`;
}
const moduleName = moduleAndSpecifiers[0];
const objectLookup = moduleAndSpecifiers.slice(1).map(r => `[${JSON.stringify(r)}]`).join("");
const objectLookup = moduleAndSpecifiers
.slice(1)
.map(r => `[${JSON.stringify(r)}]`)
.join("");
return `module.exports = require(${moduleName})${objectLookup};`;
}
checkExternalVariable(variableToCheck, request) {
return `if(typeof ${variableToCheck} === 'undefined') {${WebpackMissingModule.moduleCode(request)}}\n`;
return `if(typeof ${
variableToCheck
} === 'undefined') {${WebpackMissingModule.moduleCode(request)}}\n`;
}
getSourceForAmdOrUmdExternal(id, optional, request) {
const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(`${id}`)}__`;
const missingModuleError = optional ? this.checkExternalVariable(externalVariable, request) : "";
const externalVariable = `__WEBPACK_EXTERNAL_MODULE_${Template.toIdentifier(
`${id}`
)}__`;
const missingModuleError = optional
? this.checkExternalVariable(externalVariable, request)
: "";
return `${missingModuleError}module.exports = ${externalVariable};`;
}
getSourceForDefaultCase(optional, request) {
const missingModuleError = optional ? this.checkExternalVariable(request, request) : "";
const missingModuleError = optional
? this.checkExternalVariable(request, request)
: "";
return `${missingModuleError}module.exports = ${request};`;
}
getSourceString(runtime) {
const request = typeof this.request === "object" ? this.request[this.externalType] : this.request;
switch(this.externalType) {
const request =
typeof this.request === "object"
? this.request[this.externalType]
: this.request;
switch (this.externalType) {
case "this":
case "window":
case "self":
return this.getSourceForGlobalVariableExternal(request, this.externalType);
return this.getSourceForGlobalVariableExternal(
request,
this.externalType
);
case "global":
return this.getSourceForGlobalVariableExternal(runtime.outputOptions.globalObject, this.externalType);
return this.getSourceForGlobalVariableExternal(
runtime.outputOptions.globalObject,
this.externalType
);
case "commonjs":
case "commonjs2":
return this.getSourceForCommonJsExternal(request);
case "amd":
case "umd":
case "umd2":
return this.getSourceForAmdOrUmdExternal(this.id, this.optional, request);
return this.getSourceForAmdOrUmdExternal(
this.id,
this.optional,
request
);
default:
return this.getSourceForDefaultCase(this.optional, request);
}
}
getSource(sourceString) {
if(this.useSourceMap) {
if (this.useSourceMap) {
return new OriginalSource(sourceString, this.identifier());
}
@ -113,9 +141,7 @@ class ExternalModule extends Module {
}
source(dependencyTemplates, runtime) {
return this.getSource(
this.getSourceString(runtime)
);
return this.getSource(this.getSourceString(runtime));
}
size() {

View File

@ -14,83 +14,97 @@ class ExternalModuleFactoryPlugin {
apply(normalModuleFactory) {
const globalType = this.type;
normalModuleFactory.hooks.factory.tap("ExternalModuleFactoryPlugin", factory => (data, callback) => {
const context = data.context;
const dependency = data.dependencies[0];
normalModuleFactory.hooks.factory.tap(
"ExternalModuleFactoryPlugin",
factory => (data, callback) => {
const context = data.context;
const dependency = data.dependencies[0];
const handleExternal = (value, type, callback) => {
if(typeof type === "function") {
callback = type;
type = undefined;
}
if(value === false) return factory(data, callback);
if(value === true) value = dependency.request;
if(typeof type === "undefined" && /^[a-z0-9]+ /.test(value)) {
const idx = value.indexOf(" ");
type = value.substr(0, idx);
value = value.substr(idx + 1);
}
callback(null, new ExternalModule(value, type || globalType, dependency.request));
return true;
};
const handleExternals = (externals, callback) => {
if(typeof externals === "string") {
if(externals === dependency.request) {
return handleExternal(dependency.request, callback);
const handleExternal = (value, type, callback) => {
if (typeof type === "function") {
callback = type;
type = undefined;
}
} else if(Array.isArray(externals)) {
let i = 0;
const next = () => {
let asyncFlag;
const handleExternalsAndCallback = (err, module) => {
if(err) return callback(err);
if(!module) {
if(asyncFlag) {
asyncFlag = false;
return;
if (value === false) return factory(data, callback);
if (value === true) value = dependency.request;
if (typeof type === "undefined" && /^[a-z0-9]+ /.test(value)) {
const idx = value.indexOf(" ");
type = value.substr(0, idx);
value = value.substr(idx + 1);
}
callback(
null,
new ExternalModule(value, type || globalType, dependency.request)
);
return true;
};
const handleExternals = (externals, callback) => {
if (typeof externals === "string") {
if (externals === dependency.request) {
return handleExternal(dependency.request, callback);
}
} else if (Array.isArray(externals)) {
let i = 0;
const next = () => {
let asyncFlag;
const handleExternalsAndCallback = (err, module) => {
if (err) return callback(err);
if (!module) {
if (asyncFlag) {
asyncFlag = false;
return;
}
return next();
}
return next();
}
callback(null, module);
callback(null, module);
};
do {
asyncFlag = true;
if (i >= externals.length) return callback();
handleExternals(externals[i++], handleExternalsAndCallback);
} while (!asyncFlag); // eslint-disable-line keyword-spacing
asyncFlag = false;
};
do {
asyncFlag = true;
if(i >= externals.length) return callback();
handleExternals(externals[i++], handleExternalsAndCallback);
} while (!asyncFlag); // eslint-disable-line keyword-spacing
asyncFlag = false;
};
next();
return;
} else if(externals instanceof RegExp) {
if(externals.test(dependency.request)) {
return handleExternal(dependency.request, callback);
}
} else if(typeof externals === "function") {
externals.call(null, context, dependency.request, (err, value, type) => {
if(err) return callback(err);
if(typeof value !== "undefined") {
handleExternal(value, type, callback);
} else {
callback();
next();
return;
} else if (externals instanceof RegExp) {
if (externals.test(dependency.request)) {
return handleExternal(dependency.request, callback);
}
});
return;
} else if(typeof externals === "object" && Object.prototype.hasOwnProperty.call(externals, dependency.request)) {
return handleExternal(externals[dependency.request], callback);
}
callback();
};
} else if (typeof externals === "function") {
externals.call(
null,
context,
dependency.request,
(err, value, type) => {
if (err) return callback(err);
if (typeof value !== "undefined") {
handleExternal(value, type, callback);
} else {
callback();
}
}
);
return;
} else if (
typeof externals === "object" &&
Object.prototype.hasOwnProperty.call(externals, dependency.request)
) {
return handleExternal(externals[dependency.request], callback);
}
callback();
};
handleExternals(this.externals, (err, module) => {
if(err) return callback(err);
if(!module) return handleExternal(false, callback);
return callback(null, module);
});
});
handleExternals(this.externals, (err, module) => {
if (err) return callback(err);
if (!module) return handleExternal(false, callback);
return callback(null, module);
});
}
);
}
}
module.exports = ExternalModuleFactoryPlugin;

View File

@ -12,10 +12,10 @@ class ExternalsPlugin {
this.externals = externals;
}
apply(compiler) {
compiler.hooks.compile.tap("ExternalsPlugin", ({
normalModuleFactory
}) => {
new ExternalModuleFactoryPlugin(this.type, this.externals).apply(normalModuleFactory);
compiler.hooks.compile.tap("ExternalsPlugin", ({ normalModuleFactory }) => {
new ExternalModuleFactoryPlugin(this.type, this.externals).apply(
normalModuleFactory
);
});
}
}

View File

@ -8,8 +8,8 @@ const Queue = require("./util/Queue");
const addToSet = (a, b) => {
let changed = false;
for(const item of b) {
if(!a.has(item)) {
for (const item of b) {
if (!a.has(item)) {
a.add(item);
changed = true;
}
@ -18,113 +18,128 @@ const addToSet = (a, b) => {
};
class FlagDependencyExportsPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyExportsPlugin", (compilation) => {
compilation.hooks.finishModules.tap("FlagDependencyExportsPlugin", (modules) => {
const dependencies = new Map();
compiler.hooks.compilation.tap(
"FlagDependencyExportsPlugin",
compilation => {
compilation.hooks.finishModules.tap(
"FlagDependencyExportsPlugin",
modules => {
const dependencies = new Map();
const queue = new Queue();
const queue = new Queue();
let module;
let moduleWithExports;
let moduleProvidedExports;
let module;
let moduleWithExports;
let moduleProvidedExports;
const processDependenciesBlock = depBlock => {
for(const dep of depBlock.dependencies) {
if(processDependency(dep))
return true;
}
for(const variable of depBlock.variables) {
for(const dep of variable.dependencies) {
if(processDependency(dep))
const processDependenciesBlock = depBlock => {
for (const dep of depBlock.dependencies) {
if (processDependency(dep)) return true;
}
for (const variable of depBlock.variables) {
for (const dep of variable.dependencies) {
if (processDependency(dep)) return true;
}
}
for (const block of depBlock.blocks) {
if (processDependenciesBlock(block)) return true;
}
return false;
};
const processDependency = dep => {
const exportDesc = dep.getExports && dep.getExports();
if (!exportDesc) return;
moduleWithExports = true;
const exports = exportDesc.exports;
// break early if it's only in the worst state
if (module.buildMeta.providedExports === true) {
return true;
}
}
for(const block of depBlock.blocks) {
if(processDependenciesBlock(block))
return true;
}
return false;
};
}
// break if it should move to the worst state
if (exports === true) {
module.buildMeta.providedExports = true;
notifyDependencies();
return true;
}
// merge in new exports
if (Array.isArray(exports)) {
if (addToSet(moduleProvidedExports, exports)) {
notifyDependencies();
}
}
// store dependencies
const exportDeps = exportDesc.dependencies;
if (exportDeps) {
for (const exportDependency of exportDeps) {
// add dependency for this module
const set = dependencies.get(exportDependency);
if (set === undefined) {
dependencies.set(exportDependency, new Set([module]));
} else {
set.add(module);
}
}
}
return false;
};
const processDependency = dep => {
const exportDesc = dep.getExports && dep.getExports();
if(!exportDesc) return;
moduleWithExports = true;
const exports = exportDesc.exports;
// break early if it's only in the worst state
if(module.buildMeta.providedExports === true) {
return true;
}
// break if it should move to the worst state
if(exports === true) {
module.buildMeta.providedExports = true;
notifyDependencies();
return true;
}
// merge in new exports
if(Array.isArray(exports)) {
if(addToSet(moduleProvidedExports, exports)) {
notifyDependencies();
const notifyDependencies = () => {
const deps = dependencies.get(module);
if (deps !== undefined) {
for (const dep of deps) {
queue.enqueue(dep);
}
}
};
// Start with all modules without provided exports
for (const module of modules) {
if (!module.buildMeta.providedExports) {
queue.enqueue(module);
}
}
}
// store dependencies
const exportDeps = exportDesc.dependencies;
if(exportDeps) {
for(const exportDependency of exportDeps) {
// add dependency for this module
const set = dependencies.get(exportDependency);
if(set === undefined) {
dependencies.set(exportDependency, new Set([module]));
} else {
set.add(module);
while (queue.length > 0) {
module = queue.dequeue();
if (module.buildMeta.providedExports !== true) {
moduleWithExports =
module.buildMeta && module.buildMeta.exportsType;
moduleProvidedExports = Array.isArray(
module.buildMeta.providedExports
)
? new Set(module.buildMeta.providedExports)
: new Set();
processDependenciesBlock(module);
if (!moduleWithExports) {
module.buildMeta.providedExports = true;
notifyDependencies();
} else if (module.buildMeta.providedExports !== true) {
module.buildMeta.providedExports = Array.from(
moduleProvidedExports
);
}
}
}
}
return false;
};
const notifyDependencies = () => {
const deps = dependencies.get(module);
if(deps !== undefined) {
for(const dep of deps) {
queue.enqueue(dep);
}
);
const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap(
"FlagDependencyExportsPlugin",
module => {
providedExportsCache.set(module, module.buildMeta.providedExports);
}
};
// Start with all modules without provided exports
for(const module of modules) {
if(!module.buildMeta.providedExports) {
queue.enqueue(module);
);
compilation.hooks.finishRebuildingModule.tap(
"FlagDependencyExportsPlugin",
module => {
module.buildMeta.providedExports = providedExportsCache.get(module);
}
}
while(queue.length > 0) {
module = queue.dequeue();
if(module.buildMeta.providedExports !== true) {
moduleWithExports = module.buildMeta && module.buildMeta.exportsType;
moduleProvidedExports = Array.isArray(module.buildMeta.providedExports) ? new Set(module.buildMeta.providedExports) : new Set();
processDependenciesBlock(module);
if(!moduleWithExports) {
module.buildMeta.providedExports = true;
notifyDependencies();
} else if(module.buildMeta.providedExports !== true) {
module.buildMeta.providedExports = Array.from(moduleProvidedExports);
}
}
}
});
const providedExportsCache = new WeakMap();
compilation.hooks.rebuildModule.tap("FlagDependencyExportsPlugin", module => {
providedExportsCache.set(module, module.buildMeta.providedExports);
});
compilation.hooks.finishRebuildingModule.tap("FlagDependencyExportsPlugin", module => {
module.buildMeta.providedExports = providedExportsCache.get(module);
});
});
);
}
);
}
}

View File

@ -5,92 +5,99 @@
"use strict";
const addToSet = (a, b) => {
for(const item of b) {
if(!a.includes(item))
a.push(item);
for (const item of b) {
if (!a.includes(item)) a.push(item);
}
return a;
};
const isSubset = (biggerSet, subset) => {
if(biggerSet === true) return true;
if(subset === true) return false;
if (biggerSet === true) return true;
if (subset === true) return false;
return subset.every(item => biggerSet.indexOf(item) >= 0);
};
class FlagDependencyUsagePlugin {
apply(compiler) {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", (compilation) => {
compilation.hooks.optimizeModulesAdvanced.tap("FlagDependencyUsagePlugin", (modules) => {
compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => {
compilation.hooks.optimizeModulesAdvanced.tap(
"FlagDependencyUsagePlugin",
modules => {
const processModule = (module, usedExports) => {
module.used = true;
if (module.usedExports === true) return;
else if (usedExports === true) module.usedExports = true;
else if (Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(
module.usedExports || [],
usedExports
);
if (module.usedExports.length === old) return;
} else if (Array.isArray(module.usedExports)) return;
else module.usedExports = false;
const processModule = (module, usedExports) => {
module.used = true;
if(module.usedExports === true)
return;
else if(usedExports === true)
module.usedExports = true;
else if(Array.isArray(usedExports)) {
const old = module.usedExports ? module.usedExports.length : -1;
module.usedExports = addToSet(module.usedExports || [], usedExports);
if(module.usedExports.length === old)
return;
} else if(Array.isArray(module.usedExports))
return;
else
module.usedExports = false;
// for a module without side effects we stop tracking usage here when no export is used
// This module won't be evaluated in this case
if (module.factoryMeta.sideEffectFree) {
if (module.usedExports === false) return;
if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
return;
}
// for a module without side effects we stop tracking usage here when no export is used
// This module won't be evaluated in this case
if(module.factoryMeta.sideEffectFree) {
if(module.usedExports === false) return;
if(Array.isArray(module.usedExports) && module.usedExports.length === 0) return;
}
queue.push([module, module.usedExports]);
};
queue.push([module, module.usedExports]);
};
const processDependenciesBlock = (depBlock, usedExports) => {
for(const dep of depBlock.dependencies) {
processDependency(dep);
}
for(const variable of depBlock.variables) {
for(const dep of variable.dependencies) {
const processDependenciesBlock = (depBlock, usedExports) => {
for (const dep of depBlock.dependencies) {
processDependency(dep);
}
}
for(const block of depBlock.blocks) {
queue.push([block, usedExports]);
}
};
for (const variable of depBlock.variables) {
for (const dep of variable.dependencies) {
processDependency(dep);
}
}
for (const block of depBlock.blocks) {
queue.push([block, usedExports]);
}
};
const processDependency = dep => {
const reference = dep.getReference && dep.getReference();
if(!reference) return;
const module = reference.module;
const importedNames = reference.importedNames;
const oldUsed = module.used;
const oldUsedExports = module.usedExports;
if(!oldUsed || (importedNames && (!oldUsedExports || !isSubset(oldUsedExports, importedNames)))) {
processModule(module, importedNames);
const processDependency = dep => {
const reference = dep.getReference && dep.getReference();
if (!reference) return;
const module = reference.module;
const importedNames = reference.importedNames;
const oldUsed = module.used;
const oldUsedExports = module.usedExports;
if (
!oldUsed ||
(importedNames &&
(!oldUsedExports || !isSubset(oldUsedExports, importedNames)))
) {
processModule(module, importedNames);
}
};
for (const module of modules) {
module.used = false;
}
};
for(const module of modules) {
module.used = false;
}
const queue = [];
for (const chunk of compilation.chunks) {
if (chunk.entryModule) {
processModule(chunk.entryModule, true);
}
}
const queue = [];
for(const chunk of compilation.chunks) {
if(chunk.entryModule) {
processModule(chunk.entryModule, true);
while (queue.length) {
const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]);
}
}
while(queue.length) {
const queueItem = queue.pop();
processDependenciesBlock(queueItem[0], queueItem[1]);
}
});
);
});
}
}

View File

@ -10,20 +10,26 @@ class FlagInitialModulesAsUsedPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("FlagInitialModulesAsUsedPlugin", (compilation) => {
compilation.hooks.afterOptimizeChunks.tap("FlagInitialModulesAsUsedPlugin", (chunks) => {
for(const chunk of chunks) {
if(!chunk.isOnlyInitial()) {
return;
compiler.hooks.compilation.tap(
"FlagInitialModulesAsUsedPlugin",
compilation => {
compilation.hooks.afterOptimizeChunks.tap(
"FlagInitialModulesAsUsedPlugin",
chunks => {
for (const chunk of chunks) {
if (!chunk.isOnlyInitial()) {
return;
}
for (const module of chunk.modulesIterable) {
module.used = true;
module.usedExports = true;
module.addReason(null, null, this.explanation);
}
}
}
for(const module of chunk.modulesIterable) {
module.used = true;
module.usedExports = true;
module.addReason(null, null, this.explanation);
}
}
});
});
);
}
);
}
}

View File

@ -12,8 +12,10 @@ class FunctionModulePlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("FunctionModulePlugin", (compilation) => {
new FunctionModuleTemplatePlugin().apply(compilation.moduleTemplates.javascript);
compiler.hooks.compilation.tap("FunctionModulePlugin", compilation => {
new FunctionModuleTemplatePlugin().apply(
compilation.moduleTemplates.javascript
);
});
}
}

View File

@ -9,62 +9,85 @@ const Template = require("./Template");
class FunctionModuleTemplatePlugin {
apply(moduleTemplate) {
moduleTemplate.hooks.render.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => {
const source = new ConcatSource();
const args = [module.moduleArgument];
// TODO remove HACK checking type for javascript
if(module.type && module.type.startsWith("javascript")) {
args.push(module.exportsArgument);
if(module.hasDependencies(d => d.requireWebpackRequire !== false)) {
args.push("__webpack_require__");
}
} else if(module.type && module.type.startsWith("json")) {
// no additional arguments needed
} else {
args.push(module.exportsArgument, "__webpack_require__");
}
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
if(module.buildInfo.strict) source.add("\"use strict\";\n");
source.add(moduleSource);
source.add("\n\n/***/ })");
return source;
});
moduleTemplate.hooks.package.tap("FunctionModuleTemplatePlugin", (moduleSource, module) => {
if(moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
moduleTemplate.hooks.render.tap(
"FunctionModuleTemplatePlugin",
(moduleSource, module) => {
const source = new ConcatSource();
const req = module.readableIdentifier(moduleTemplate.runtimeTemplate.requestShortener);
source.add("/*!****" + req.replace(/./g, "*") + "****!*\\\n");
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
if(Array.isArray(module.buildMeta.providedExports) && module.buildMeta.providedExports.length === 0)
source.add(Template.toComment("no exports provided") + "\n");
else if(Array.isArray(module.buildMeta.providedExports))
source.add(Template.toComment("exports provided: " + module.buildMeta.providedExports.join(", ")) + "\n");
else if(module.buildMeta.providedExports)
source.add(Template.toComment("no static exports found") + "\n");
if(Array.isArray(module.usedExports) && module.usedExports.length === 0)
source.add(Template.toComment("no exports used") + "\n");
else if(Array.isArray(module.usedExports))
source.add(Template.toComment("exports used: " + module.usedExports.join(", ")) + "\n");
else if(module.usedExports)
source.add(Template.toComment("all exports used") + "\n");
if(module.optimizationBailout) {
for(const text of module.optimizationBailout) {
let code;
if(typeof text === "function") {
code = text(moduleTemplate.runtimeTemplate.requestShortener);
} else {
code = text;
}
source.add(Template.toComment(`${code}`) + "\n");
const args = [module.moduleArgument];
// TODO remove HACK checking type for javascript
if (module.type && module.type.startsWith("javascript")) {
args.push(module.exportsArgument);
if (module.hasDependencies(d => d.requireWebpackRequire !== false)) {
args.push("__webpack_require__");
}
} else if (module.type && module.type.startsWith("json")) {
// no additional arguments needed
} else {
args.push(module.exportsArgument, "__webpack_require__");
}
source.add("/***/ (function(" + args.join(", ") + ") {\n\n");
if (module.buildInfo.strict) source.add('"use strict";\n');
source.add(moduleSource);
source.add("\n\n/***/ })");
return source;
}
return moduleSource;
});
);
moduleTemplate.hooks.package.tap(
"FunctionModuleTemplatePlugin",
(moduleSource, module) => {
if (moduleTemplate.runtimeTemplate.outputOptions.pathinfo) {
const source = new ConcatSource();
const req = module.readableIdentifier(
moduleTemplate.runtimeTemplate.requestShortener
);
source.add("/*!****" + req.replace(/./g, "*") + "****!*\\\n");
source.add(" !*** " + req.replace(/\*\//g, "*_/") + " ***!\n");
source.add(" \\****" + req.replace(/./g, "*") + "****/\n");
if (
Array.isArray(module.buildMeta.providedExports) &&
module.buildMeta.providedExports.length === 0
)
source.add(Template.toComment("no exports provided") + "\n");
else if (Array.isArray(module.buildMeta.providedExports))
source.add(
Template.toComment(
"exports provided: " +
module.buildMeta.providedExports.join(", ")
) + "\n"
);
else if (module.buildMeta.providedExports)
source.add(Template.toComment("no static exports found") + "\n");
if (
Array.isArray(module.usedExports) &&
module.usedExports.length === 0
)
source.add(Template.toComment("no exports used") + "\n");
else if (Array.isArray(module.usedExports))
source.add(
Template.toComment(
"exports used: " + module.usedExports.join(", ")
) + "\n"
);
else if (module.usedExports)
source.add(Template.toComment("all exports used") + "\n");
if (module.optimizationBailout) {
for (const text of module.optimizationBailout) {
let code;
if (typeof text === "function") {
code = text(moduleTemplate.runtimeTemplate.requestShortener);
} else {
code = text;
}
source.add(Template.toComment(`${code}`) + "\n");
}
}
source.add(moduleSource);
return source;
}
return moduleSource;
}
);
moduleTemplate.hooks.hash.tap("FunctionModuleTemplatePlugin", hash => {
hash.update("FunctionModuleTemplatePlugin");

View File

@ -1,17 +1,17 @@
exports.connectChunkGroupAndChunk = (chunkGroup, chunk) => {
if(chunkGroup.pushChunk(chunk)) {
if (chunkGroup.pushChunk(chunk)) {
chunk.addGroup(chunkGroup);
}
};
exports.connectChunkGroupParentAndChild = (parent, child) => {
if(parent.addChild(child)) {
if (parent.addChild(child)) {
child.addParent(parent);
}
};
exports.connectChunkAndModule = (chunk, module) => {
if(module.addChunk(chunk)) {
if (module.addChunk(chunk)) {
chunk.addModule(module);
}
};
@ -22,7 +22,7 @@ exports.disconnectChunkAndModule = (chunk, module) => {
};
exports.connectDependenciesBlockAndChunkGroup = (depBlock, chunkGroup) => {
if(chunkGroup.addBlock(depBlock)) {
if (chunkGroup.addBlock(depBlock)) {
depBlock.chunkGroup = chunkGroup;
}
};

View File

@ -12,35 +12,40 @@ class HashedModuleIdsPlugin {
constructor(options) {
validateOptions(schema, options || {}, "Hashed Module Ids Plugin");
this.options = Object.assign({
context: null,
hashFunction: "md4",
hashDigest: "base64",
hashDigestLength: 4
}, options);
this.options = Object.assign(
{
context: null,
hashFunction: "md4",
hashDigest: "base64",
hashDigestLength: 4
},
options
);
}
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap("HashedModuleIdsPlugin", (compilation) => {
compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => {
const usedIds = new Set();
compilation.hooks.beforeModuleIds.tap("HashedModuleIdsPlugin", (modules) => {
for(const module of modules) {
if(module.id === null && module.libIdent) {
const id = module.libIdent({
context: this.options.context || compiler.options.context
});
const hash = createHash(options.hashFunction);
hash.update(id);
const hashId = hash.digest(options.hashDigest);
let len = options.hashDigestLength;
while(usedIds.has(hashId.substr(0, len)))
len++;
module.id = hashId.substr(0, len);
usedIds.add(module.id);
compilation.hooks.beforeModuleIds.tap(
"HashedModuleIdsPlugin",
modules => {
for (const module of modules) {
if (module.id === null && module.libIdent) {
const id = module.libIdent({
context: this.options.context || compiler.options.context
});
const hash = createHash(options.hashFunction);
hash.update(id);
const hashId = hash.digest(options.hashDigest);
let len = options.hashDigestLength;
while (usedIds.has(hashId.substr(0, len))) len++;
module.id = hashId.substr(0, len);
usedIds.add(module.id);
}
}
}
});
);
});
}
}

View File

@ -4,7 +4,6 @@
*/
/*global $hash$ $requestTimeout$ installedModules $require$ hotDownloadManifest hotDownloadUpdateChunk hotDisposeChunk modules */
module.exports = function() {
var hotApplyOnUpdate = true;
var hotCurrentHash = $hash$; // eslint-disable-line no-unused-vars
var hotRequestTimeout = $requestTimeout$;
@ -13,22 +12,27 @@ module.exports = function() {
var hotCurrentParents = []; // eslint-disable-line no-unused-vars
var hotCurrentParentsTemp = []; // eslint-disable-line no-unused-vars
function hotCreateRequire(moduleId) { // eslint-disable-line no-unused-vars
function hotCreateRequire(moduleId) {
// eslint-disable-line no-unused-vars
var me = installedModules[moduleId];
if(!me) return $require$;
if (!me) return $require$;
var fn = function(request) {
if(me.hot.active) {
if(installedModules[request]) {
if(!installedModules[request].parents.includes(moduleId))
if (me.hot.active) {
if (installedModules[request]) {
if (!installedModules[request].parents.includes(moduleId))
installedModules[request].parents.push(moduleId);
} else {
hotCurrentParents = [moduleId];
hotCurrentChildModule = request;
}
if(!me.children.includes(request))
me.children.push(request);
if (!me.children.includes(request)) me.children.push(request);
} else {
console.warn("[HMR] unexpected require(" + request + ") from disposed module " + moduleId);
console.warn(
"[HMR] unexpected require(" +
request +
") from disposed module " +
moduleId
);
hotCurrentParents = [];
}
return $require$(request);
@ -45,14 +49,16 @@ module.exports = function() {
}
};
};
for(var name in $require$) {
if(Object.prototype.hasOwnProperty.call($require$, name) && name !== "e") {
for (var name in $require$) {
if (
Object.prototype.hasOwnProperty.call($require$, name) &&
name !== "e"
) {
Object.defineProperty(fn, name, ObjectFactory(name));
}
}
fn.e = function(chunkId) {
if(hotStatus === "ready")
hotSetStatus("prepare");
if (hotStatus === "ready") hotSetStatus("prepare");
hotChunksLoading++;
return $require$.e(chunkId).then(finishChunkLoading, function(err) {
finishChunkLoading();
@ -61,11 +67,11 @@ module.exports = function() {
function finishChunkLoading() {
hotChunksLoading--;
if(hotStatus === "prepare") {
if(!hotWaitingFilesMap[chunkId]) {
if (hotStatus === "prepare") {
if (!hotWaitingFilesMap[chunkId]) {
hotEnsureUpdateChunk(chunkId);
}
if(hotChunksLoading === 0 && hotWaitingFiles === 0) {
if (hotChunksLoading === 0 && hotWaitingFiles === 0) {
hotUpdateDownloaded();
}
}
@ -74,7 +80,8 @@ module.exports = function() {
return fn;
}
function hotCreateModule(moduleId) { // eslint-disable-line no-unused-vars
function hotCreateModule(moduleId) {
// eslint-disable-line no-unused-vars
var hot = {
// private stuff
_acceptedDependencies: {},
@ -87,24 +94,19 @@ module.exports = function() {
// Module API
active: true,
accept: function(dep, callback) {
if(typeof dep === "undefined")
hot._selfAccepted = true;
else if(typeof dep === "function")
hot._selfAccepted = dep;
else if(typeof dep === "object")
for(var i = 0; i < dep.length; i++)
if (typeof dep === "undefined") hot._selfAccepted = true;
else if (typeof dep === "function") hot._selfAccepted = dep;
else if (typeof dep === "object")
for (var i = 0; i < dep.length; i++)
hot._acceptedDependencies[dep[i]] = callback || function() {};
else
hot._acceptedDependencies[dep] = callback || function() {};
else hot._acceptedDependencies[dep] = callback || function() {};
},
decline: function(dep) {
if(typeof dep === "undefined")
hot._selfDeclined = true;
else if(typeof dep === "object")
for(var i = 0; i < dep.length; i++)
if (typeof dep === "undefined") hot._selfDeclined = true;
else if (typeof dep === "object")
for (var i = 0; i < dep.length; i++)
hot._declinedDependencies[dep[i]] = true;
else
hot._declinedDependencies[dep] = true;
else hot._declinedDependencies[dep] = true;
},
dispose: function(callback) {
hot._disposeHandlers.push(callback);
@ -114,14 +116,14 @@ module.exports = function() {
},
removeDisposeHandler: function(callback) {
var idx = hot._disposeHandlers.indexOf(callback);
if(idx >= 0) hot._disposeHandlers.splice(idx, 1);
if (idx >= 0) hot._disposeHandlers.splice(idx, 1);
},
// Management API
check: hotCheck,
apply: hotApply,
status: function(l) {
if(!l) return hotStatus;
if (!l) return hotStatus;
hotStatusHandlers.push(l);
},
addStatusHandler: function(l) {
@ -129,7 +131,7 @@ module.exports = function() {
},
removeStatusHandler: function(l) {
var idx = hotStatusHandlers.indexOf(l);
if(idx >= 0) hotStatusHandlers.splice(idx, 1);
if (idx >= 0) hotStatusHandlers.splice(idx, 1);
},
//inherit from previous dispose call
@ -144,7 +146,7 @@ module.exports = function() {
function hotSetStatus(newStatus) {
hotStatus = newStatus;
for(var i = 0; i < hotStatusHandlers.length; i++)
for (var i = 0; i < hotStatusHandlers.length; i++)
hotStatusHandlers[i].call(null, newStatus);
}
@ -160,16 +162,17 @@ module.exports = function() {
var hotUpdate, hotUpdateNewHash;
function toModuleId(id) {
var isNumber = (+id) + "" === id;
var isNumber = +id + "" === id;
return isNumber ? +id : id;
}
function hotCheck(apply) {
if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status");
if (hotStatus !== "idle")
throw new Error("check() is only allowed in idle status");
hotApplyOnUpdate = apply;
hotSetStatus("check");
return hotDownloadManifest(hotRequestTimeout).then(function(update) {
if(!update) {
if (!update) {
hotSetStatus("idle");
return null;
}
@ -187,33 +190,39 @@ module.exports = function() {
});
hotUpdate = {};
/*foreachInstalledChunks*/
{ // eslint-disable-line no-lone-blocks
{
// eslint-disable-line no-lone-blocks
/*globals chunkId */
hotEnsureUpdateChunk(chunkId);
}
if(hotStatus === "prepare" && hotChunksLoading === 0 && hotWaitingFiles === 0) {
if (
hotStatus === "prepare" &&
hotChunksLoading === 0 &&
hotWaitingFiles === 0
) {
hotUpdateDownloaded();
}
return promise;
});
}
function hotAddUpdateChunk(chunkId, moreModules) { // eslint-disable-line no-unused-vars
if(!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
function hotAddUpdateChunk(chunkId, moreModules) {
// eslint-disable-line no-unused-vars
if (!hotAvailableFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
return;
hotRequestedFilesMap[chunkId] = false;
for(var moduleId in moreModules) {
if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
for (var moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
hotUpdate[moduleId] = moreModules[moduleId];
}
}
if(--hotWaitingFiles === 0 && hotChunksLoading === 0) {
if (--hotWaitingFiles === 0 && hotChunksLoading === 0) {
hotUpdateDownloaded();
}
}
function hotEnsureUpdateChunk(chunkId) {
if(!hotAvailableFilesMap[chunkId]) {
if (!hotAvailableFilesMap[chunkId]) {
hotWaitingFilesMap[chunkId] = true;
} else {
hotRequestedFilesMap[chunkId] = true;
@ -226,25 +235,27 @@ module.exports = function() {
hotSetStatus("ready");
var deferred = hotDeferred;
hotDeferred = null;
if(!deferred) return;
if(hotApplyOnUpdate) {
if (!deferred) return;
if (hotApplyOnUpdate) {
// Wrap deferred object in Promise to mark it as a well-handled Promise to
// avoid triggering uncaught exception warning in Chrome.
// See https://bugs.chromium.org/p/chromium/issues/detail?id=465666
Promise.resolve().then(function() {
return hotApply(hotApplyOnUpdate);
}).then(
function(result) {
deferred.resolve(result);
},
function(err) {
deferred.reject(err);
}
);
Promise.resolve()
.then(function() {
return hotApply(hotApplyOnUpdate);
})
.then(
function(result) {
deferred.resolve(result);
},
function(err) {
deferred.reject(err);
}
);
} else {
var outdatedModules = [];
for(var id in hotUpdate) {
if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
for (var id in hotUpdate) {
if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
outdatedModules.push(toModuleId(id));
}
}
@ -253,7 +264,8 @@ module.exports = function() {
}
function hotApply(options) {
if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status");
if (hotStatus !== "ready")
throw new Error("apply() is only allowed in ready status");
options = options || {};
var cb;
@ -272,32 +284,31 @@ module.exports = function() {
id: id
};
});
while(queue.length > 0) {
while (queue.length > 0) {
var queueItem = queue.pop();
var moduleId = queueItem.id;
var chain = queueItem.chain;
module = installedModules[moduleId];
if(!module || module.hot._selfAccepted)
continue;
if(module.hot._selfDeclined) {
if (!module || module.hot._selfAccepted) continue;
if (module.hot._selfDeclined) {
return {
type: "self-declined",
chain: chain,
moduleId: moduleId
};
}
if(module.hot._main) {
if (module.hot._main) {
return {
type: "unaccepted",
chain: chain,
moduleId: moduleId
};
}
for(var i = 0; i < module.parents.length; i++) {
for (var i = 0; i < module.parents.length; i++) {
var parentId = module.parents[i];
var parent = installedModules[parentId];
if(!parent) continue;
if(parent.hot._declinedDependencies[moduleId]) {
if (!parent) continue;
if (parent.hot._declinedDependencies[moduleId]) {
return {
type: "declined",
chain: chain.concat([parentId]),
@ -305,9 +316,9 @@ module.exports = function() {
parentId: parentId
};
}
if(outdatedModules.includes(parentId)) continue;
if(parent.hot._acceptedDependencies[moduleId]) {
if(!outdatedDependencies[parentId])
if (outdatedModules.includes(parentId)) continue;
if (parent.hot._acceptedDependencies[moduleId]) {
if (!outdatedDependencies[parentId])
outdatedDependencies[parentId] = [];
addAllToSet(outdatedDependencies[parentId], [moduleId]);
continue;
@ -330,10 +341,9 @@ module.exports = function() {
}
function addAllToSet(a, b) {
for(var i = 0; i < b.length; i++) {
for (var i = 0; i < b.length; i++) {
var item = b[i];
if(!a.includes(item))
a.push(item);
if (!a.includes(item)) a.push(item);
}
}
@ -344,14 +354,16 @@ module.exports = function() {
var appliedUpdate = {};
var warnUnexpectedRequire = function warnUnexpectedRequire() {
console.warn("[HMR] unexpected require(" + result.moduleId + ") to disposed module");
console.warn(
"[HMR] unexpected require(" + result.moduleId + ") to disposed module"
);
};
for(var id in hotUpdate) {
if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
for (var id in hotUpdate) {
if (Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
moduleId = toModuleId(id);
var result;
if(hotUpdate[id]) {
if (hotUpdate[id]) {
result = getAffectedStuff(moduleId);
} else {
result = {
@ -363,57 +375,72 @@ module.exports = function() {
var doApply = false;
var doDispose = false;
var chainInfo = "";
if(result.chain) {
if (result.chain) {
chainInfo = "\nUpdate propagation: " + result.chain.join(" -> ");
}
switch(result.type) {
switch (result.type) {
case "self-declined":
if(options.onDeclined)
options.onDeclined(result);
if(!options.ignoreDeclined)
abortError = new Error("Aborted because of self decline: " + result.moduleId + chainInfo);
if (options.onDeclined) options.onDeclined(result);
if (!options.ignoreDeclined)
abortError = new Error(
"Aborted because of self decline: " +
result.moduleId +
chainInfo
);
break;
case "declined":
if(options.onDeclined)
options.onDeclined(result);
if(!options.ignoreDeclined)
abortError = new Error("Aborted because of declined dependency: " + result.moduleId + " in " + result.parentId + chainInfo);
if (options.onDeclined) options.onDeclined(result);
if (!options.ignoreDeclined)
abortError = new Error(
"Aborted because of declined dependency: " +
result.moduleId +
" in " +
result.parentId +
chainInfo
);
break;
case "unaccepted":
if(options.onUnaccepted)
options.onUnaccepted(result);
if(!options.ignoreUnaccepted)
abortError = new Error("Aborted because " + moduleId + " is not accepted" + chainInfo);
if (options.onUnaccepted) options.onUnaccepted(result);
if (!options.ignoreUnaccepted)
abortError = new Error(
"Aborted because " + moduleId + " is not accepted" + chainInfo
);
break;
case "accepted":
if(options.onAccepted)
options.onAccepted(result);
if (options.onAccepted) options.onAccepted(result);
doApply = true;
break;
case "disposed":
if(options.onDisposed)
options.onDisposed(result);
if (options.onDisposed) options.onDisposed(result);
doDispose = true;
break;
default:
throw new Error("Unexception type " + result.type);
}
if(abortError) {
if (abortError) {
hotSetStatus("abort");
return Promise.reject(abortError);
}
if(doApply) {
if (doApply) {
appliedUpdate[moduleId] = hotUpdate[moduleId];
addAllToSet(outdatedModules, result.outdatedModules);
for(moduleId in result.outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(result.outdatedDependencies, moduleId)) {
if(!outdatedDependencies[moduleId])
for (moduleId in result.outdatedDependencies) {
if (
Object.prototype.hasOwnProperty.call(
result.outdatedDependencies,
moduleId
)
) {
if (!outdatedDependencies[moduleId])
outdatedDependencies[moduleId] = [];
addAllToSet(outdatedDependencies[moduleId], result.outdatedDependencies[moduleId]);
addAllToSet(
outdatedDependencies[moduleId],
result.outdatedDependencies[moduleId]
);
}
}
}
if(doDispose) {
if (doDispose) {
addAllToSet(outdatedModules, [result.moduleId]);
appliedUpdate[moduleId] = warnUnexpectedRequire;
}
@ -422,9 +449,12 @@ module.exports = function() {
// Store self accepted outdated modules to require them later by the module system
var outdatedSelfAcceptedModules = [];
for(i = 0; i < outdatedModules.length; i++) {
for (i = 0; i < outdatedModules.length; i++) {
moduleId = outdatedModules[i];
if(installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted)
if (
installedModules[moduleId] &&
installedModules[moduleId].hot._selfAccepted
)
outdatedSelfAcceptedModules.push({
module: moduleId,
errorHandler: installedModules[moduleId].hot._selfAccepted
@ -434,23 +464,23 @@ module.exports = function() {
// Now in "dispose" phase
hotSetStatus("dispose");
Object.keys(hotAvailableFilesMap).forEach(function(chunkId) {
if(hotAvailableFilesMap[chunkId] === false) {
if (hotAvailableFilesMap[chunkId] === false) {
hotDisposeChunk(chunkId);
}
});
var idx;
var queue = outdatedModules.slice();
while(queue.length > 0) {
while (queue.length > 0) {
moduleId = queue.pop();
module = installedModules[moduleId];
if(!module) continue;
if (!module) continue;
var data = {};
// Call dispose handlers
var disposeHandlers = module.hot._disposeHandlers;
for(j = 0; j < disposeHandlers.length; j++) {
for (j = 0; j < disposeHandlers.length; j++) {
cb = disposeHandlers[j];
cb(data);
}
@ -466,11 +496,11 @@ module.exports = function() {
delete outdatedDependencies[moduleId];
// remove "parents" references from all children
for(j = 0; j < module.children.length; j++) {
for (j = 0; j < module.children.length; j++) {
var child = installedModules[module.children[j]];
if(!child) continue;
if (!child) continue;
idx = child.parents.indexOf(moduleId);
if(idx >= 0) {
if (idx >= 0) {
child.parents.splice(idx, 1);
}
}
@ -479,15 +509,17 @@ module.exports = function() {
// remove outdated dependency from module children
var dependency;
var moduleOutdatedDependencies;
for(moduleId in outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
for (moduleId in outdatedDependencies) {
if (
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
) {
module = installedModules[moduleId];
if(module) {
if (module) {
moduleOutdatedDependencies = outdatedDependencies[moduleId];
for(j = 0; j < moduleOutdatedDependencies.length; j++) {
for (j = 0; j < moduleOutdatedDependencies.length; j++) {
dependency = moduleOutdatedDependencies[j];
idx = module.children.indexOf(dependency);
if(idx >= 0) module.children.splice(idx, 1);
if (idx >= 0) module.children.splice(idx, 1);
}
}
}
@ -499,34 +531,36 @@ module.exports = function() {
hotCurrentHash = hotUpdateNewHash;
// insert new code
for(moduleId in appliedUpdate) {
if(Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
for (moduleId in appliedUpdate) {
if (Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
modules[moduleId] = appliedUpdate[moduleId];
}
}
// call accept handlers
var error = null;
for(moduleId in outdatedDependencies) {
if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
for (moduleId in outdatedDependencies) {
if (
Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)
) {
module = installedModules[moduleId];
if(module) {
if (module) {
moduleOutdatedDependencies = outdatedDependencies[moduleId];
var callbacks = [];
for(i = 0; i < moduleOutdatedDependencies.length; i++) {
for (i = 0; i < moduleOutdatedDependencies.length; i++) {
dependency = moduleOutdatedDependencies[i];
cb = module.hot._acceptedDependencies[dependency];
if(cb) {
if(callbacks.includes(cb)) continue;
if (cb) {
if (callbacks.includes(cb)) continue;
callbacks.push(cb);
}
}
for(i = 0; i < callbacks.length; i++) {
for (i = 0; i < callbacks.length; i++) {
cb = callbacks[i];
try {
cb(moduleOutdatedDependencies);
} catch(err) {
if(options.onErrored) {
} catch (err) {
if (options.onErrored) {
options.onErrored({
type: "accept-errored",
moduleId: moduleId,
@ -534,9 +568,8 @@ module.exports = function() {
error: err
});
}
if(!options.ignoreErrored) {
if(!error)
error = err;
if (!options.ignoreErrored) {
if (!error) error = err;
}
}
}
@ -545,18 +578,18 @@ module.exports = function() {
}
// Load self accepted modules
for(i = 0; i < outdatedSelfAcceptedModules.length; i++) {
for (i = 0; i < outdatedSelfAcceptedModules.length; i++) {
var item = outdatedSelfAcceptedModules[i];
moduleId = item.module;
hotCurrentParents = [moduleId];
try {
$require$(moduleId);
} catch(err) {
if(typeof item.errorHandler === "function") {
} catch (err) {
if (typeof item.errorHandler === "function") {
try {
item.errorHandler(err);
} catch(err2) {
if(options.onErrored) {
} catch (err2) {
if (options.onErrored) {
options.onErrored({
type: "self-accept-error-handler-errored",
moduleId: moduleId,
@ -564,31 +597,28 @@ module.exports = function() {
originalError: err
});
}
if(!options.ignoreErrored) {
if(!error)
error = err2;
if (!options.ignoreErrored) {
if (!error) error = err2;
}
if(!error)
error = err;
if (!error) error = err;
}
} else {
if(options.onErrored) {
if (options.onErrored) {
options.onErrored({
type: "self-accept-errored",
moduleId: moduleId,
error: err
});
}
if(!options.ignoreErrored) {
if(!error)
error = err;
if (!options.ignoreErrored) {
if (!error) error = err;
}
}
}
}
// handle errors in accept handlers and self accepted module load
if(error) {
if (error) {
hotSetStatus("fail");
return Promise.reject(error);
}

View File

@ -25,255 +25,382 @@ module.exports = class HotModuleReplacementPlugin {
const multiStep = this.multiStep;
const fullBuildTimeout = this.fullBuildTimeout;
const requestTimeout = this.requestTimeout;
const hotUpdateChunkFilename = compiler.options.output.hotUpdateChunkFilename;
const hotUpdateChunkFilename =
compiler.options.output.hotUpdateChunkFilename;
const hotUpdateMainFilename = compiler.options.output.hotUpdateMainFilename;
compiler.hooks.additionalPass.tapAsync("HotModuleReplacementPlugin", (callback) => {
if(multiStep)
return setTimeout(callback, fullBuildTimeout);
return callback();
});
compiler.hooks.compilation.tap("HotModuleReplacementPlugin", (compilation, {
normalModuleFactory
}) => {
const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate;
if(!hotUpdateChunkTemplate) return;
compiler.hooks.additionalPass.tapAsync(
"HotModuleReplacementPlugin",
callback => {
if (multiStep) return setTimeout(callback, fullBuildTimeout);
return callback();
}
);
compiler.hooks.compilation.tap(
"HotModuleReplacementPlugin",
(compilation, { normalModuleFactory }) => {
const hotUpdateChunkTemplate = compilation.hotUpdateChunkTemplate;
if (!hotUpdateChunkTemplate) return;
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(ConstDependency, new ConstDependency.Template());
compilation.dependencyFactories.set(ConstDependency, new NullFactory());
compilation.dependencyTemplates.set(
ConstDependency,
new ConstDependency.Template()
);
compilation.dependencyFactories.set(ModuleHotAcceptDependency, normalModuleFactory);
compilation.dependencyTemplates.set(ModuleHotAcceptDependency, new ModuleHotAcceptDependency.Template());
compilation.dependencyFactories.set(
ModuleHotAcceptDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ModuleHotAcceptDependency,
new ModuleHotAcceptDependency.Template()
);
compilation.dependencyFactories.set(ModuleHotDeclineDependency, normalModuleFactory);
compilation.dependencyTemplates.set(ModuleHotDeclineDependency, new ModuleHotDeclineDependency.Template());
compilation.dependencyFactories.set(
ModuleHotDeclineDependency,
normalModuleFactory
);
compilation.dependencyTemplates.set(
ModuleHotDeclineDependency,
new ModuleHotDeclineDependency.Template()
);
compilation.hooks.record.tap("HotModuleReplacementPlugin", (compilation, records) => {
if(records.hash === compilation.hash) return;
records.hash = compilation.hash;
records.moduleHashs = {};
for(const module of compilation.modules) {
const identifier = module.identifier();
const hash = createHash(compilation.outputOptions.hashFunction);
module.updateHash(hash);
records.moduleHashs[identifier] = hash.digest("hex");
}
records.chunkHashs = {};
for(const chunk of compilation.chunks) {
records.chunkHashs[chunk.id] = chunk.hash;
}
records.chunkModuleIds = {};
for(const chunk of compilation.chunks) {
records.chunkModuleIds[chunk.id] = Array.from(chunk.modulesIterable, m => m.id);
}
});
let initialPass = false;
let recompilation = false;
compilation.hooks.afterHash.tap("HotModuleReplacementPlugin", () => {
let records = compilation.records;
if(!records) {
initialPass = true;
return;
}
if(!records.hash)
initialPass = true;
const preHash = records.preHash || "x";
const prepreHash = records.prepreHash || "x";
if(preHash === compilation.hash) {
recompilation = true;
compilation.modifyHash(prepreHash);
return;
}
records.prepreHash = records.hash || "x";
records.preHash = compilation.hash;
compilation.modifyHash(records.prepreHash);
});
compilation.hooks.shouldGenerateChunkAssets.tap("HotModuleReplacementPlugin", () => {
if(multiStep && !recompilation && !initialPass)
return false;
});
compilation.hooks.needAdditionalPass.tap("HotModuleReplacementPlugin", () => {
if(multiStep && !recompilation && !initialPass)
return true;
});
compilation.hooks.additionalChunkAssets.tap("HotModuleReplacementPlugin", () => {
const records = compilation.records;
if(records.hash === compilation.hash) return;
if(!records.moduleHashs || !records.chunkHashs || !records.chunkModuleIds) return;
for(const module of compilation.modules) {
const identifier = module.identifier();
let hash = createHash(compilation.outputOptions.hashFunction);
module.updateHash(hash);
hash = hash.digest("hex");
module.hotUpdate = records.moduleHashs[identifier] !== hash;
}
const hotUpdateMainContent = {
h: compilation.hash,
c: {},
};
for(let chunkId of Object.keys(records.chunkHashs)) {
chunkId = isNaN(+chunkId) ? chunkId : +chunkId;
const currentChunk = compilation.chunks.find(chunk => chunk.id === chunkId);
if(currentChunk) {
const newModules = currentChunk.getModules().filter(module => module.hotUpdate);
const allModules = new Set();
for(const module of currentChunk.modulesIterable) {
allModules.add(module.id);
compilation.hooks.record.tap(
"HotModuleReplacementPlugin",
(compilation, records) => {
if (records.hash === compilation.hash) return;
records.hash = compilation.hash;
records.moduleHashs = {};
for (const module of compilation.modules) {
const identifier = module.identifier();
const hash = createHash(compilation.outputOptions.hashFunction);
module.updateHash(hash);
records.moduleHashs[identifier] = hash.digest("hex");
}
const removedModules = records.chunkModuleIds[chunkId].filter(id => !allModules.has(id));
if(newModules.length > 0 || removedModules.length > 0) {
const source = hotUpdateChunkTemplate.render(chunkId, newModules, removedModules, compilation.hash, compilation.moduleTemplates.javascript, compilation.dependencyTemplates);
const filename = compilation.getPath(hotUpdateChunkFilename, {
hash: records.hash,
chunk: currentChunk
});
compilation.additionalChunkAssets.push(filename);
compilation.assets[filename] = source;
hotUpdateMainContent.c[chunkId] = true;
currentChunk.files.push(filename);
compilation.hooks.chunkAsset.call("HotModuleReplacementPlugin", currentChunk, filename);
records.chunkHashs = {};
for (const chunk of compilation.chunks) {
records.chunkHashs[chunk.id] = chunk.hash;
}
} else {
hotUpdateMainContent.c[chunkId] = false;
}
}
const source = new RawSource(JSON.stringify(hotUpdateMainContent));
const filename = compilation.getPath(hotUpdateMainFilename, {
hash: records.hash
});
compilation.assets[filename] = source;
});
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.hash.tap("HotModuleReplacementPlugin", hash => {
hash.update("HotMainTemplateDecorator");
});
mainTemplate.hooks.moduleRequire.tap("HotModuleReplacementPlugin", (_, chunk, hash, varModuleId) => {
return `hotCreateRequire(${varModuleId})`;
});
mainTemplate.hooks.requireExtensions.tap("HotModuleReplacementPlugin", source => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(mainTemplate.requireFn + ".h = function() { return hotCurrentHash; };");
return Template.asString(buf);
});
const needChunkLoadingCode = chunk => {
for(const chunkGroup of chunk.groupsIterable) {
if(chunkGroup.chunks.length > 1) return true;
if(chunkGroup.getNumberOfChildren() > 0) return true;
}
return false;
};
mainTemplate.hooks.bootstrap.tap("HotModuleReplacementPlugin", (source, chunk, hash) => {
source = mainTemplate.hooks.hotBootstrap.call(source, chunk, hash);
return Template.asString([
source,
"",
hotInitCode
.replace(/\$require\$/g, mainTemplate.requireFn)
.replace(/\$hash\$/g, JSON.stringify(hash))
.replace(/\$requestTimeout\$/g, requestTimeout)
.replace(/\/\*foreachInstalledChunks\*\//g, needChunkLoadingCode(chunk) ? "for(var chunkId in installedChunks)" : `var chunkId = ${JSON.stringify(chunk.id)};`)
]);
});
mainTemplate.hooks.globalHash.tap("HotModuleReplacementPlugin", () => true);
mainTemplate.hooks.currentHash.tap("HotModuleReplacementPlugin", (_, length) => {
if(isFinite(length))
return `hotCurrentHash.substr(0, ${length})`;
else
return "hotCurrentHash";
});
mainTemplate.hooks.moduleObj.tap("HotModuleReplacementPlugin", (source, chunk, hash, varModuleId) => {
return Template.asString([
`${source},`,
`hot: hotCreateModule(${varModuleId}),`,
"parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),",
"children: []"
]);
});
const handler = (parser, parserOptions) => {
parser.hooks.expression.for("__webpack_hash__").tap("HotModuleReplacementPlugin", ParserHelpers.toConstantDependencyWithWebpackRequire(parser, "__webpack_require__.h()"));
parser.hooks.evaluateTypeof.for("__webpack_hash__").tap("HotModuleReplacementPlugin", ParserHelpers.evaluateToString("string"));
parser.hooks.evaluateIdentifier.for("module.hot").tap({
name: "HotModuleReplacementPlugin",
before: "NodeStuffPlugin"
}, expr => {
return ParserHelpers.evaluateToIdentifier("module.hot", !!parser.state.compilation.hotUpdateChunkTemplate)(expr);
});
// TODO webpack 5: refactor this, no custom hooks
if(!parser.hooks.hotAcceptCallback)
parser.hooks.hotAcceptCallback = new SyncBailHook(["expression", "requests"]);
if(!parser.hooks.hotAcceptWithoutCallback)
parser.hooks.hotAcceptWithoutCallback = new SyncBailHook(["expression", "requests"]);
parser.hooks.call.for("module.hot.accept").tap("HotModuleReplacementPlugin", expr => {
if(!parser.state.compilation.hotUpdateChunkTemplate) return false;
if(expr.arguments.length >= 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];
let requests = [];
if(arg.isString()) {
params = [arg];
} else if(arg.isArray()) {
params = arg.items.filter(param => param.isString());
}
if(params.length > 0) {
params.forEach((param, idx) => {
const request = param.string;
const dep = new ModuleHotAcceptDependency(request, param.range);
dep.optional = true;
dep.loc = Object.create(expr.loc);
dep.loc.index = idx;
parser.state.module.addDependency(dep);
requests.push(request);
});
if(expr.arguments.length > 1)
parser.hooks.hotAcceptCallback.call(expr.arguments[1], requests);
else
parser.hooks.hotAcceptWithoutCallback.call(expr, requests);
records.chunkModuleIds = {};
for (const chunk of compilation.chunks) {
records.chunkModuleIds[chunk.id] = Array.from(
chunk.modulesIterable,
m => m.id
);
}
}
);
let initialPass = false;
let recompilation = false;
compilation.hooks.afterHash.tap("HotModuleReplacementPlugin", () => {
let records = compilation.records;
if (!records) {
initialPass = true;
return;
}
if (!records.hash) initialPass = true;
const preHash = records.preHash || "x";
const prepreHash = records.prepreHash || "x";
if (preHash === compilation.hash) {
recompilation = true;
compilation.modifyHash(prepreHash);
return;
}
records.prepreHash = records.hash || "x";
records.preHash = compilation.hash;
compilation.modifyHash(records.prepreHash);
});
parser.hooks.call.for("module.hot.decline").tap("HotModuleReplacementPlugin", expr => {
if(!parser.state.compilation.hotUpdateChunkTemplate) return false;
if(expr.arguments.length === 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];
if(arg.isString()) {
params = [arg];
} else if(arg.isArray()) {
params = arg.items.filter(param => param.isString());
compilation.hooks.shouldGenerateChunkAssets.tap(
"HotModuleReplacementPlugin",
() => {
if (multiStep && !recompilation && !initialPass) return false;
}
);
compilation.hooks.needAdditionalPass.tap(
"HotModuleReplacementPlugin",
() => {
if (multiStep && !recompilation && !initialPass) return true;
}
);
compilation.hooks.additionalChunkAssets.tap(
"HotModuleReplacementPlugin",
() => {
const records = compilation.records;
if (records.hash === compilation.hash) return;
if (
!records.moduleHashs ||
!records.chunkHashs ||
!records.chunkModuleIds
)
return;
for (const module of compilation.modules) {
const identifier = module.identifier();
let hash = createHash(compilation.outputOptions.hashFunction);
module.updateHash(hash);
hash = hash.digest("hex");
module.hotUpdate = records.moduleHashs[identifier] !== hash;
}
params.forEach((param, idx) => {
const dep = new ModuleHotDeclineDependency(param.string, param.range);
dep.optional = true;
dep.loc = Object.create(expr.loc);
dep.loc.index = idx;
parser.state.module.addDependency(dep);
const hotUpdateMainContent = {
h: compilation.hash,
c: {}
};
for (let chunkId of Object.keys(records.chunkHashs)) {
chunkId = isNaN(+chunkId) ? chunkId : +chunkId;
const currentChunk = compilation.chunks.find(
chunk => chunk.id === chunkId
);
if (currentChunk) {
const newModules = currentChunk
.getModules()
.filter(module => module.hotUpdate);
const allModules = new Set();
for (const module of currentChunk.modulesIterable) {
allModules.add(module.id);
}
const removedModules = records.chunkModuleIds[chunkId].filter(
id => !allModules.has(id)
);
if (newModules.length > 0 || removedModules.length > 0) {
const source = hotUpdateChunkTemplate.render(
chunkId,
newModules,
removedModules,
compilation.hash,
compilation.moduleTemplates.javascript,
compilation.dependencyTemplates
);
const filename = compilation.getPath(hotUpdateChunkFilename, {
hash: records.hash,
chunk: currentChunk
});
compilation.additionalChunkAssets.push(filename);
compilation.assets[filename] = source;
hotUpdateMainContent.c[chunkId] = true;
currentChunk.files.push(filename);
compilation.hooks.chunkAsset.call(
"HotModuleReplacementPlugin",
currentChunk,
filename
);
}
} else {
hotUpdateMainContent.c[chunkId] = false;
}
}
const source = new RawSource(JSON.stringify(hotUpdateMainContent));
const filename = compilation.getPath(hotUpdateMainFilename, {
hash: records.hash
});
compilation.assets[filename] = source;
}
);
const mainTemplate = compilation.mainTemplate;
mainTemplate.hooks.hash.tap("HotModuleReplacementPlugin", hash => {
hash.update("HotMainTemplateDecorator");
});
parser.hooks.expression.for("module.hot").tap("HotModuleReplacementPlugin", ParserHelpers.skipTraversal);
};
// TODO add HMR support for javascript/esm
normalModuleFactory.hooks.parser.for("javascript/auto").tap("HotModuleReplacementPlugin", handler);
normalModuleFactory.hooks.parser.for("javascript/dynamic").tap("HotModuleReplacementPlugin", handler);
mainTemplate.hooks.moduleRequire.tap(
"HotModuleReplacementPlugin",
(_, chunk, hash, varModuleId) => {
return `hotCreateRequire(${varModuleId})`;
}
);
compilation.hooks.normalModuleLoader.tap("HotModuleReplacementPlugin", context => {
context.hot = true;
});
});
mainTemplate.hooks.requireExtensions.tap(
"HotModuleReplacementPlugin",
source => {
const buf = [source];
buf.push("");
buf.push("// __webpack_hash__");
buf.push(
mainTemplate.requireFn +
".h = function() { return hotCurrentHash; };"
);
return Template.asString(buf);
}
);
const needChunkLoadingCode = chunk => {
for (const chunkGroup of chunk.groupsIterable) {
if (chunkGroup.chunks.length > 1) return true;
if (chunkGroup.getNumberOfChildren() > 0) return true;
}
return false;
};
mainTemplate.hooks.bootstrap.tap(
"HotModuleReplacementPlugin",
(source, chunk, hash) => {
source = mainTemplate.hooks.hotBootstrap.call(source, chunk, hash);
return Template.asString([
source,
"",
hotInitCode
.replace(/\$require\$/g, mainTemplate.requireFn)
.replace(/\$hash\$/g, JSON.stringify(hash))
.replace(/\$requestTimeout\$/g, requestTimeout)
.replace(
/\/\*foreachInstalledChunks\*\//g,
needChunkLoadingCode(chunk)
? "for(var chunkId in installedChunks)"
: `var chunkId = ${JSON.stringify(chunk.id)};`
)
]);
}
);
mainTemplate.hooks.globalHash.tap(
"HotModuleReplacementPlugin",
() => true
);
mainTemplate.hooks.currentHash.tap(
"HotModuleReplacementPlugin",
(_, length) => {
if (isFinite(length)) return `hotCurrentHash.substr(0, ${length})`;
else return "hotCurrentHash";
}
);
mainTemplate.hooks.moduleObj.tap(
"HotModuleReplacementPlugin",
(source, chunk, hash, varModuleId) => {
return Template.asString([
`${source},`,
`hot: hotCreateModule(${varModuleId}),`,
"parents: (hotCurrentParentsTemp = hotCurrentParents, hotCurrentParents = [], hotCurrentParentsTemp),",
"children: []"
]);
}
);
const handler = (parser, parserOptions) => {
parser.hooks.expression
.for("__webpack_hash__")
.tap(
"HotModuleReplacementPlugin",
ParserHelpers.toConstantDependencyWithWebpackRequire(
parser,
"__webpack_require__.h()"
)
);
parser.hooks.evaluateTypeof
.for("__webpack_hash__")
.tap(
"HotModuleReplacementPlugin",
ParserHelpers.evaluateToString("string")
);
parser.hooks.evaluateIdentifier.for("module.hot").tap(
{
name: "HotModuleReplacementPlugin",
before: "NodeStuffPlugin"
},
expr => {
return ParserHelpers.evaluateToIdentifier(
"module.hot",
!!parser.state.compilation.hotUpdateChunkTemplate
)(expr);
}
);
// TODO webpack 5: refactor this, no custom hooks
if (!parser.hooks.hotAcceptCallback)
parser.hooks.hotAcceptCallback = new SyncBailHook([
"expression",
"requests"
]);
if (!parser.hooks.hotAcceptWithoutCallback)
parser.hooks.hotAcceptWithoutCallback = new SyncBailHook([
"expression",
"requests"
]);
parser.hooks.call
.for("module.hot.accept")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
return false;
if (expr.arguments.length >= 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];
let requests = [];
if (arg.isString()) {
params = [arg];
} else if (arg.isArray()) {
params = arg.items.filter(param => param.isString());
}
if (params.length > 0) {
params.forEach((param, idx) => {
const request = param.string;
const dep = new ModuleHotAcceptDependency(
request,
param.range
);
dep.optional = true;
dep.loc = Object.create(expr.loc);
dep.loc.index = idx;
parser.state.module.addDependency(dep);
requests.push(request);
});
if (expr.arguments.length > 1)
parser.hooks.hotAcceptCallback.call(
expr.arguments[1],
requests
);
else
parser.hooks.hotAcceptWithoutCallback.call(expr, requests);
}
}
});
parser.hooks.call
.for("module.hot.decline")
.tap("HotModuleReplacementPlugin", expr => {
if (!parser.state.compilation.hotUpdateChunkTemplate)
return false;
if (expr.arguments.length === 1) {
const arg = parser.evaluateExpression(expr.arguments[0]);
let params = [];
if (arg.isString()) {
params = [arg];
} else if (arg.isArray()) {
params = arg.items.filter(param => param.isString());
}
params.forEach((param, idx) => {
const dep = new ModuleHotDeclineDependency(
param.string,
param.range
);
dep.optional = true;
dep.loc = Object.create(expr.loc);
dep.loc.index = idx;
parser.state.module.addDependency(dep);
});
}
});
parser.hooks.expression
.for("module.hot")
.tap("HotModuleReplacementPlugin", ParserHelpers.skipTraversal);
};
// TODO add HMR support for javascript/esm
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap("HotModuleReplacementPlugin", handler);
normalModuleFactory.hooks.parser
.for("javascript/dynamic")
.tap("HotModuleReplacementPlugin", handler);
compilation.hooks.normalModuleLoader.tap(
"HotModuleReplacementPlugin",
context => {
context.hot = true;
}
);
}
);
}
};
const hotInitCode = Template.getFunctionContent(require("./HotModuleReplacement.runtime.js"));
const hotInitCode = Template.getFunctionContent(
require("./HotModuleReplacement.runtime.js")
);

View File

@ -15,20 +15,60 @@ module.exports = class HotUpdateChunkTemplate extends Tapable {
super();
this.outputOptions = outputOptions || {};
this.hooks = {
modules: new SyncWaterfallHook(["source", "modules", "removedModules", "moduleTemplate", "dependencyTemplates"]),
render: new SyncWaterfallHook(["source", "modules", "removedModules", "hash", "id", "moduleTemplate", "dependencyTemplates"]),
hash: new SyncHook(["hash"]),
modules: new SyncWaterfallHook([
"source",
"modules",
"removedModules",
"moduleTemplate",
"dependencyTemplates"
]),
render: new SyncWaterfallHook([
"source",
"modules",
"removedModules",
"hash",
"id",
"moduleTemplate",
"dependencyTemplates"
]),
hash: new SyncHook(["hash"])
};
}
render(id, modules, removedModules, hash, moduleTemplate, dependencyTemplates) {
render(
id,
modules,
removedModules,
hash,
moduleTemplate,
dependencyTemplates
) {
const hotUpdateChunk = new Chunk();
hotUpdateChunk.id = id;
hotUpdateChunk.setModules(modules);
hotUpdateChunk.removedModules = removedModules;
const modulesSource = Template.renderChunkModules(hotUpdateChunk, () => true, moduleTemplate, dependencyTemplates);
const core = this.hooks.modules.call(modulesSource, modules, removedModules, moduleTemplate, dependencyTemplates);
const source = this.hooks.render.call(core, modules, removedModules, hash, id, moduleTemplate, dependencyTemplates);
const modulesSource = Template.renderChunkModules(
hotUpdateChunk,
() => true,
moduleTemplate,
dependencyTemplates
);
const core = this.hooks.modules.call(
modulesSource,
modules,
removedModules,
moduleTemplate,
dependencyTemplates
);
const source = this.hooks.render.call(
core,
modules,
removedModules,
hash,
id,
moduleTemplate,
dependencyTemplates
);
return source;
}

View File

@ -17,7 +17,7 @@ class IgnorePlugin {
* and the resource given matches the regexp.
*/
checkResource(resource) {
if(!this.resourceRegExp) {
if (!this.resourceRegExp) {
return false;
}
return this.resourceRegExp.test(resource);
@ -28,7 +28,7 @@ class IgnorePlugin {
* or if context matches the given regexp.
*/
checkContext(context) {
if(!this.contextRegExp) {
if (!this.contextRegExp) {
return true;
}
return this.contextRegExp.test(context);
@ -42,25 +42,27 @@ class IgnorePlugin {
* and "contextRegExp" have to match.
*/
checkResult(result) {
if(!result) {
if (!result) {
return true;
}
return this.checkResource(result.request) && this.checkContext(result.context);
return (
this.checkResource(result.request) && this.checkContext(result.context)
);
}
checkIgnore(result) {
// check if result is ignored
if(this.checkResult(result)) {
if (this.checkResult(result)) {
return null;
}
return result;
}
apply(compiler) {
compiler.hooks.normalModuleFactory.tap("IgnorePlugin", (nmf) => {
compiler.hooks.normalModuleFactory.tap("IgnorePlugin", nmf => {
nmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore);
});
compiler.hooks.contextModuleFactory.tap("IgnorePlugin", (cmf) => {
compiler.hooks.contextModuleFactory.tap("IgnorePlugin", cmf => {
cmf.hooks.beforeResolve.tap("IgnorePlugin", this.checkIgnore);
});
}

View File

@ -13,23 +13,41 @@ const ReplaceSource = require("webpack-sources").ReplaceSource;
// TODO: remove DependencyVariables and replace them with something better
class JavascriptGenerator {
generate(module, dependencyTemplates, runtimeTemplate) {
const originalSource = module.originalSource();
if(!originalSource) {
if (!originalSource) {
return new RawSource("throw new Error('No source available');");
}
const source = new ReplaceSource(originalSource);
this.sourceBlock(module, module, [], dependencyTemplates, source, runtimeTemplate);
this.sourceBlock(
module,
module,
[],
dependencyTemplates,
source,
runtimeTemplate
);
return source;
}
sourceBlock(module, block, availableVars, dependencyTemplates, source, runtimeTemplate) {
for(const dependency of block.dependencies) {
this.sourceDependency(dependency, dependencyTemplates, source, runtimeTemplate);
sourceBlock(
module,
block,
availableVars,
dependencyTemplates,
source,
runtimeTemplate
) {
for (const dependency of block.dependencies) {
this.sourceDependency(
dependency,
dependencyTemplates,
source,
runtimeTemplate
);
}
/**
@ -39,9 +57,13 @@ class JavascriptGenerator {
*/
const vars = block.variables.reduce((result, value) => {
const variable = this.sourceVariables(
value, availableVars, dependencyTemplates, runtimeTemplate);
value,
availableVars,
dependencyTemplates,
runtimeTemplate
);
if(variable) {
if (variable) {
result.push(variable);
}
@ -54,7 +76,7 @@ class JavascriptGenerator {
* it will always return an array in an array which would lead to a IIFE wrapper around
* a module if we do this with an empty vars array.
*/
if(vars.length > 0) {
if (vars.length > 0) {
/**
* Split all variables up into chunks of unique names.
* e.g. imagine you have the following variable names that need to be injected:
@ -69,20 +91,25 @@ class JavascriptGenerator {
* "splitVariablesInUniqueNamedChunks" splits the variables shown above up to this:
* [[foo, bar, baz], [foo, some, more]]
*/
const injectionVariableChunks = this.splitVariablesInUniqueNamedChunks(vars);
const injectionVariableChunks = this.splitVariablesInUniqueNamedChunks(
vars
);
// create all the beginnings of IIFEs
const functionWrapperStarts = injectionVariableChunks.map((variableChunk) => {
return this.variableInjectionFunctionWrapperStartCode(
variableChunk.map(variable => variable.name)
);
});
const functionWrapperStarts = injectionVariableChunks.map(
variableChunk => {
return this.variableInjectionFunctionWrapperStartCode(
variableChunk.map(variable => variable.name)
);
}
);
// and all the ends
const functionWrapperEnds = injectionVariableChunks.map((variableChunk) => {
const functionWrapperEnds = injectionVariableChunks.map(variableChunk => {
return this.variableInjectionFunctionWrapperEndCode(
module,
variableChunk.map(variable => variable.expression), block
variableChunk.map(variable => variable.expression),
block
);
});
@ -93,15 +120,17 @@ class JavascriptGenerator {
const varEndCode = functionWrapperEnds.reverse().join("");
// if we have anything, add it to the source
if(varStartCode && varEndCode) {
if (varStartCode && varEndCode) {
const start = block.range ? block.range[0] : -10;
const end = block.range ? block.range[1] : (module.originalSource().size() + 1);
const end = block.range
? block.range[1]
: module.originalSource().size() + 1;
source.insert(start + 0.5, varStartCode);
source.insert(end + 0.5, "\n/* WEBPACK VAR INJECTION */" + varEndCode);
}
}
for(const childBlock of block.blocks) {
for (const childBlock of block.blocks) {
this.sourceBlock(
module,
childBlock,
@ -115,15 +144,30 @@ class JavascriptGenerator {
sourceDependency(dependency, dependencyTemplates, source, runtimeTemplate) {
const template = dependencyTemplates.get(dependency.constructor);
if(!template) throw new Error("No template for dependency: " + dependency.constructor.name);
if (!template)
throw new Error(
"No template for dependency: " + dependency.constructor.name
);
template.apply(dependency, source, runtimeTemplate, dependencyTemplates);
}
sourceVariables(variable, availableVars, dependencyTemplates, runtimeTemplate) {
sourceVariables(
variable,
availableVars,
dependencyTemplates,
runtimeTemplate
) {
const name = variable.name;
const expr = variable.expressionSource(dependencyTemplates, runtimeTemplate);
const expr = variable.expressionSource(
dependencyTemplates,
runtimeTemplate
);
if(availableVars.some(v => v.name === name && v.expression.source() === expr.source())) {
if (
availableVars.some(
v => v.name === name && v.expression.source() === expr.source()
)
) {
return;
}
return {
@ -143,7 +187,7 @@ class JavascriptGenerator {
}
contextArgument(module, block) {
if(this === block) {
if (this === block) {
return module.exportsArgument;
}
return "this";
@ -161,16 +205,16 @@ class JavascriptGenerator {
}
splitVariablesInUniqueNamedChunks(vars) {
const startState = [
[]
];
const startState = [[]];
return vars.reduce((chunks, variable) => {
const current = chunks[chunks.length - 1];
// check if variable with same name exists already
// if so create a new chunk of variables.
const variableNameAlreadyExists = current.some(v => v.name === variable.name);
const variableNameAlreadyExists = current.some(
v => v.name === variable.name
);
if(variableNameAlreadyExists) {
if (variableNameAlreadyExists) {
// start new chunk with current variable
chunks.push([variable]);
} else {
@ -180,7 +224,6 @@ class JavascriptGenerator {
return chunks;
}, startState);
}
}
module.exports = JavascriptGenerator;

View File

@ -11,86 +11,140 @@ const JavascriptGenerator = require("./JavascriptGenerator");
class JavascriptModulesPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("JavascriptModulesPlugin", (compilation, {
normalModuleFactory
}) => {
normalModuleFactory.hooks.createParser.for("javascript/auto").tap("JavascriptModulesPlugin", options => {
return new Parser(options, "auto");
});
normalModuleFactory.hooks.createParser.for("javascript/dynamic").tap("JavascriptModulesPlugin", options => {
return new Parser(options, "script");
});
normalModuleFactory.hooks.createParser.for("javascript/esm").tap("JavascriptModulesPlugin", options => {
return new Parser(options, "module");
});
normalModuleFactory.hooks.createGenerator.for("javascript/auto").tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
normalModuleFactory.hooks.createGenerator.for("javascript/dynamic").tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
normalModuleFactory.hooks.createGenerator.for("javascript/esm").tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
compilation.mainTemplate.hooks.renderManifest.tap("JavascriptModulesPlugin", (result, options) => {
const chunk = options.chunk;
const hash = options.hash;
const fullHash = options.fullHash;
const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates;
compiler.hooks.compilation.tap(
"JavascriptModulesPlugin",
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.createParser
.for("javascript/auto")
.tap("JavascriptModulesPlugin", options => {
return new Parser(options, "auto");
});
normalModuleFactory.hooks.createParser
.for("javascript/dynamic")
.tap("JavascriptModulesPlugin", options => {
return new Parser(options, "script");
});
normalModuleFactory.hooks.createParser
.for("javascript/esm")
.tap("JavascriptModulesPlugin", options => {
return new Parser(options, "module");
});
normalModuleFactory.hooks.createGenerator
.for("javascript/auto")
.tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
normalModuleFactory.hooks.createGenerator
.for("javascript/dynamic")
.tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
normalModuleFactory.hooks.createGenerator
.for("javascript/esm")
.tap("JavascriptModulesPlugin", options => {
return new JavascriptGenerator(options);
});
compilation.mainTemplate.hooks.renderManifest.tap(
"JavascriptModulesPlugin",
(result, options) => {
const chunk = options.chunk;
const hash = options.hash;
const fullHash = options.fullHash;
const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates;
let filenameTemplate;
if(chunk.filenameTemplate)
filenameTemplate = chunk.filenameTemplate;
else
filenameTemplate = outputOptions.filename;
let filenameTemplate;
if (chunk.filenameTemplate)
filenameTemplate = chunk.filenameTemplate;
else filenameTemplate = outputOptions.filename;
const useChunkHash = compilation.mainTemplate.useChunkHash(chunk);
const useChunkHash = compilation.mainTemplate.useChunkHash(chunk);
result.push({
render: () => compilation.mainTemplate.render(hash, chunk, moduleTemplates.javascript, dependencyTemplates),
filenameTemplate,
pathOptions: {
noChunkHash: !useChunkHash,
chunk
},
identifier: `chunk${chunk.id}`,
hash: useChunkHash ? chunk.hash : fullHash
});
return result;
});
compilation.mainTemplate.hooks.modules.tap("JavascriptModulesPlugin", (source, chunk, hash, moduleTemplate, dependencyTemplates) => {
return Template.renderChunkModules(chunk, () => true, moduleTemplate, dependencyTemplates, "/******/ ");
});
compilation.chunkTemplate.hooks.renderManifest.tap("JavascriptModulesPlugin", (result, options) => {
const chunk = options.chunk;
const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates;
result.push({
render: () =>
compilation.mainTemplate.render(
hash,
chunk,
moduleTemplates.javascript,
dependencyTemplates
),
filenameTemplate,
pathOptions: {
noChunkHash: !useChunkHash,
chunk
},
identifier: `chunk${chunk.id}`,
hash: useChunkHash ? chunk.hash : fullHash
});
return result;
}
);
compilation.mainTemplate.hooks.modules.tap(
"JavascriptModulesPlugin",
(source, chunk, hash, moduleTemplate, dependencyTemplates) => {
return Template.renderChunkModules(
chunk,
() => true,
moduleTemplate,
dependencyTemplates,
"/******/ "
);
}
);
compilation.chunkTemplate.hooks.renderManifest.tap(
"JavascriptModulesPlugin",
(result, options) => {
const chunk = options.chunk;
const outputOptions = options.outputOptions;
const moduleTemplates = options.moduleTemplates;
const dependencyTemplates = options.dependencyTemplates;
const filenameTemplate = outputOptions.chunkFilename;
const filenameTemplate = outputOptions.chunkFilename;
result.push({
render: () => this.renderJavascript(compilation.chunkTemplate, chunk, moduleTemplates.javascript, dependencyTemplates),
filenameTemplate,
pathOptions: {
chunk
},
identifier: `chunk${chunk.id}`,
hash: chunk.hash
});
result.push({
render: () =>
this.renderJavascript(
compilation.chunkTemplate,
chunk,
moduleTemplates.javascript,
dependencyTemplates
),
filenameTemplate,
pathOptions: {
chunk
},
identifier: `chunk${chunk.id}`,
hash: chunk.hash
});
return result;
});
});
return result;
}
);
}
);
}
renderJavascript(chunkTemplate, chunk, moduleTemplate, dependencyTemplates) {
const moduleSources = Template.renderChunkModules(chunk, m => true, moduleTemplate, dependencyTemplates);
const core = chunkTemplate.hooks.modules.call(moduleSources, chunk, moduleTemplate, dependencyTemplates);
let source = chunkTemplate.hooks.render.call(core, chunk, moduleTemplate, dependencyTemplates);
if(chunk.hasEntryModule()) {
const moduleSources = Template.renderChunkModules(
chunk,
m => true,
moduleTemplate,
dependencyTemplates
);
const core = chunkTemplate.hooks.modules.call(
moduleSources,
chunk,
moduleTemplate,
dependencyTemplates
);
let source = chunkTemplate.hooks.render.call(
core,
chunk,
moduleTemplate,
dependencyTemplates
);
if (chunk.hasEntryModule()) {
source = chunkTemplate.hooks.renderWithEntry.call(source, chunk);
}
chunk.rendered = true;

View File

@ -6,25 +6,32 @@
const ConcatSource = require("webpack-sources").ConcatSource;
const stringifySafe = data => JSON.stringify(data)
.replace(/\u2028|\u2029/g, str => str === "\u2029" ? "\\u2029" : "\\u2028"); // invalid in JavaScript but valid JSON
const stringifySafe = data =>
JSON.stringify(data).replace(
/\u2028|\u2029/g,
str => (str === "\u2029" ? "\\u2029" : "\\u2028")
); // invalid in JavaScript but valid JSON
class JsonGenerator {
generate(module, dependencyTemplates, runtimeTemplate) {
const source = new ConcatSource();
const data = module.buildInfo.jsonData;
if(Array.isArray(module.buildMeta.providedExports) && !module.isUsed("default")) {
if (
Array.isArray(module.buildMeta.providedExports) &&
!module.isUsed("default")
) {
// Only some exports are used: We can optimize here, by only generating a part of the JSON
const reducedJson = {};
for(const exportName of module.buildMeta.providedExports) {
if(exportName === "default")
continue;
for (const exportName of module.buildMeta.providedExports) {
if (exportName === "default") continue;
const used = module.isUsed(exportName);
if(used) {
if (used) {
reducedJson[used] = data[exportName];
}
}
source.add(`${module.moduleArgument}.exports = ${stringifySafe(reducedJson)};`);
source.add(
`${module.moduleArgument}.exports = ${stringifySafe(reducedJson)};`
);
} else {
source.add(`${module.moduleArgument}.exports = ${stringifySafe(data)};`);
}

View File

@ -9,16 +9,21 @@ const JsonGenerator = require("./JsonGenerator");
class JsonModulesPlugin {
apply(compiler) {
compiler.hooks.compilation.tap("JsonModulesPlugin", (compilation, {
normalModuleFactory
}) => {
normalModuleFactory.hooks.createParser.for("json").tap("JsonModulesPlugin", () => {
return new JsonParser();
});
normalModuleFactory.hooks.createGenerator.for("json").tap("JsonModulesPlugin", () => {
return new JsonGenerator();
});
});
compiler.hooks.compilation.tap(
"JsonModulesPlugin",
(compilation, { normalModuleFactory }) => {
normalModuleFactory.hooks.createParser
.for("json")
.tap("JsonModulesPlugin", () => {
return new JsonParser();
});
normalModuleFactory.hooks.createGenerator
.for("json")
.tap("JsonModulesPlugin", () => {
return new JsonGenerator();
});
}
);
}
}

View File

@ -15,7 +15,7 @@ class JsonParser {
const data = JSON.parse(source);
state.module.buildInfo.jsonData = data;
state.module.buildMeta.exportsType = "named";
if(typeof data === "object" && data)
if (typeof data === "object" && data)
state.module.addDependency(new JsonExportsDependency(Object.keys(data)));
state.module.addDependency(new JsonExportsDependency(["default"]));
return state;

View File

@ -13,50 +13,65 @@ class LibManifestPlugin {
}
apply(compiler) {
compiler.hooks.emit.tapAsync("LibManifestPlugin", (compilation, callback) => {
asyncLib.forEach(compilation.chunks, (chunk, callback) => {
if(!chunk.isOnlyInitial()) {
callback();
return;
}
const targetPath = compilation.getPath(this.options.path, {
hash: compilation.hash,
chunk
});
const name = this.options.name && compilation.getPath(this.options.name, {
hash: compilation.hash,
chunk
});
const manifest = {
name,
type: this.options.type,
content: Array.from(chunk.modulesIterable, module => {
if(module.libIdent) {
const ident = module.libIdent({
context: this.options.context || compiler.options.context
});
if(ident) {
return {
ident,
data: {
id: module.id,
buildMeta: module.buildMeta
}
};
}
compiler.hooks.emit.tapAsync(
"LibManifestPlugin",
(compilation, callback) => {
asyncLib.forEach(
compilation.chunks,
(chunk, callback) => {
if (!chunk.isOnlyInitial()) {
callback();
return;
}
}).filter(Boolean).reduce((obj, item) => {
obj[item.ident] = item.data;
return obj;
}, Object.create(null))
};
const content = Buffer.from(JSON.stringify(manifest), "utf8");
compiler.outputFileSystem.mkdirp(path.dirname(targetPath), err => {
if(err) return callback(err);
compiler.outputFileSystem.writeFile(targetPath, content, callback);
});
}, callback);
});
const targetPath = compilation.getPath(this.options.path, {
hash: compilation.hash,
chunk
});
const name =
this.options.name &&
compilation.getPath(this.options.name, {
hash: compilation.hash,
chunk
});
const manifest = {
name,
type: this.options.type,
content: Array.from(chunk.modulesIterable, module => {
if (module.libIdent) {
const ident = module.libIdent({
context: this.options.context || compiler.options.context
});
if (ident) {
return {
ident,
data: {
id: module.id,
buildMeta: module.buildMeta
}
};
}
}
})
.filter(Boolean)
.reduce((obj, item) => {
obj[item.ident] = item.data;
return obj;
}, Object.create(null))
};
const content = Buffer.from(JSON.stringify(manifest), "utf8");
compiler.outputFileSystem.mkdirp(path.dirname(targetPath), err => {
if (err) return callback(err);
compiler.outputFileSystem.writeFile(
targetPath,
content,
callback
);
});
},
callback
);
}
);
}
}
module.exports = LibManifestPlugin;

View File

@ -6,26 +6,30 @@
const SetVarMainTemplatePlugin = require("./SetVarMainTemplatePlugin");
const accessorToObjectAccess = (accessor) => {
return accessor.map((a) => {
return `[${JSON.stringify(a)}]`;
}).join("");
const accessorToObjectAccess = accessor => {
return accessor
.map(a => {
return `[${JSON.stringify(a)}]`;
})
.join("");
};
const accessorAccess = (base, accessor, joinWith) => {
accessor = [].concat(accessor);
return accessor.map((a, idx) => {
a = base ?
base + accessorToObjectAccess(accessor.slice(0, idx + 1)) :
accessor[0] + accessorToObjectAccess(accessor.slice(1, idx + 1));
if(idx === accessor.length - 1) return a;
if(idx === 0 && typeof base === "undefined") return `${a} = typeof ${a} === "object" ? ${a} : {}`;
return `${a} = ${a} || {}`;
}).join(joinWith || "; ");
return accessor
.map((a, idx) => {
a = base
? base + accessorToObjectAccess(accessor.slice(0, idx + 1))
: accessor[0] + accessorToObjectAccess(accessor.slice(1, idx + 1));
if (idx === accessor.length - 1) return a;
if (idx === 0 && typeof base === "undefined")
return `${a} = typeof ${a} === "object" ? ${a} : {}`;
return `${a} = ${a} || {}`;
})
.join(joinWith || "; ");
};
class LibraryTemplatePlugin {
constructor(name, target, umdNamedDefine, auxiliaryComment, exportProperty) {
this.name = name;
this.target = target;
@ -35,37 +39,54 @@ class LibraryTemplatePlugin {
}
apply(compiler) {
compiler.hooks.thisCompilation.tap("LibraryTemplatePlugin", (compilation) => {
if(this.exportProperty) {
compiler.hooks.thisCompilation.tap("LibraryTemplatePlugin", compilation => {
if (this.exportProperty) {
var ExportPropertyMainTemplatePlugin = require("./ExportPropertyMainTemplatePlugin");
new ExportPropertyMainTemplatePlugin(this.exportProperty).apply(compilation);
new ExportPropertyMainTemplatePlugin(this.exportProperty).apply(
compilation
);
}
switch(this.target) {
switch (this.target) {
case "var":
new SetVarMainTemplatePlugin(`var ${accessorAccess(false, this.name)}`).apply(compilation);
new SetVarMainTemplatePlugin(
`var ${accessorAccess(false, this.name)}`
).apply(compilation);
break;
case "assign":
new SetVarMainTemplatePlugin(accessorAccess(undefined, this.name)).apply(compilation);
new SetVarMainTemplatePlugin(
accessorAccess(undefined, this.name)
).apply(compilation);
break;
case "this":
case "self":
case "window":
if(this.name)
new SetVarMainTemplatePlugin(accessorAccess(this.target, this.name)).apply(compilation);
if (this.name)
new SetVarMainTemplatePlugin(
accessorAccess(this.target, this.name)
).apply(compilation);
else
new SetVarMainTemplatePlugin(this.target, true).apply(compilation);
break;
case "global":
if(this.name)
new SetVarMainTemplatePlugin(accessorAccess(compilation.runtimeTemplate.outputOptions.globalObject, this.name)).apply(compilation);
if (this.name)
new SetVarMainTemplatePlugin(
accessorAccess(
compilation.runtimeTemplate.outputOptions.globalObject,
this.name
)
).apply(compilation);
else
new SetVarMainTemplatePlugin(compilation.runtimeTemplate.outputOptions.globalObject, true).apply(compilation);
new SetVarMainTemplatePlugin(
compilation.runtimeTemplate.outputOptions.globalObject,
true
).apply(compilation);
break;
case "commonjs":
if(this.name)
new SetVarMainTemplatePlugin(accessorAccess("exports", this.name)).apply(compilation);
else
new SetVarMainTemplatePlugin("exports", true).apply(compilation);
if (this.name)
new SetVarMainTemplatePlugin(
accessorAccess("exports", this.name)
).apply(compilation);
else new SetVarMainTemplatePlugin("exports", true).apply(compilation);
break;
case "commonjs2":
case "commonjs-module":

View File

@ -13,29 +13,38 @@ class LoaderOptionsPlugin {
constructor(options) {
validateOptions(schema, options || {}, "Loader Options Plugin");
if(typeof options !== "object") options = {};
if(!options.test) options.test = {
test: () => true
};
if (typeof options !== "object") options = {};
if (!options.test)
options.test = {
test: () => true
};
this.options = options;
}
apply(compiler) {
const options = this.options;
compiler.hooks.compilation.tap("LoaderOptionsPlugin", (compilation) => {
compilation.hooks.normalModuleLoader.tap("LoaderOptionsPlugin", (context, module) => {
const resource = module.resource;
if(!resource) return;
const i = resource.indexOf("?");
if(ModuleFilenameHelpers.matchObject(options, i < 0 ? resource : resource.substr(0, i))) {
for(const key of Object.keys(options)) {
if(key === "include" || key === "exclude" || key === "test") {
continue;
compiler.hooks.compilation.tap("LoaderOptionsPlugin", compilation => {
compilation.hooks.normalModuleLoader.tap(
"LoaderOptionsPlugin",
(context, module) => {
const resource = module.resource;
if (!resource) return;
const i = resource.indexOf("?");
if (
ModuleFilenameHelpers.matchObject(
options,
i < 0 ? resource : resource.substr(0, i)
)
) {
for (const key of Object.keys(options)) {
if (key === "include" || key === "exclude" || key === "test") {
continue;
}
context[key] = options[key];
}
context[key] = options[key];
}
}
});
);
});
}
}

View File

@ -10,10 +10,13 @@ class LoaderTargetPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("LoaderTargetPlugin", (compilation) => {
compilation.hooks.normalModuleLoader.tap("LoaderTargetPlugin", (loaderContext) => {
loaderContext.target = this.target;
});
compiler.hooks.compilation.tap("LoaderTargetPlugin", compilation => {
compilation.hooks.normalModuleLoader.tap(
"LoaderTargetPlugin",
loaderContext => {
loaderContext.target = this.target;
}
);
});
}
}

View File

@ -36,19 +36,58 @@ module.exports = class MainTemplate extends Tapable {
this.outputOptions = outputOptions || {};
this.hooks = {
renderManifest: new SyncWaterfallHook(["result", "options"]),
modules: new SyncWaterfallHook(["modules", "chunk", "hash", "moduleTemplate", "dependencyTemplates"]),
moduleObj: new SyncWaterfallHook(["source", "chunk", "hash", "moduleIdExpression"]),
requireEnsure: new SyncWaterfallHook(["source", "chunk", "hash", "chunkIdExpression"]),
bootstrap: new SyncWaterfallHook(["source", "chunk", "hash", "moduleTemplate", "dependencyTemplates"]),
modules: new SyncWaterfallHook([
"modules",
"chunk",
"hash",
"moduleTemplate",
"dependencyTemplates"
]),
moduleObj: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"moduleIdExpression"
]),
requireEnsure: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"chunkIdExpression"
]),
bootstrap: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"moduleTemplate",
"dependencyTemplates"
]),
localVars: new SyncWaterfallHook(["source", "chunk", "hash"]),
require: new SyncWaterfallHook(["source", "chunk", "hash"]),
requireExtensions: new SyncWaterfallHook(["source", "chunk", "hash"]),
beforeStartup: new SyncWaterfallHook(["source", "chunk", "hash"]),
startup: new SyncWaterfallHook(["source", "chunk", "hash"]),
render: new SyncWaterfallHook(["source", "chunk", "hash", "moduleTemplate", "dependencyTemplates"]),
render: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"moduleTemplate",
"dependencyTemplates"
]),
renderWithEntry: new SyncWaterfallHook(["source", "chunk", "hash"]),
moduleRequire: new SyncWaterfallHook(["source", "chunk", "hash", "moduleIdExpression"]),
addModule: new SyncWaterfallHook(["source", "chunk", "hash", "moduleIdExpression", "moduleExpression"]),
moduleRequire: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"moduleIdExpression"
]),
addModule: new SyncWaterfallHook([
"source",
"chunk",
"hash",
"moduleIdExpression",
"moduleExpression"
]),
currentHash: new SyncWaterfallHook(["source", "requestedLength"]),
assetPath: new SyncWaterfallHook(["path", "options"]),
hash: new SyncHook(["hash"]),
@ -62,23 +101,42 @@ module.exports = class MainTemplate extends Tapable {
};
this.hooks.startup.tap("MainTemplate", (source, chunk, hash) => {
const buf = [];
if(chunk.entryModule) {
if (chunk.entryModule) {
buf.push("// Load entry module and return exports");
buf.push(`return ${this.renderRequireFunctionForModule(hash, chunk, JSON.stringify(chunk.entryModule.id))}(${this.requireFn}.s = ${JSON.stringify(chunk.entryModule.id)});`);
buf.push(
`return ${this.renderRequireFunctionForModule(
hash,
chunk,
JSON.stringify(chunk.entryModule.id)
)}(${this.requireFn}.s = ${JSON.stringify(chunk.entryModule.id)});`
);
}
return Template.asString(buf);
});
this.hooks.render.tap("MainTemplate", (bootstrapSource, chunk, hash, moduleTemplate, dependencyTemplates) => {
const source = new ConcatSource();
source.add("/******/ (function(modules) { // webpackBootstrap\n");
source.add(new PrefixSource("/******/", bootstrapSource));
source.add("/******/ })\n");
source.add("/************************************************************************/\n");
source.add("/******/ (");
source.add(this.hooks.modules.call(new RawSource(""), chunk, hash, moduleTemplate, dependencyTemplates));
source.add(")");
return source;
});
this.hooks.render.tap(
"MainTemplate",
(bootstrapSource, chunk, hash, moduleTemplate, dependencyTemplates) => {
const source = new ConcatSource();
source.add("/******/ (function(modules) { // webpackBootstrap\n");
source.add(new PrefixSource("/******/", bootstrapSource));
source.add("/******/ })\n");
source.add(
"/************************************************************************/\n"
);
source.add("/******/ (");
source.add(
this.hooks.modules.call(
new RawSource(""),
chunk,
hash,
moduleTemplate,
dependencyTemplates
)
);
source.add(")");
return source;
}
);
this.hooks.localVars.tap("MainTemplate", (source, chunk, hash) => {
return Template.asString([
source,
@ -98,23 +156,35 @@ module.exports = class MainTemplate extends Tapable {
Template.indent(this.hooks.moduleObj.call("", chunk, hash, "moduleId")),
"};",
"",
Template.asString(outputOptions.strictModuleExceptionHandling ? [
"// Execute the module function",
"var threw = true;",
"try {",
Template.indent([
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(hash, chunk, "moduleId")});`,
"threw = false;"
]),
"} finally {",
Template.indent([
"if(threw) delete installedModules[moduleId];"
]),
"}"
] : [
"// Execute the module function",
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(hash, chunk, "moduleId")});`,
]),
Template.asString(
outputOptions.strictModuleExceptionHandling
? [
"// Execute the module function",
"var threw = true;",
"try {",
Template.indent([
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(
hash,
chunk,
"moduleId"
)});`,
"threw = false;"
]),
"} finally {",
Template.indent([
"if(threw) delete installedModules[moduleId];"
]),
"}"
]
: [
"// Execute the module function",
`modules[moduleId].call(module.exports, module, module.exports, ${this.renderRequireFunctionForModule(
hash,
chunk,
"moduleId"
)});`
]
),
"",
"// Flag the module as loaded",
"module.l = true;",
@ -123,23 +193,26 @@ module.exports = class MainTemplate extends Tapable {
"return module.exports;"
]);
});
this.hooks.moduleObj.tap("MainTemplate", (source, chunk, hash, varModuleId) => {
return Template.asString([
"i: moduleId,",
"l: false,",
"exports: {}"
]);
});
this.hooks.moduleObj.tap(
"MainTemplate",
(source, chunk, hash, varModuleId) => {
return Template.asString(["i: moduleId,", "l: false,", "exports: {}"]);
}
);
this.hooks.requireExtensions.tap("MainTemplate", (source, chunk, hash) => {
const buf = [];
const chunkMaps = chunk.getChunkMaps();
// Check if there are non initial chunks which need to be imported using require-ensure
if(Object.keys(chunkMaps.hash).length) {
if (Object.keys(chunkMaps.hash).length) {
buf.push("// This file contains only the entry chunk.");
buf.push("// The chunk loading function for additional chunks");
buf.push(`${this.requireFn}.e = function requireEnsure(chunkId) {`);
buf.push(Template.indent("var promises = [];"));
buf.push(Template.indent(this.hooks.requireEnsure.call("", chunk, hash, "chunkId")));
buf.push(
Template.indent(
this.hooks.requireEnsure.call("", chunk, hash, "chunkId")
)
);
buf.push(Template.indent("return Promise.all(promises);"));
buf.push("};");
}
@ -154,46 +227,58 @@ module.exports = class MainTemplate extends Tapable {
buf.push("");
buf.push("// define getter function for harmony exports");
buf.push(`${this.requireFn}.d = function(exports, name, getter) {`);
buf.push(Template.indent([
`if(!${this.requireFn}.o(exports, name)) {`,
buf.push(
Template.indent([
"Object.defineProperty(exports, name, {",
`if(!${this.requireFn}.o(exports, name)) {`,
Template.indent([
"configurable: false,",
"enumerable: true,",
"get: getter"
"Object.defineProperty(exports, name, {",
Template.indent([
"configurable: false,",
"enumerable: true,",
"get: getter"
]),
"});"
]),
"});"
]),
"}"
]));
"}"
])
);
buf.push("};");
buf.push("");
buf.push("// define __esModule on exports");
buf.push(`${this.requireFn}.r = function(exports) {`);
buf.push(Template.indent([
"Object.defineProperty(exports, '__esModule', { value: true });"
]));
buf.push(
Template.indent([
"Object.defineProperty(exports, '__esModule', { value: true });"
])
);
buf.push("};");
buf.push("");
buf.push("// getDefaultExport function for compatibility with non-harmony modules");
buf.push(
"// getDefaultExport function for compatibility with non-harmony modules"
);
buf.push(this.requireFn + ".n = function(module) {");
buf.push(Template.indent([
"var getter = module && module.__esModule ?",
buf.push(
Template.indent([
"function getDefault() { return module['default']; } :",
"function getModuleExports() { return module; };"
]),
`${this.requireFn}.d(getter, 'a', getter);`,
"return getter;"
]));
"var getter = module && module.__esModule ?",
Template.indent([
"function getDefault() { return module['default']; } :",
"function getModuleExports() { return module; };"
]),
`${this.requireFn}.d(getter, 'a', getter);`,
"return getter;"
])
);
buf.push("};");
buf.push("");
buf.push("// Object.prototype.hasOwnProperty.call");
buf.push(`${this.requireFn}.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };`);
buf.push(
`${
this.requireFn
}.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };`
);
const publicPath = this.getPublicPath({
hash: hash
@ -217,7 +302,15 @@ module.exports = class MainTemplate extends Tapable {
render(hash, chunk, moduleTemplate, dependencyTemplates) {
const buf = [];
buf.push(this.hooks.bootstrap.call("", chunk, hash, moduleTemplate, dependencyTemplates));
buf.push(
this.hooks.bootstrap.call(
"",
chunk,
hash,
moduleTemplate,
dependencyTemplates
)
);
buf.push(this.hooks.localVars.call("", chunk, hash));
buf.push("");
buf.push("// The require function");
@ -225,34 +318,65 @@ module.exports = class MainTemplate extends Tapable {
buf.push(Template.indent(this.hooks.require.call("", chunk, hash)));
buf.push("}");
buf.push("");
buf.push(Template.asString(this.hooks.requireExtensions.call("", chunk, hash)));
buf.push(
Template.asString(this.hooks.requireExtensions.call("", chunk, hash))
);
buf.push("");
buf.push(Template.asString(this.hooks.beforeStartup.call("", chunk, hash)));
buf.push(Template.asString(this.hooks.startup.call("", chunk, hash)));
let source = this.hooks.render.call(new OriginalSource(Template.prefix(buf, " \t") + "\n", "webpack/bootstrap"), chunk, hash, moduleTemplate, dependencyTemplates);
if(chunk.hasEntryModule()) {
let source = this.hooks.render.call(
new OriginalSource(
Template.prefix(buf, " \t") + "\n",
"webpack/bootstrap"
),
chunk,
hash,
moduleTemplate,
dependencyTemplates
);
if (chunk.hasEntryModule()) {
source = this.hooks.renderWithEntry.call(source, chunk, hash);
}
if(!source) throw new Error("Compiler error: MainTemplate plugin 'render' should return something");
if (!source)
throw new Error(
"Compiler error: MainTemplate plugin 'render' should return something"
);
chunk.rendered = true;
return new ConcatSource(source, ";");
}
renderRequireFunctionForModule(hash, chunk, varModuleId) {
return this.hooks.moduleRequire.call(this.requireFn, chunk, hash, varModuleId);
return this.hooks.moduleRequire.call(
this.requireFn,
chunk,
hash,
varModuleId
);
}
renderAddModule(hash, chunk, varModuleId, varModule) {
return this.hooks.addModule.call(`modules[${varModuleId}] = ${varModule};`, chunk, hash, varModuleId, varModule);
return this.hooks.addModule.call(
`modules[${varModuleId}] = ${varModule};`,
chunk,
hash,
varModuleId,
varModule
);
}
renderCurrentHashCode(hash, length) {
length = length || Infinity;
return this.hooks.currentHash.call(JSON.stringify(hash.substr(0, length)), length);
return this.hooks.currentHash.call(
JSON.stringify(hash.substr(0, length)),
length
);
}
getPublicPath(options) {
return this.hooks.assetPath.call(this.outputOptions.publicPath || "", options);
return this.hooks.assetPath.call(
this.outputOptions.publicPath || "",
options
);
}
getAssetPath(path, options) {

View File

@ -24,7 +24,6 @@ const sortByDebugId = (a, b) => {
};
class Module extends DependenciesBlock {
constructor(type, context = null) {
super();
this.type = type;
@ -71,11 +70,11 @@ class Module extends DependenciesBlock {
}
get exportsArgument() {
return this.buildInfo && this.buildInfo.exportsArgument || "exports";
return (this.buildInfo && this.buildInfo.exportsArgument) || "exports";
}
get moduleArgument() {
return this.buildInfo && this.buildInfo.moduleArgument || "module";
return (this.buildInfo && this.buildInfo.moduleArgument) || "module";
}
disconnect() {
@ -115,14 +114,13 @@ class Module extends DependenciesBlock {
}
addChunk(chunk) {
if(this._chunks.has(chunk))
return false;
if (this._chunks.has(chunk)) return false;
this._chunks.add(chunk);
return true;
}
removeChunk(chunk) {
if(this._chunks.delete(chunk)) {
if (this._chunks.delete(chunk)) {
chunk.removeModule(this);
return true;
}
@ -134,15 +132,17 @@ class Module extends DependenciesBlock {
}
isEntryModule() {
for(const chunk of this._chunks) {
if(chunk.entryModule === this)
return true;
for (const chunk of this._chunks) {
if (chunk.entryModule === this) return true;
}
return false;
}
get optional() {
return this.reasons.length > 0 && this.reasons.every(r => r.dependency && r.dependency.optional);
return (
this.reasons.length > 0 &&
this.reasons.every(r => r.dependency && r.dependency.optional)
);
}
getChunks() {
@ -158,16 +158,17 @@ class Module extends DependenciesBlock {
}
hasEqualsChunks(otherModule) {
if(this._chunks.size !== otherModule._chunks.size) return false;
if (this._chunks.size !== otherModule._chunks.size) return false;
this._chunks.sortWith(sortByDebugId);
otherModule._chunks.sortWith(sortByDebugId);
const a = this._chunks[Symbol.iterator]();
const b = otherModule._chunks[Symbol.iterator]();
while(true) { // eslint-disable-line
while (true) {
// eslint-disable-line
const aItem = a.next();
const bItem = b.next();
if(aItem.done) return true;
if(aItem.value !== bItem.value) return false;
if (aItem.done) return true;
if (aItem.value !== bItem.value) return false;
}
}
@ -176,9 +177,9 @@ class Module extends DependenciesBlock {
}
removeReason(module, dependency) {
for(let i = 0; i < this.reasons.length; i++) {
for (let i = 0; i < this.reasons.length; i++) {
let r = this.reasons[i];
if(r.module === module && r.dependency === dependency) {
if (r.module === module && r.dependency === dependency) {
this.reasons.splice(i, 1);
return true;
}
@ -187,14 +188,13 @@ class Module extends DependenciesBlock {
}
hasReasonForChunk(chunk) {
if(this._rewriteChunkInReasons) {
for(const operation of this._rewriteChunkInReasons)
if (this._rewriteChunkInReasons) {
for (const operation of this._rewriteChunkInReasons)
this._doRewriteChunkInReasons(operation.oldChunk, operation.newChunks);
this._rewriteChunkInReasons = undefined;
}
for(let i = 0; i < this.reasons.length; i++) {
if(this.reasons[i].hasChunk(chunk))
return true;
for (let i = 0; i < this.reasons.length; i++) {
if (this.reasons[i].hasChunk(chunk)) return true;
}
return false;
}
@ -205,7 +205,7 @@ class Module extends DependenciesBlock {
rewriteChunkInReasons(oldChunk, newChunks) {
// This is expensive. Delay operation until we really need the data
if(this._rewriteChunkInReasons === undefined)
if (this._rewriteChunkInReasons === undefined)
this._rewriteChunkInReasons = [];
this._rewriteChunkInReasons.push({
oldChunk,
@ -214,33 +214,35 @@ class Module extends DependenciesBlock {
}
_doRewriteChunkInReasons(oldChunk, newChunks) {
for(let i = 0; i < this.reasons.length; i++) {
for (let i = 0; i < this.reasons.length; i++) {
this.reasons[i].rewriteChunks(oldChunk, newChunks);
}
}
isUsed(exportName) {
if(!exportName) return this.used !== false;
if(this.used === null || this.usedExports === null) return exportName;
if(!this.used) return false;
if(!this.usedExports) return false;
if(this.usedExports === true) return exportName;
if (!exportName) return this.used !== false;
if (this.used === null || this.usedExports === null) return exportName;
if (!this.used) return false;
if (!this.usedExports) return false;
if (this.usedExports === true) return exportName;
let idx = this.usedExports.indexOf(exportName);
if(idx < 0) return false;
if (idx < 0) return false;
// Mangle export name if possible
if(this.isProvided(exportName)) {
if(this.buildMeta.exportsType === "namespace")
if (this.isProvided(exportName)) {
if (this.buildMeta.exportsType === "namespace")
return Template.numberToIdentifer(idx);
else if(this.buildMeta.exportsType === "named" && !this.usedExports.includes("default"))
else if (
this.buildMeta.exportsType === "named" &&
!this.usedExports.includes("default")
)
return Template.numberToIdentifer(idx);
}
return exportName;
}
isProvided(exportName) {
if(!Array.isArray(this.buildMeta.providedExports))
return null;
if (!Array.isArray(this.buildMeta.providedExports)) return null;
return this.buildMeta.providedExports.includes(exportName);
}
@ -260,15 +262,14 @@ class Module extends DependenciesBlock {
sortItems(sortChunks) {
super.sortItems();
if(sortChunks)
this._chunks.sort();
if (sortChunks) this._chunks.sort();
this.reasons.sort((a, b) => {
if(a.module === b.module) return 0;
if(!a.module) return -1;
if(!b.module) return 1;
if (a.module === b.module) return 0;
if (!a.module) return -1;
if (!b.module) return 1;
return sortById(a.module, b.module);
});
if(Array.isArray(this.usedExports)) {
if (Array.isArray(this.usedExports)) {
this.usedExports.sort();
}
}
@ -326,7 +327,7 @@ Object.defineProperty(Module.prototype, "meta", {
}, "Module.meta was renamed to Module.buildMeta"),
set: util.deprecate(function(value) {
this.buildMeta = value;
}, "Module.meta was renamed to Module.buildMeta"),
}, "Module.meta was renamed to Module.buildMeta")
});
Module.prototype.identifier = null;

View File

@ -13,20 +13,20 @@ class ModuleBuildError extends WebpackError {
this.name = "ModuleBuildError";
this.message = "Module build failed: ";
if(err !== null && typeof err === "object") {
if(typeof err.stack === "string" && err.stack) {
if (err !== null && typeof err === "object") {
if (typeof err.stack === "string" && err.stack) {
var stack = cutOffLoaderExecution(err.stack);
if(!err.hideStack) {
if (!err.hideStack) {
this.message += stack;
} else {
this.details = stack;
if(typeof err.message === "string" && err.message) {
if (typeof err.message === "string" && err.message) {
this.message += err.message;
} else {
this.message += err;
}
}
} else if(typeof err.message === "string" && err.message) {
} else if (typeof err.message === "string" && err.message) {
this.message += err.message;
} else {
this.message += err;

View File

@ -13,7 +13,10 @@ module.exports = class ModuleDependencyError extends WebpackError {
this.name = "ModuleDependencyError";
this.message = `${formatLocation(loc)} ${err.message}`;
this.details = err.stack.split("\n").slice(1).join("\n");
this.details = err.stack
.split("\n")
.slice(1)
.join("\n");
this.origin = this.module = module;
this.error = err;

View File

@ -13,7 +13,10 @@ module.exports = class ModuleDependencyWarning extends WebpackError {
this.name = "ModuleDependencyWarning";
this.message = `${formatLocation(loc)} ${err.message}`;
this.details = err.stack.split("\n").slice(1).join("\n");
this.details = err.stack
.split("\n")
.slice(1)
.join("\n");
this.origin = this.module = module;
this.error = err;

View File

@ -13,9 +13,13 @@ class ModuleError extends WebpackError {
this.name = "ModuleError";
this.module = module;
this.message = err && typeof err === "object" && err.message ? err.message : err;
this.message =
err && typeof err === "object" && err.message ? err.message : err;
this.error = err;
this.details = err && typeof err === "object" && err.stack ? cleanUp(err.stack, this.message) : undefined;
this.details =
err && typeof err === "object" && err.stack
? cleanUp(err.stack, this.message)
: undefined;
Error.captureStackTrace(this, this.constructor);
}

View File

@ -48,25 +48,31 @@ const getHash = str => {
};
const asRegExp = test => {
if(typeof test === "string") test = new RegExp("^" + test.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"));
if (typeof test === "string")
test = new RegExp("^" + test.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"));
return test;
};
ModuleFilenameHelpers.createFilename = (module, options, requestShortener) => {
const opts = Object.assign({
namespace: "",
moduleFilenameTemplate: ""
}, typeof options === "object" ? options : {
moduleFilenameTemplate: options
});
const opts = Object.assign(
{
namespace: "",
moduleFilenameTemplate: ""
},
typeof options === "object"
? options
: {
moduleFilenameTemplate: options
}
);
let absoluteResourcePath;
let hash;
let identifier;
let moduleId;
let shortIdentifier;
if(module === undefined) module = "";
if(typeof module === "string") {
if (module === undefined) module = "";
if (typeof module === "string") {
shortIdentifier = requestShortener.shorten(module);
identifier = shortIdentifier;
moduleId = "";
@ -76,7 +82,10 @@ ModuleFilenameHelpers.createFilename = (module, options, requestShortener) => {
shortIdentifier = module.readableIdentifier(requestShortener);
identifier = requestShortener.shorten(module.identifier());
moduleId = module.id;
absoluteResourcePath = module.identifier().split("!").pop();
absoluteResourcePath = module
.identifier()
.split("!")
.pop();
hash = getHash(identifier);
}
const resource = shortIdentifier.split("!").pop();
@ -84,7 +93,7 @@ ModuleFilenameHelpers.createFilename = (module, options, requestShortener) => {
const allLoaders = getBefore(identifier, "!");
const query = getAfter(resource, "?");
const resourcePath = resource.substr(0, resource.length - query.length);
if(typeof opts.moduleFilenameTemplate === "function") {
if (typeof opts.moduleFilenameTemplate === "function") {
return opts.moduleFilenameTemplate({
identifier: identifier,
shortIdentifier: shortIdentifier,
@ -103,7 +112,10 @@ ModuleFilenameHelpers.createFilename = (module, options, requestShortener) => {
.replace(ModuleFilenameHelpers.REGEXP_LOADERS_RESOURCE, shortIdentifier)
.replace(ModuleFilenameHelpers.REGEXP_RESOURCE, resource)
.replace(ModuleFilenameHelpers.REGEXP_RESOURCE_PATH, resourcePath)
.replace(ModuleFilenameHelpers.REGEXP_ABSOLUTE_RESOURCE_PATH, absoluteResourcePath)
.replace(
ModuleFilenameHelpers.REGEXP_ABSOLUTE_RESOURCE_PATH,
absoluteResourcePath
)
.replace(ModuleFilenameHelpers.REGEXP_ALL_LOADERS, allLoaders)
.replace(ModuleFilenameHelpers.REGEXP_LOADERS, loaders)
.replace(ModuleFilenameHelpers.REGEXP_QUERY, query)
@ -116,28 +128,27 @@ ModuleFilenameHelpers.replaceDuplicates = (array, fn, comparator) => {
const countMap = Object.create(null);
const posMap = Object.create(null);
array.forEach((item, idx) => {
countMap[item] = (countMap[item] || []);
countMap[item] = countMap[item] || [];
countMap[item].push(idx);
posMap[item] = 0;
});
if(comparator) {
if (comparator) {
Object.keys(countMap).forEach(item => {
countMap[item].sort(comparator);
});
}
return array.map((item, i) => {
if(countMap[item].length > 1) {
if(comparator && countMap[item][0] === i)
return item;
if (countMap[item].length > 1) {
if (comparator && countMap[item][0] === i) return item;
return fn(item, i, posMap[item]++);
} else return item;
});
};
ModuleFilenameHelpers.matchPart = (str, test) => {
if(!test) return true;
if (!test) return true;
test = asRegExp(test);
if(Array.isArray(test)) {
if (Array.isArray(test)) {
return test.map(asRegExp).some(regExp => regExp.test(str));
} else {
return test.test(str);
@ -145,11 +156,11 @@ ModuleFilenameHelpers.matchPart = (str, test) => {
};
ModuleFilenameHelpers.matchObject = (obj, str) => {
if(obj.test)
if(!ModuleFilenameHelpers.matchPart(str, obj.test)) return false;
if(obj.include)
if(!ModuleFilenameHelpers.matchPart(str, obj.include)) return false;
if(obj.exclude)
if(ModuleFilenameHelpers.matchPart(str, obj.exclude)) return false;
if (obj.test)
if (!ModuleFilenameHelpers.matchPart(str, obj.test)) return false;
if (obj.include)
if (!ModuleFilenameHelpers.matchPart(str, obj.include)) return false;
if (obj.exclude)
if (ModuleFilenameHelpers.matchPart(str, obj.exclude)) return false;
return true;
};

View File

@ -12,14 +12,24 @@ class ModuleParseError extends WebpackError {
this.name = "ModuleParseError";
this.message = "Module parse failed: " + err.message;
this.message += "\nYou may need an appropriate loader to handle this file type.";
if(err.loc && typeof err.loc === "object" && typeof err.loc.line === "number") {
this.message +=
"\nYou may need an appropriate loader to handle this file type.";
if (
err.loc &&
typeof err.loc === "object" &&
typeof err.loc.line === "number"
) {
var lineNumber = err.loc.line;
if(/[\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007]/.test(source)) { // binary file
if (/[\0\u0001\u0002\u0003\u0004\u0005\u0006\u0007]/.test(source)) {
// binary file
this.message += "\n(Source code omitted for this binary file)";
} else {
source = source.split("\n");
this.message += "\n| " + source.slice(Math.max(0, lineNumber - 3), lineNumber + 2).join("\n| ");
this.message +=
"\n| " +
source
.slice(Math.max(0, lineNumber - 3), lineNumber + 2)
.join("\n| ");
}
} else {
this.message += "\n" + err.stack;

View File

@ -13,27 +13,24 @@ class ModuleReason {
}
hasChunk(chunk) {
if(this._chunks) {
if(this._chunks.has(chunk))
return true;
} else if(this.module && this.module._chunks.has(chunk))
return true;
if (this._chunks) {
if (this._chunks.has(chunk)) return true;
} else if (this.module && this.module._chunks.has(chunk)) return true;
return false;
}
rewriteChunks(oldChunk, newChunks) {
if(!this._chunks) {
if(this.module) {
if(!this.module._chunks.has(oldChunk))
return;
if (!this._chunks) {
if (this.module) {
if (!this.module._chunks.has(oldChunk)) return;
this._chunks = new Set(this.module._chunks);
} else {
this._chunks = new Set();
}
}
if(this._chunks.has(oldChunk)) {
if (this._chunks.has(oldChunk)) {
this._chunks.delete(oldChunk);
for(let i = 0; i < newChunks.length; i++) {
for (let i = 0; i < newChunks.length; i++) {
this._chunks.add(newChunks[i]);
}
}

View File

@ -13,20 +13,63 @@ module.exports = class ModuleTemplate extends Tapable {
super();
this.runtimeTemplate = runtimeTemplate;
this.hooks = {
content: new SyncWaterfallHook(["source", "module", "options", "dependencyTemplates"]),
module: new SyncWaterfallHook(["source", "module", "options", "dependencyTemplates"]),
render: new SyncWaterfallHook(["source", "module", "options", "dependencyTemplates"]),
package: new SyncWaterfallHook(["source", "module", "options", "dependencyTemplates"]),
content: new SyncWaterfallHook([
"source",
"module",
"options",
"dependencyTemplates"
]),
module: new SyncWaterfallHook([
"source",
"module",
"options",
"dependencyTemplates"
]),
render: new SyncWaterfallHook([
"source",
"module",
"options",
"dependencyTemplates"
]),
package: new SyncWaterfallHook([
"source",
"module",
"options",
"dependencyTemplates"
]),
hash: new SyncHook(["hash"])
};
}
render(module, dependencyTemplates, options) {
const moduleSource = module.source(dependencyTemplates, this.runtimeTemplate);
const moduleSourcePostContent = this.hooks.content.call(moduleSource, module, options, dependencyTemplates);
const moduleSourcePostModule = this.hooks.module.call(moduleSourcePostContent, module, options, dependencyTemplates);
const moduleSourcePostRender = this.hooks.render.call(moduleSourcePostModule, module, options, dependencyTemplates);
return this.hooks.package.call(moduleSourcePostRender, module, options, dependencyTemplates);
const moduleSource = module.source(
dependencyTemplates,
this.runtimeTemplate
);
const moduleSourcePostContent = this.hooks.content.call(
moduleSource,
module,
options,
dependencyTemplates
);
const moduleSourcePostModule = this.hooks.module.call(
moduleSourcePostContent,
module,
options,
dependencyTemplates
);
const moduleSourcePostRender = this.hooks.render.call(
moduleSourcePostModule,
module,
options,
dependencyTemplates
);
return this.hooks.package.call(
moduleSourcePostRender,
module,
options,
dependencyTemplates
);
}
updateHash(hash) {

View File

@ -13,9 +13,15 @@ class ModuleWarning extends WebpackError {
this.name = "ModuleWarning";
this.module = module;
this.message = warning && typeof warning === "object" && warning.message ? warning.message : warning;
this.message =
warning && typeof warning === "object" && warning.message
? warning.message
: warning;
this.warning = warning;
this.details = warning && typeof warning === "object" && warning.stack ? cleanUp(warning.stack, this.message) : undefined;
this.details =
warning && typeof warning === "object" && warning.stack
? cleanUp(warning.stack, this.message)
: undefined;
Error.captureStackTrace(this, this.constructor);
}

View File

@ -21,8 +21,8 @@ module.exports = class MultiCompiler extends Tapable {
watchClose: new SyncHook([]),
watchRun: new MultiHook(compilers.map(c => c.hooks.watchRun))
};
if(!Array.isArray(compilers)) {
compilers = Object.keys(compilers).map((name) => {
if (!Array.isArray(compilers)) {
compilers = Object.keys(compilers).map(name => {
compilers[name].name = name;
return compilers[name];
});
@ -31,21 +31,23 @@ module.exports = class MultiCompiler extends Tapable {
let doneCompilers = 0;
let compilerStats = [];
let index = 0;
for(const compiler of this.compilers) {
for (const compiler of this.compilers) {
let compilerDone = false;
const compilerIndex = index++;
compiler.hooks.done.tap("MultiCompiler", stats => { // eslint-disable-line no-loop-func
if(!compilerDone) {
compiler.hooks.done.tap("MultiCompiler", stats => {
// eslint-disable-line no-loop-func
if (!compilerDone) {
compilerDone = true;
doneCompilers++;
}
compilerStats[compilerIndex] = stats;
if(doneCompilers === this.compilers.length) {
if (doneCompilers === this.compilers.length) {
this.hooks.done.call(new MultiStats(compilerStats));
}
});
compiler.hooks.invalid.tap("MultiCompiler", () => { // eslint-disable-line no-loop-func
if(compilerDone) {
compiler.hooks.invalid.tap("MultiCompiler", () => {
// eslint-disable-line no-loop-func
if (compilerDone) {
compilerDone = false;
doneCompilers--;
}
@ -55,13 +57,16 @@ module.exports = class MultiCompiler extends Tapable {
get outputPath() {
let commonPath = this.compilers[0].outputPath;
for(const compiler of this.compilers) {
while(compiler.outputPath.indexOf(commonPath) !== 0 && /[/\\]/.test(commonPath)) {
for (const compiler of this.compilers) {
while (
compiler.outputPath.indexOf(commonPath) !== 0 &&
/[/\\]/.test(commonPath)
) {
commonPath = commonPath.replace(/[/\\][^/\\]*$/, "");
}
}
if(!commonPath && this.compilers[0].outputPath[0] === "/") return "/";
if (!commonPath && this.compilers[0].outputPath[0] === "/") return "/";
return commonPath;
}
@ -74,13 +79,13 @@ module.exports = class MultiCompiler extends Tapable {
}
set inputFileSystem(value) {
for(const compiler of this.compilers) {
for (const compiler of this.compilers) {
compiler.inputFileSystem = value;
}
}
set outputFileSystem(value) {
for(const compiler of this.compilers) {
for (const compiler of this.compilers) {
compiler.outputFileSystem = value;
}
}
@ -88,23 +93,25 @@ module.exports = class MultiCompiler extends Tapable {
validateDependencies(callback) {
const edges = new Set();
const missing = [];
const targetFound = (compiler) => {
for(const edge of edges) {
if(edge.target === compiler) {
const targetFound = compiler => {
for (const edge of edges) {
if (edge.target === compiler) {
return true;
}
}
return false;
};
const sortEdges = (e1, e2) => {
return e1.source.name.localeCompare(e2.source.name) ||
e1.target.name.localeCompare(e2.target.name);
return (
e1.source.name.localeCompare(e2.source.name) ||
e1.target.name.localeCompare(e2.target.name)
);
};
for(const source of this.compilers) {
if(source.dependencies) {
for(const dep of source.dependencies) {
const target = this.compilers.find((c) => c.name === dep);
if(!target) {
for (const source of this.compilers) {
if (source.dependencies) {
for (const dep of source.dependencies) {
const target = this.compilers.find(c => c.name === dep);
if (!target) {
missing.push(dep);
} else {
edges.add({
@ -115,26 +122,28 @@ module.exports = class MultiCompiler extends Tapable {
}
}
}
const errors = missing.map((m) => `Compiler dependency \`${m}\` not found.`);
const stack = this.compilers.filter((c) => !targetFound(c));
while(stack.length > 0) {
const errors = missing.map(m => `Compiler dependency \`${m}\` not found.`);
const stack = this.compilers.filter(c => !targetFound(c));
while (stack.length > 0) {
const current = stack.pop();
for(const edge of edges) {
if(edge.source === current) {
for (const edge of edges) {
if (edge.source === current) {
edges.delete(edge);
const target = edge.target;
if(!targetFound(target)) {
if (!targetFound(target)) {
stack.push(target);
}
}
}
}
if(edges.size > 0) {
const lines = Array.from(edges).sort(sortEdges).map(edge => `${edge.source.name} -> ${edge.target.name}`);
if (edges.size > 0) {
const lines = Array.from(edges)
.sort(sortEdges)
.map(edge => `${edge.source.name} -> ${edge.target.name}`);
lines.unshift("Circular dependency found in compiler dependencies.");
errors.unshift(lines.join("\n"));
}
if(errors.length > 0) {
if (errors.length > 0) {
const message = errors.join("\n");
callback(new Error(message));
return false;
@ -145,29 +154,32 @@ module.exports = class MultiCompiler extends Tapable {
runWithDependencies(compilers, fn, callback) {
const fulfilledNames = new Set();
let remainingCompilers = compilers;
const isDependencyFulfilled = (d) => fulfilledNames.has(d);
const isDependencyFulfilled = d => fulfilledNames.has(d);
const getReadyCompilers = () => {
let readyCompilers = [];
let list = remainingCompilers;
remainingCompilers = [];
for(const c of list) {
const ready = !c.dependencies || c.dependencies.every(isDependencyFulfilled);
if(ready)
readyCompilers.push(c);
else
remainingCompilers.push(c);
for (const c of list) {
const ready =
!c.dependencies || c.dependencies.every(isDependencyFulfilled);
if (ready) readyCompilers.push(c);
else remainingCompilers.push(c);
}
return readyCompilers;
};
const runCompilers = (callback) => {
if(remainingCompilers.length === 0) return callback();
asyncLib.map(getReadyCompilers(), (compiler, callback) => {
fn(compiler, (err) => {
if(err) return callback(err);
fulfilledNames.add(compiler.name);
runCompilers(callback);
});
}, callback);
const runCompilers = callback => {
if (remainingCompilers.length === 0) return callback();
asyncLib.map(
getReadyCompilers(),
(compiler, callback) => {
fn(compiler, err => {
if (err) return callback(err);
fulfilledNames.add(compiler.name);
runCompilers(callback);
});
},
callback
);
};
runCompilers(callback);
}
@ -176,34 +188,42 @@ module.exports = class MultiCompiler extends Tapable {
let watchings = [];
let allStats = this.compilers.map(() => null);
let compilerStatus = this.compilers.map(() => false);
if(this.validateDependencies(handler)) {
this.runWithDependencies(this.compilers, (compiler, callback) => {
const compilerIdx = this.compilers.indexOf(compiler);
let firstRun = true;
let watching = compiler.watch(Array.isArray(watchOptions) ? watchOptions[compilerIdx] : watchOptions, (err, stats) => {
if(err)
handler(err);
if(stats) {
allStats[compilerIdx] = stats;
compilerStatus[compilerIdx] = "new";
if(compilerStatus.every(Boolean)) {
const freshStats = allStats.filter((s, idx) => {
return compilerStatus[idx] === "new";
});
compilerStatus.fill(true);
const multiStats = new MultiStats(freshStats);
handler(null, multiStats);
if (this.validateDependencies(handler)) {
this.runWithDependencies(
this.compilers,
(compiler, callback) => {
const compilerIdx = this.compilers.indexOf(compiler);
let firstRun = true;
let watching = compiler.watch(
Array.isArray(watchOptions)
? watchOptions[compilerIdx]
: watchOptions,
(err, stats) => {
if (err) handler(err);
if (stats) {
allStats[compilerIdx] = stats;
compilerStatus[compilerIdx] = "new";
if (compilerStatus.every(Boolean)) {
const freshStats = allStats.filter((s, idx) => {
return compilerStatus[idx] === "new";
});
compilerStatus.fill(true);
const multiStats = new MultiStats(freshStats);
handler(null, multiStats);
}
}
if (firstRun && !err) {
firstRun = false;
callback();
}
}
}
if(firstRun && !err) {
firstRun = false;
callback();
}
});
watchings.push(watching);
}, () => {
// ignore
});
);
watchings.push(watching);
},
() => {
// ignore
}
);
}
return new MultiWatching(watchings, this);
@ -211,24 +231,28 @@ module.exports = class MultiCompiler extends Tapable {
run(callback) {
const allStats = this.compilers.map(() => null);
if(this.validateDependencies(callback)) {
this.runWithDependencies(this.compilers, ((compiler, callback) => {
const compilerIdx = this.compilers.indexOf(compiler);
compiler.run((err, stats) => {
if(err) return callback(err);
allStats[compilerIdx] = stats;
callback();
});
}), (err) => {
if(err) return callback(err);
callback(null, new MultiStats(allStats));
});
if (this.validateDependencies(callback)) {
this.runWithDependencies(
this.compilers,
(compiler, callback) => {
const compilerIdx = this.compilers.indexOf(compiler);
compiler.run((err, stats) => {
if (err) return callback(err);
allStats[compilerIdx] = stats;
callback();
});
},
err => {
if (err) return callback(err);
callback(null, new MultiStats(allStats));
}
);
}
}
purgeInputFileSystem() {
for(const compiler of this.compilers) {
if(compiler.inputFileSystem && compiler.inputFileSystem.purge)
for (const compiler of this.compilers) {
if (compiler.inputFileSystem && compiler.inputFileSystem.purge)
compiler.inputFileSystem.purge();
}
}

View File

@ -16,34 +16,43 @@ module.exports = class MultiEntryPlugin {
}
apply(compiler) {
compiler.hooks.compilation.tap("MultiEntryPlugin", (compilation, {
normalModuleFactory
}) => {
const multiModuleFactory = new MultiModuleFactory();
compiler.hooks.compilation.tap(
"MultiEntryPlugin",
(compilation, { normalModuleFactory }) => {
const multiModuleFactory = new MultiModuleFactory();
compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory);
compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);
});
compilation.dependencyFactories.set(
MultiEntryDependency,
multiModuleFactory
);
compilation.dependencyFactories.set(
SingleEntryDependency,
normalModuleFactory
);
}
);
compiler.hooks.make.tapAsync("MultiEntryPlugin", (compilation, callback) => {
const {
context,
entries,
name
} = this;
compiler.hooks.make.tapAsync(
"MultiEntryPlugin",
(compilation, callback) => {
const { context, entries, name } = this;
const dep = MultiEntryPlugin.createDependency(entries, name);
compilation.addEntry(context, dep, name, callback);
});
const dep = MultiEntryPlugin.createDependency(entries, name);
compilation.addEntry(context, dep, name, callback);
}
);
}
static createDependency(entries, name) {
return new MultiEntryDependency(entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
// Because entrypoints are not dependencies found in an
// existing module, we give it a synthetic id
dep.loc = `${name}:${100000 + idx}`;
return dep;
}), name);
return new MultiEntryDependency(
entries.map((e, idx) => {
const dep = new SingleEntryDependency(e);
// Because entrypoints are not dependencies found in an
// existing module, we give it a synthetic id
dep.loc = `${name}:${100000 + idx}`;
return dep;
}),
name
);
}
};

Some files were not shown because too many files have changed in this diff Show More