2020-02-20 17:52:47 +08:00
|
|
|
/*
|
|
|
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
|
|
|
Author Tobias Koppers @sokra
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
2020-04-30 19:39:58 +08:00
|
|
|
const validateOptions = require("schema-utils");
|
|
|
|
|
const schema = require("../../schemas/plugins/container/OverridablesPlugin.json");
|
2020-02-20 17:52:47 +08:00
|
|
|
const ModuleNotFoundError = require("../ModuleNotFoundError");
|
|
|
|
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
2020-02-29 00:29:24 +08:00
|
|
|
const {
|
|
|
|
|
toConstantDependency,
|
|
|
|
|
evaluateToString
|
|
|
|
|
} = require("../javascript/JavascriptParserHelpers");
|
|
|
|
|
const LazySet = require("../util/LazySet");
|
2020-02-20 17:52:47 +08:00
|
|
|
const OverridableModule = require("./OverridableModule");
|
|
|
|
|
const OverridableOriginalDependency = require("./OverridableOriginalDependency");
|
|
|
|
|
const OverridablesRuntimeModule = require("./OverridablesRuntimeModule");
|
2020-02-25 04:12:45 +08:00
|
|
|
const parseOptions = require("./parseOptions");
|
2020-02-20 17:52:47 +08:00
|
|
|
|
2020-02-29 00:29:24 +08:00
|
|
|
/** @typedef {import("enhanced-resolve").ResolveContext} ResolveContext */
|
2020-04-30 19:39:58 +08:00
|
|
|
/** @typedef {import("../../declarations/plugins/container/OverridablesPlugin").OverridablesPluginOptions} OverridablesPluginOptions */
|
2020-02-20 17:52:47 +08:00
|
|
|
/** @typedef {import("../Compiler")} Compiler */
|
|
|
|
|
|
2020-04-30 19:39:58 +08:00
|
|
|
const PLUGIN_NAME = "OverridablesPlugin";
|
|
|
|
|
|
2020-02-20 17:52:47 +08:00
|
|
|
class OverridablesPlugin {
|
2020-04-30 19:39:58 +08:00
|
|
|
/**
|
|
|
|
|
* @param {OverridablesPluginOptions} options options
|
|
|
|
|
*/
|
2020-02-20 17:52:47 +08:00
|
|
|
constructor(options) {
|
2020-04-30 19:39:58 +08:00
|
|
|
if (typeof options !== "string") {
|
|
|
|
|
validateOptions(schema, options, { name: "Overridables Plugin" });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._overridables = parseOptions(options);
|
2020-02-20 17:52:47 +08:00
|
|
|
}
|
2020-04-30 19:39:58 +08:00
|
|
|
|
2020-02-20 17:52:47 +08:00
|
|
|
/**
|
2020-04-30 19:39:58 +08:00
|
|
|
* Apply the plugin
|
|
|
|
|
* @param {Compiler} compiler the compiler instance
|
2020-02-20 17:52:47 +08:00
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
apply(compiler) {
|
|
|
|
|
compiler.hooks.thisCompilation.tap(
|
2020-04-30 19:39:58 +08:00
|
|
|
PLUGIN_NAME,
|
2020-02-20 17:52:47 +08:00
|
|
|
(compilation, { normalModuleFactory }) => {
|
|
|
|
|
compilation.dependencyFactories.set(
|
|
|
|
|
OverridableOriginalDependency,
|
2020-04-17 08:41:51 +08:00
|
|
|
normalModuleFactory
|
2020-02-20 17:52:47 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const resolvedOverridables = new Map();
|
2020-02-29 00:29:24 +08:00
|
|
|
const resolveContext = {
|
|
|
|
|
/** @type {LazySet<string>} */
|
|
|
|
|
fileDependencies: new LazySet(),
|
|
|
|
|
/** @type {LazySet<string>} */
|
|
|
|
|
contextDependencies: new LazySet(),
|
|
|
|
|
/** @type {LazySet<string>} */
|
|
|
|
|
missingDependencies: new LazySet()
|
|
|
|
|
};
|
2020-02-20 17:52:47 +08:00
|
|
|
const promise = Promise.all(
|
2020-04-30 19:39:58 +08:00
|
|
|
this._overridables.map(([key, request]) => {
|
2020-02-20 17:52:47 +08:00
|
|
|
const resolver = compilation.resolverFactory.get("normal");
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
resolver.resolve(
|
|
|
|
|
{},
|
|
|
|
|
compiler.context,
|
|
|
|
|
request,
|
2020-02-29 00:29:24 +08:00
|
|
|
resolveContext,
|
2020-02-20 17:52:47 +08:00
|
|
|
(err, result) => {
|
|
|
|
|
if (err) {
|
|
|
|
|
compilation.errors.push(
|
|
|
|
|
new ModuleNotFoundError(null, err, {
|
|
|
|
|
name: `overridable ${key}`
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
return resolve();
|
|
|
|
|
}
|
|
|
|
|
resolvedOverridables.set(result, key);
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
})
|
2020-02-29 00:29:24 +08:00
|
|
|
).then(() => {
|
|
|
|
|
compilation.contextDependencies.addAll(
|
|
|
|
|
resolveContext.contextDependencies
|
|
|
|
|
);
|
|
|
|
|
compilation.fileDependencies.addAll(resolveContext.fileDependencies);
|
|
|
|
|
compilation.missingDependencies.addAll(
|
|
|
|
|
resolveContext.missingDependencies
|
|
|
|
|
);
|
|
|
|
|
});
|
2020-02-20 17:52:47 +08:00
|
|
|
normalModuleFactory.hooks.afterResolve.tapAsync(
|
2020-04-30 19:39:58 +08:00
|
|
|
PLUGIN_NAME,
|
2020-02-20 17:52:47 +08:00
|
|
|
(resolveData, callback) => {
|
|
|
|
|
// wait for resolving to be complete
|
|
|
|
|
promise.then(() => callback());
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
normalModuleFactory.hooks.module.tap(
|
2020-04-30 19:39:58 +08:00
|
|
|
PLUGIN_NAME,
|
2020-04-17 08:41:51 +08:00
|
|
|
(module, createData, resolveData) => {
|
|
|
|
|
if (
|
|
|
|
|
resolveData.dependencies[0] instanceof
|
|
|
|
|
OverridableOriginalDependency
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-02-20 17:52:47 +08:00
|
|
|
const key = resolvedOverridables.get(createData.resource);
|
2020-04-17 08:41:51 +08:00
|
|
|
if (key !== undefined) {
|
|
|
|
|
return new OverridableModule(
|
|
|
|
|
resolveData.context,
|
|
|
|
|
resolveData.request,
|
|
|
|
|
key
|
|
|
|
|
);
|
|
|
|
|
}
|
2020-02-20 17:52:47 +08:00
|
|
|
}
|
|
|
|
|
);
|
2020-02-27 05:32:48 +08:00
|
|
|
compilation.hooks.runtimeRequirementInTree
|
|
|
|
|
.for(RuntimeGlobals.ensureChunkHandlers)
|
2020-04-30 19:39:58 +08:00
|
|
|
.tap(PLUGIN_NAME, (chunk, set) => {
|
2020-02-20 17:52:47 +08:00
|
|
|
set.add(RuntimeGlobals.module);
|
2020-02-25 04:12:45 +08:00
|
|
|
set.add(RuntimeGlobals.moduleFactories);
|
2020-02-20 17:52:47 +08:00
|
|
|
set.add(RuntimeGlobals.hasOwnProperty);
|
|
|
|
|
compilation.addRuntimeModule(
|
|
|
|
|
chunk,
|
|
|
|
|
new OverridablesRuntimeModule()
|
|
|
|
|
);
|
2020-02-27 05:32:48 +08:00
|
|
|
});
|
2020-02-29 00:22:37 +08:00
|
|
|
const handler = parser => {
|
|
|
|
|
parser.hooks.expression
|
|
|
|
|
.for("__webpack_override__")
|
|
|
|
|
.tap(
|
2020-04-30 19:39:58 +08:00
|
|
|
PLUGIN_NAME,
|
2020-02-29 00:22:37 +08:00
|
|
|
toConstantDependency(
|
|
|
|
|
parser,
|
|
|
|
|
`Object.assign.bind(Object, ${RuntimeGlobals.overrides})`,
|
|
|
|
|
[RuntimeGlobals.overrides]
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
parser.hooks.evaluateTypeof
|
|
|
|
|
.for("__webpack_override__")
|
2020-04-30 19:39:58 +08:00
|
|
|
.tap(PLUGIN_NAME, evaluateToString("function"));
|
2020-02-29 00:22:37 +08:00
|
|
|
};
|
|
|
|
|
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);
|
2020-02-20 17:52:47 +08:00
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = OverridablesPlugin;
|