webpack/lib/ContextReplacementPlugin.js

203 lines
6.8 KiB
JavaScript
Raw Normal View History

2013-01-31 09:33:11 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
2017-03-11 01:27:53 +08:00
"use strict";
2017-03-11 01:27:53 +08:00
const ContextElementDependency = require("./dependencies/ContextElementDependency");
const { join } = require("./util/fs");
2017-03-11 01:27:53 +08:00
2023-06-17 06:33:17 +08:00
/** @typedef {import("./Compiler")} Compiler */
2025-03-11 08:28:01 +08:00
/** @typedef {import("./ContextModule").ContextModuleOptions} ContextModuleOptions */
2024-03-12 00:33:52 +08:00
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
2023-06-17 06:33:17 +08:00
2025-03-11 08:28:01 +08:00
/** @typedef {Record<string, string>} NewContentCreateContextMap */
2025-04-23 20:03:37 +08:00
const PLUGIN_NAME = "ContextReplacementPlugin";
2017-03-11 01:27:53 +08:00
class ContextReplacementPlugin {
2023-06-17 06:33:17 +08:00
/**
* @param {RegExp} resourceRegExp A regular expression that determines which files will be selected
2025-03-11 08:28:01 +08:00
* @param {(string | ((context: TODO) => void) | RegExp | boolean)=} newContentResource A new resource to replace the match
* @param {(boolean | NewContentCreateContextMap | RegExp)=} newContentRecursive If true, all subdirectories are searched for matches
2024-08-15 02:38:08 +08:00
* @param {RegExp=} newContentRegExp A regular expression that determines which files will be selected
2023-06-17 06:33:17 +08:00
*/
2018-02-25 09:00:20 +08:00
constructor(
resourceRegExp,
newContentResource,
newContentRecursive,
newContentRegExp
) {
2017-03-11 01:27:53 +08:00
this.resourceRegExp = resourceRegExp;
2025-03-11 08:28:01 +08:00
// new webpack.ContextReplacementPlugin(/selector/, (context) => { /* Logic */ });
2018-02-25 09:00:20 +08:00
if (typeof newContentResource === "function") {
2017-03-11 01:27:53 +08:00
this.newContentCallback = newContentResource;
2025-03-11 08:28:01 +08:00
}
// new ContextReplacementPlugin(/selector/, './folder', { './request': './request' });
else if (
2018-02-25 09:00:20 +08:00
typeof newContentResource === "string" &&
typeof newContentRecursive === "object"
) {
2017-03-11 01:27:53 +08:00
this.newContentResource = newContentResource;
2025-03-11 08:28:01 +08:00
/**
* @param {InputFileSystem} fs input file system
* @param {(err: null | Error, newContentRecursive: NewContentCreateContextMap) => void} callback callback
*/
2017-03-11 01:27:53 +08:00
this.newContentCreateContextMap = (fs, callback) => {
2025-03-11 08:28:01 +08:00
callback(
null,
/** @type {NewContentCreateContextMap} */ (newContentRecursive)
);
2017-03-11 01:27:53 +08:00
};
2025-03-11 08:28:01 +08:00
}
// new ContextReplacementPlugin(/selector/, './folder', (context) => { /* Logic */ });
else if (
2018-02-25 09:00:20 +08:00
typeof newContentResource === "string" &&
typeof newContentRecursive === "function"
) {
2017-03-11 01:27:53 +08:00
this.newContentResource = newContentResource;
this.newContentCreateContextMap = newContentRecursive;
} else {
2025-03-11 08:28:01 +08:00
// new webpack.ContextReplacementPlugin(/selector/, false, /reg-exp/);
2018-02-25 09:00:20 +08:00
if (typeof newContentResource !== "string") {
2025-03-11 08:28:01 +08:00
newContentRegExp = /** @type {RegExp} */ (newContentRecursive);
newContentRecursive = /** @type {boolean} */ (newContentResource);
2017-03-11 01:27:53 +08:00
newContentResource = undefined;
}
2025-03-11 08:28:01 +08:00
// new webpack.ContextReplacementPlugin(/selector/, /de|fr|hu/);
2018-02-25 09:00:20 +08:00
if (typeof newContentRecursive !== "boolean") {
2025-03-11 08:28:01 +08:00
newContentRegExp = /** @type {RegExp} */ (newContentRecursive);
2017-03-11 01:27:53 +08:00
newContentRecursive = undefined;
}
2025-03-11 08:28:01 +08:00
// new webpack.ContextReplacementPlugin(/selector/, './folder', false, /selector/);
this.newContentResource =
/** @type {string | undefined} */
(newContentResource);
this.newContentRecursive =
/** @type {boolean | undefined} */
(newContentRecursive);
this.newContentRegExp =
/** @type {RegExp | undefined} */
(newContentRegExp);
2014-10-23 16:58:26 +08:00
}
}
2017-03-11 01:27:53 +08:00
2023-06-17 06:33:17 +08:00
/**
* Apply the plugin
* @param {Compiler} compiler the compiler instance
* @returns {void}
*/
2017-03-11 01:27:53 +08:00
apply(compiler) {
const resourceRegExp = this.resourceRegExp;
const newContentCallback = this.newContentCallback;
const newContentResource = this.newContentResource;
const newContentRecursive = this.newContentRecursive;
const newContentRegExp = this.newContentRegExp;
const newContentCreateContextMap = this.newContentCreateContextMap;
2025-04-23 20:03:37 +08:00
compiler.hooks.contextModuleFactory.tap(PLUGIN_NAME, cmf => {
cmf.hooks.beforeResolve.tap(PLUGIN_NAME, result => {
2018-02-25 09:00:20 +08:00
if (!result) return;
if (resourceRegExp.test(result.request)) {
if (newContentResource !== undefined) {
2017-03-11 01:27:53 +08:00
result.request = newContentResource;
}
if (newContentRecursive !== undefined) {
2017-03-11 01:27:53 +08:00
result.recursive = newContentRecursive;
}
if (newContentRegExp !== undefined) {
2017-03-11 01:27:53 +08:00
result.regExp = newContentRegExp;
}
2018-02-25 09:00:20 +08:00
if (typeof newContentCallback === "function") {
2017-03-11 01:27:53 +08:00
newContentCallback(result);
} else {
2018-02-25 09:00:20 +08:00
for (const d of result.dependencies) {
if (d.critical) d.critical = false;
2018-01-22 20:52:43 +08:00
}
2017-03-11 01:27:53 +08:00
}
2014-10-23 16:58:26 +08:00
}
return result;
2017-03-11 01:27:53 +08:00
});
2025-04-23 20:03:37 +08:00
cmf.hooks.afterResolve.tap(PLUGIN_NAME, result => {
2018-02-25 09:00:20 +08:00
if (!result) return;
if (resourceRegExp.test(result.resource)) {
if (newContentResource !== undefined) {
if (
newContentResource.startsWith("/") ||
(newContentResource.length > 1 && newContentResource[1] === ":")
) {
result.resource = newContentResource;
} else {
result.resource = join(
2024-03-12 00:33:52 +08:00
/** @type {InputFileSystem} */ (compiler.inputFileSystem),
result.resource,
newContentResource
);
}
}
if (newContentRecursive !== undefined) {
2017-03-11 01:27:53 +08:00
result.recursive = newContentRecursive;
}
if (newContentRegExp !== undefined) {
2017-03-11 01:27:53 +08:00
result.regExp = newContentRegExp;
}
if (typeof newContentCreateContextMap === "function") {
2021-05-11 15:31:46 +08:00
result.resolveDependencies =
createResolveDependenciesFromContextMap(
newContentCreateContextMap
);
}
2018-02-25 09:00:20 +08:00
if (typeof newContentCallback === "function") {
2017-03-11 01:27:53 +08:00
const origResource = result.resource;
newContentCallback(result);
if (
result.resource !== origResource &&
!result.resource.startsWith("/") &&
(result.resource.length <= 1 || result.resource[1] !== ":")
) {
// When the function changed it to an relative path
result.resource = join(
2024-03-12 00:33:52 +08:00
/** @type {InputFileSystem} */ (compiler.inputFileSystem),
origResource,
result.resource
);
2017-03-11 01:27:53 +08:00
}
} else {
2018-02-25 09:00:20 +08:00
for (const d of result.dependencies) {
if (d.critical) d.critical = false;
2018-01-22 20:52:43 +08:00
}
2014-10-23 16:58:26 +08:00
}
}
return result;
2017-03-11 01:27:53 +08:00
});
2013-01-31 09:33:11 +08:00
});
2017-03-11 01:27:53 +08:00
}
}
2025-03-11 08:28:01 +08:00
/**
* @param {(fs: InputFileSystem, callback: (err: null | Error, map: NewContentCreateContextMap) => void) => void} createContextMap create context map function
* @returns {(fs: InputFileSystem, options: ContextModuleOptions, callback: (err: null | Error, dependencies?: ContextElementDependency[]) => void) => void} resolve resolve dependencies from context map function
*/
const createResolveDependenciesFromContextMap =
createContextMap => (fs, options, callback) => {
2017-03-11 01:27:53 +08:00
createContextMap(fs, (err, map) => {
2018-02-25 09:00:20 +08:00
if (err) return callback(err);
2024-07-31 11:31:11 +08:00
const dependencies = Object.keys(map).map(
key =>
new ContextElementDependency(
map[key] + options.resourceQuery + options.resourceFragment,
key,
2025-03-11 08:28:01 +08:00
options.typePrefix,
2025-04-26 01:43:01 +08:00
/** @type {string} */
(options.category),
2024-07-31 11:31:11 +08:00
options.referencedExports
)
);
callback(null, dependencies);
});
2017-01-11 17:51:58 +08:00
};
2017-03-11 01:27:53 +08:00
module.exports = ContextReplacementPlugin;