webpack/lib/sharing/ProvideSharedPlugin.js

186 lines
5.5 KiB
JavaScript
Raw Normal View History

2020-05-23 22:08:51 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra and Zackary Jackson @ScriptedAlchemy
*/
"use strict";
const validateOptions = require("schema-utils");
const schema = require("../../schemas/plugins/sharing/ProvideSharedPlugin.json");
const WebpackError = require("../WebpackError");
2020-05-23 22:08:51 +08:00
const { parseOptions } = require("../container/options");
const LazySet = require("../util/LazySet");
2020-05-23 22:08:51 +08:00
const ProvideDependency = require("./ProvideDependency");
const ProvideModuleFactory = require("./ProvideModuleFactory");
const ProvidedDependency = require("./ProvidedDependency");
2020-05-25 23:14:59 +08:00
const { parseVersion } = require("./utils");
2020-05-23 22:08:51 +08:00
/** @typedef {import("../../declarations/plugins/sharing/ProvideSharedPlugin").ProvideSharedPluginOptions} ProvideSharedPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
/**
* @typedef {Object} ProvideOptions
* @property {string} import
* @property {string} shareScope
* @property {(string|number)[] | undefined | false} version
* @property {boolean} eager
2020-05-23 22:08:51 +08:00
*/
class ProvideSharedPlugin {
/**
* @param {ProvideSharedPluginOptions} options options
*/
constructor(options) {
validateOptions(schema, options, { name: "Provide Shared Plugin" });
/** @type {[string, ProvideOptions][]} */
this._provides = parseOptions(
options.provides,
item => {
if (Array.isArray(item))
throw new Error("Unexpected array of provides");
/** @type {ProvideOptions} */
const result = {
2020-05-23 22:08:51 +08:00
import: item,
version: undefined,
shareScope: options.shareScope || "default",
eager: false
2020-05-23 22:08:51 +08:00
};
return result;
2020-05-23 22:08:51 +08:00
},
item => ({
import: item.import,
version:
typeof item.version === "string"
2020-05-25 23:14:59 +08:00
? parseVersion(item.version)
2020-05-23 22:08:51 +08:00
: item.version,
shareScope: item.shareScope || options.shareScope || "default",
eager: !!item.eager
2020-05-23 22:08:51 +08:00
})
);
this._provides.sort(([a], [b]) => {
if (a < b) return -1;
if (b < a) return 1;
return 0;
});
}
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
apply(compiler) {
const { _provides: provides } = this;
for (const [name, config] of provides) {
compiler.hooks.make.tapAsync(
"ProvideSharedPlugin",
(compilation, callback) => {
let version = config.version;
const addModule = () => {
compilation.addInclude(
compiler.context,
new ProvideDependency(
config.shareScope,
name,
2020-05-27 22:02:41 +08:00
version || false,
config.import,
config.eager
),
{
name: undefined
},
err => callback(err)
);
};
2020-05-27 22:02:41 +08:00
if (
version !== undefined ||
config.import.startsWith("./") ||
config.import.startsWith("../")
) {
return addModule();
}
const resolveContext = {
/** @type {LazySet<string>} */
fileDependencies: new LazySet(),
/** @type {LazySet<string>} */
contextDependencies: new LazySet(),
/** @type {LazySet<string>} */
missingDependencies: new LazySet()
};
const resolver = compiler.resolverFactory.get("normal");
resolver.resolve(
{},
2020-05-23 22:08:51 +08:00
compiler.context,
config.import,
resolveContext,
(err, result, additionalInfo) => {
compilation.fileDependencies.addAll(
resolveContext.fileDependencies
);
compilation.contextDependencies.addAll(
resolveContext.contextDependencies
);
compilation.missingDependencies.addAll(
resolveContext.missingDependencies
);
let details;
if (err) {
details = `Failed to resolve: ${err}.`;
} else if (!result) {
details = `Resolved to void.`;
} else if (!additionalInfo) {
details = `No additional info provided from resolver.`;
} else {
const info = /** @type {any} */ (additionalInfo);
const descriptionFileData = info.descriptionFileData;
if (!descriptionFileData) {
details =
"No description file (usually package.json) found. Add description file with name and version, or manually specify version in shared config.";
} else if (!descriptionFileData.version) {
details =
"No version in description file (usually package.json). Add version to description file, or manually specify version in shared config.";
} else if (
descriptionFileData.name &&
config.import !== descriptionFileData.name &&
!config.import.startsWith(`${descriptionFileData.name}/`)
) {
details = `Invalid name in description file (usually package.json): ${descriptionFileData.name}. Check location of description file, update name in description file, add missing description file to the package, or manually specify version in shared config.`;
} else {
version = parseVersion(descriptionFileData.version);
}
}
if (!version) {
const error = new WebpackError(
`No version specified and unable to automatically determine one. ${details}`
);
error.file = `shared module ${name} -> ${config.import}`;
compilation.warnings.push(error);
}
addModule();
}
2020-05-23 22:08:51 +08:00
);
}
);
}
compiler.hooks.compilation.tap(
"ProvideSharedPlugin",
(compilation, { normalModuleFactory }) => {
compilation.dependencyFactories.set(
ProvidedDependency,
normalModuleFactory
);
compilation.dependencyFactories.set(
ProvideDependency,
new ProvideModuleFactory()
);
}
);
}
}
module.exports = ProvideSharedPlugin;