/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/dependencies/CommonJsImportsParserPlugin.js
881 строка
28 KB
Alexander Akait
perf: load webpack's own modules only when a build needs them (#21652)
10 авг 2026, 07:32
Не верифицирован
10 авг 2026, 07:32
8e28763
Код
Авторство
О чём код?
/* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ "use strict"; const RuntimeGlobals = require("../RuntimeGlobals"); const { evaluateToIdentifier, evaluateToString, expressionIsUnsupported, toConstantDependency } = require("../javascript/JavascriptParserHelpers"); const memoize = require("../util/memoize"); const traverseDestructuringAssignmentProperties = require("../util/traverseDestructuringAssignmentProperties"); const CommonJsFullRequireDependency = require("./CommonJsFullRequireDependency"); const CommonJsRequireContextDependency = require("./CommonJsRequireContextDependency"); const CommonJsRequireDependency = require("./CommonJsRequireDependency"); const ConstDependency = require("./ConstDependency"); const ContextDependencyHelpers = require("./ContextDependencyHelpers"); const HarmonyImportGuard = require("./HarmonyImportGuard"); const LocalModuleDependency = require("./LocalModuleDependency"); const { getLocalModule } = require("./LocalModulesHelpers"); const RequireHeaderDependency = require("./RequireHeaderDependency"); const RequireResolveContextDependency = require("./RequireResolveContextDependency"); const RequireResolveDependency = require("./RequireResolveDependency"); const RequireResolveHeaderDependency = require("./RequireResolveHeaderDependency"); const getUnsupportedFeatureWarning = memoize(() => require("../errors/UnsupportedFeatureWarning") ); const getCommentCompilationWarning = memoize(() => require("../errors/CommentCompilationWarning") ); /** @typedef {import("estree").CallExpression} CallExpression */ /** @typedef {import("estree").Expression} Expression */ /** @typedef {import("estree").NewExpression} NewExpression */ /** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */ /** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */ /** @typedef {import("../Dependency").RawReferencedExports} RawReferencedExports */ /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */ /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */ /** @typedef {import("../javascript/JavascriptParser").ImportSource} ImportSource */ /** @typedef {import("../javascript/JavascriptParser").Range} Range */ /** @typedef {import("../javascript/JavascriptParser").Members} Members */ /** @typedef {import("../javascript/JavascriptParser").CalleeMembers} CalleeMembers */ /** @typedef {import("./LocalModule")} LocalModule */ /** * Defines the common js import settings type used by this module. * @typedef {object} CommonJsImportSettings * @property {string=} name * @property {string} context */ /** * Per-`const NAME = require(LITERAL)` binding state used to forward * member-access references on `NAME` to the `CommonJsRequireDependency` * created for the `require()` call. * @typedef {object} RequireBindingData * @property {RawReferencedExports | null} referencedExports mutable list, pushed to as `NAME.x.y` accesses are walked; null means the whole namespace is used. Separate from `dep` so a deferred require (walked after accesses on `NAME`) still collects them; becomes the dep's shared list on creation. * @property {InstanceType<typeof import("./CommonJsRequireDependency")> | null} dep dependency for the `require()` call, null until the `require()` is walked; kept so a later whole-namespace use can null its list directly */ const REQUIRE_BINDING_TAG = Symbol( "CommonJsImportsParserPlugin require binding" ); const PLUGIN_NAME = "CommonJsImportsParserPlugin"; /** * Checks whether this object is require call expression. * @param {Expression} expression expression * @returns {boolean} true, when expression is `require(...)` or `module.require(...)` */ const isRequireCallExpression = (expression) => { if (expression.type !== "CallExpression") return false; const { callee } = expression; if (callee.type === "Identifier") { return callee.name === "require"; } if (callee.type === "MemberExpression" && !callee.computed) { const object = callee.object; const property = callee.property; return ( object.type === "Identifier" && object.name === "module" && property.type === "Identifier" && property.name === "require" ); } return false; }; /** * Gets require referenced exports from destructuring. * @param {JavascriptParser} parser parser * @param {CallExpression | NewExpression} expr expression * @returns {RawReferencedExports | null} referenced exports from destructuring */ const getRequireReferencedExportsFromDestructuring = (parser, expr) => { const referencedPropertiesInDestructuring = parser.destructuringAssignmentPropertiesFor(expr); if (!referencedPropertiesInDestructuring) return null; /** @type {RawReferencedExports} */ const referencedExports = []; traverseDestructuringAssignmentProperties( referencedPropertiesInDestructuring, (stack) => referencedExports.push(stack.map((p) => p.id)) ); return referencedExports; }; /** * Creates a require cache dependency. * @param {JavascriptParser} parser parser * @returns {(expr: Expression) => boolean} handler */ const createRequireCacheDependency = (parser) => toConstantDependency(parser, RuntimeGlobals.moduleCache, [ RuntimeGlobals.moduleCache, RuntimeGlobals.moduleId, RuntimeGlobals.moduleLoaded ]); /** * Creates a require as expression handler. * @param {JavascriptParser} parser parser * @param {JavascriptParserOptions} options options * @param {() => undefined | string} getContext context accessor * @returns {(expr: Expression) => boolean} handler */ const createRequireAsExpressionHandler = (parser, options, getContext) => (expr) => { const dep = new CommonJsRequireContextDependency( { request: /** @type {string} */ (options.unknownContextRequest), recursive: /** @type {boolean} */ (options.unknownContextRecursive), regExp: /** @type {RegExp} */ (options.unknownContextRegExp), mode: "sync" }, /** @type {Range} */ (expr.range), undefined, parser.scope.inShorthand, getContext() ); dep.critical = options.unknownContextCritical && "require function is used in a way in which dependencies cannot be statically extracted"; dep.loc = parser.getLocation(expr); dep.optional = Boolean(parser.scope.inTry); parser.state.current.addDependency(dep); return true; }; /** * Creates a require call handler. * @param {JavascriptParser} parser parser * @param {JavascriptParserOptions} options options * @param {() => undefined | string} getContext context accessor * @param {WeakMap<CallExpression, RequireBindingData>=} requireBindingData per-parser `const NAME = require(LITERAL)` binding state; only the free-`require` plugin populates it * @returns {(callNew: boolean) => (expr: CallExpression | NewExpression) => (boolean | void)} handler factory */ const createRequireCallHandler = ( parser, options, getContext, requireBindingData ) => { /** * Process require item. * @param {CallExpression | NewExpression} expr expression * @param {BasicEvaluatedExpression} param param * @param {boolean=} allowEvaluationOnly when false (conditional require), keep full namespace use * @returns {CommonJsRequireDependency | undefined} created dependency when handled */ const processRequireItem = (expr, param, allowEvaluationOnly = true) => { if (param.isString()) { let referencedExports = getRequireReferencedExportsFromDestructuring( parser, expr ); const binding = requireBindingData && requireBindingData.get(/** @type {CallExpression} */ (expr)); if (binding && !referencedExports) { // `const NAME = require(LITERAL)` — let later member-access walks // on `NAME` populate the dependency's referenced exports. referencedExports = binding.referencedExports; } else if ( allowEvaluationOnly && referencedExports === null && !binding && parser.isStatementLevelExpression(expr) ) { // Bare `require(...)` as a statement: result discarded → evaluation only. referencedExports = []; } const dep = new CommonJsRequireDependency( /** @type {string} */ (param.string), /** @type {Range} */ (param.range), getContext(), referencedExports, /** @type {Range} */ (expr.range) ); if (binding) binding.dep = dep; dep.loc = parser.getLocation(expr); dep.optional = Boolean(parser.scope.inTry); parser.state.current.addDependency(dep); HarmonyImportGuard.attachDependencyGuards(parser, dep); return dep; } }; /** * Process require context. * @param {CallExpression | NewExpression} expr expression * @param {BasicEvaluatedExpression} param param * @returns {boolean | void} true when handled */ const processRequireContext = (expr, param) => { const referencedExports = getRequireReferencedExportsFromDestructuring( parser, expr ); const dep = ContextDependencyHelpers.create( CommonJsRequireContextDependency, /** @type {Range} */ (expr.range), param, expr, options, { category: "commonjs", referencedExports }, parser, undefined, getContext() ); if (!dep) return; dep.loc = parser.getLocation(expr); dep.optional = Boolean(parser.scope.inTry); parser.state.current.addDependency(dep); return true; }; return (callNew) => (expr) => { if (options.commonjsMagicComments) { const { options: requireOptions, errors: commentErrors } = parser.parseCommentOptions(/** @type {Range} */ (expr.range)); if (commentErrors) { for (const e of commentErrors) { const { comment } = e; parser.state.module.addWarning( new (getCommentCompilationWarning())( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, parser.getLocation(comment) ) ); } } if (requireOptions && requireOptions.webpackIgnore !== undefined) { if (typeof requireOptions.webpackIgnore !== "boolean") { parser.state.module.addWarning( new (getUnsupportedFeatureWarning())( `\`webpackIgnore\` expected a boolean, but received: ${requireOptions.webpackIgnore}.`, parser.getLocation(expr) ) ); } else if (requireOptions.webpackIgnore) { // Do not instrument `require()` if `webpackIgnore` is `true` return true; } } } if (expr.arguments.length !== 1) return; /** @type {null | LocalModule} */ let localModule; const param = parser.evaluateExpression(expr.arguments[0]); if (param.isConditional()) { let isExpression = false; for (const p of /** @type {BasicEvaluatedExpression[]} */ ( param.options )) { // Shared valueRange across branches: never mark evaluation-only. const requireDep = processRequireItem(expr, p, false); if (requireDep === undefined) { isExpression = true; } } if (!isExpression) { const dep = new RequireHeaderDependency( /** @type {Range} */ (expr.callee.range) ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); return true; } } if ( param.isString() && (localModule = getLocalModule( parser.state, /** @type {string} */ (param.string) )) ) { localModule.flagUsed(); const dep = new LocalModuleDependency( localModule, /** @type {Range} */ (expr.range), callNew ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); } else { const requireDep = processRequireItem(expr, param); if (requireDep === undefined) { processRequireContext(expr, param); } else { requireDep._canConcatenate = true; // concatenation replaces the whole NewExpression; the template // reapplies the `new` return-value rule requireDep.callNew = callNew; const dep = new RequireHeaderDependency( /** @type {Range} */ (expr.callee.range), requireDep ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); } } return true; }; }; /** * Creates a process resolve handler. * @param {JavascriptParser} parser parser * @param {JavascriptParserOptions} options options * @param {() => undefined | string} getContext context accessor * @returns {(expr: CallExpression, weak: boolean) => (boolean | void)} resolver */ const createProcessResolveHandler = (parser, options, getContext) => { /** * Process resolve item. * @param {CallExpression} expr call expression * @param {BasicEvaluatedExpression} param param * @param {boolean} weak weak * @returns {boolean | void} true when handled */ const processResolveItem = (expr, param, weak) => { if (param.isString()) { const dep = new RequireResolveDependency( /** @type {string} */ (param.string), /** @type {Range} */ (param.range), getContext() ); dep.loc = parser.getLocation(expr); dep.optional = Boolean(parser.scope.inTry); dep.weak = weak; parser.state.current.addDependency(dep); return true; } }; /** * Process resolve context. * @param {CallExpression} expr call expression * @param {BasicEvaluatedExpression} param param * @param {boolean} weak weak * @returns {boolean | void} true when handled */ const processResolveContext = (expr, param, weak) => { const dep = ContextDependencyHelpers.create( RequireResolveContextDependency, /** @type {Range} */ (param.range), param, expr, options, { category: "commonjs", mode: weak ? "weak" : "sync" }, parser, getContext() ); if (!dep) return; dep.loc = parser.getLocation(expr); dep.optional = Boolean(parser.scope.inTry); parser.state.current.addDependency(dep); return true; }; return (expr, weak) => { if (!weak && options.commonjsMagicComments) { const { options: requireOptions, errors: commentErrors } = parser.parseCommentOptions(/** @type {Range} */ (expr.range)); if (commentErrors) { for (const e of commentErrors) { const { comment } = e; parser.state.module.addWarning( new (getCommentCompilationWarning())( `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`, parser.getLocation(comment) ) ); } } if (requireOptions && requireOptions.webpackIgnore !== undefined) { if (typeof requireOptions.webpackIgnore !== "boolean") { parser.state.module.addWarning( new (getUnsupportedFeatureWarning())( `\`webpackIgnore\` expected a boolean, but received: ${requireOptions.webpackIgnore}.`, parser.getLocation(expr) ) ); } else if (requireOptions.webpackIgnore) { // Do not instrument `require()` if `webpackIgnore` is `true` return true; } } } if (expr.arguments.length !== 1) return; const param = parser.evaluateExpression(expr.arguments[0]); if (param.isConditional()) { for (const option of /** @type {BasicEvaluatedExpression[]} */ ( param.options )) { const result = processResolveItem(expr, option, weak); if (result === undefined) { processResolveContext(expr, option, weak); } } const dep = new RequireResolveHeaderDependency( /** @type {Range} */ (expr.callee.range) ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); return true; } const result = processResolveItem(expr, param, weak); if (result === undefined) { processResolveContext(expr, param, weak); } const dep = new RequireResolveHeaderDependency( /** @type {Range} */ (expr.callee.range) ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); return true; }; }; class CommonJsImportsParserPlugin { /** * Creates an instance of CommonJsImportsParserPlugin. * @param {JavascriptParserOptions} options parser options */ constructor(options) { /** @type {JavascriptParserOptions} */ this.options = options; } /** * Applies the plugin by registering its hooks on the compiler. * @param {JavascriptParser} parser the parser * @returns {void} */ apply(parser) { const options = this.options; parser.hooks.collectDestructuringAssignmentProperties.tap( PLUGIN_NAME, (expr) => { if (isRequireCallExpression(expr)) return true; // `const NAME = require(…); const { a } = NAME;` if ( expr.type === "Identifier" && parser.getTagData(expr.name, REQUIRE_BINDING_TAG) ) { return true; } } ); const getContext = () => { if (parser.currentTagData) { const { context } = /** @type {CommonJsImportSettings} */ (parser.currentTagData); return context; } }; // #region metadata /** * Tap require expression. * @param {string} expression expression * @param {() => Members} getMembers get members */ const tapRequireExpression = (expression, getMembers) => { parser.hooks.typeof .for(expression) .tap( PLUGIN_NAME, toConstantDependency(parser, JSON.stringify("function")) ); parser.hooks.evaluateTypeof .for(expression) .tap(PLUGIN_NAME, evaluateToString("function")); parser.hooks.evaluateIdentifier .for(expression) .tap( PLUGIN_NAME, evaluateToIdentifier(expression, "require", getMembers, true) ); }; tapRequireExpression("require", () => []); tapRequireExpression("require.resolve", () => ["resolve"]); tapRequireExpression("require.resolveWeak", () => ["resolveWeak"]); // #endregion // Weird stuff // parser.hooks.assign.for("require").tap(PLUGIN_NAME, (expr) => { // to not leak to global "require", we need to define a local require here. const dep = new ConstDependency("var require;", 0); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); return true; }); // #region Unsupported parser.hooks.call .for("require.main.require") .tap( PLUGIN_NAME, expressionIsUnsupported( parser, "require.main.require is not supported by webpack." ) ); parser.hooks.expression .for("module.parent.require") .tap( PLUGIN_NAME, expressionIsUnsupported( parser, "module.parent.require is not supported by webpack." ) ); parser.hooks.call .for("module.parent.require") .tap( PLUGIN_NAME, expressionIsUnsupported( parser, "module.parent.require is not supported by webpack." ) ); // #endregion // #region Renaming /** * Returns true when set undefined. * @param {Expression} expr expression * @returns {boolean} true when set undefined */ const defineUndefined = (expr) => { // To avoid "not defined" error, replace the value with undefined const dep = new ConstDependency( "undefined", /** @type {Range} */ (expr.range) ); dep.loc = parser.getLocation(expr); parser.state.module.addPresentationalDependency(dep); return false; }; parser.hooks.canRename.for("require").tap(PLUGIN_NAME, () => true); parser.hooks.rename.for("require").tap(PLUGIN_NAME, defineUndefined); // #endregion // #region Inspection const requireCache = createRequireCacheDependency(parser); parser.hooks.expression.for("require.cache").tap(PLUGIN_NAME, requireCache); // #endregion // #region Require as expression /** * Require as expression handler. * @param {Expression} expr expression * @returns {boolean} true when handled */ const requireAsExpressionHandler = createRequireAsExpressionHandler( parser, options, getContext ); parser.hooks.expression .for("require") .tap(PLUGIN_NAME, requireAsExpressionHandler); // #endregion // #region Require /** * Creates a require handler. * @param {boolean} callNew true, when require is called with new * @returns {(expr: CallExpression | NewExpression) => (boolean | void)} handler */ /** @type {WeakMap<CallExpression, RequireBindingData>} */ const requireBindingData = new WeakMap(); const createRequireHandler = createRequireCallHandler( parser, options, getContext, requireBindingData ); parser.hooks.call .for("require") .tap(PLUGIN_NAME, createRequireHandler(false)); parser.hooks.new .for("require") .tap(PLUGIN_NAME, createRequireHandler(true)); parser.hooks.call .for("module.require") .tap(PLUGIN_NAME, createRequireHandler(false)); parser.hooks.new .for("module.require") .tap(PLUGIN_NAME, createRequireHandler(true)); // #endregion // #region Require with property access /** * Returns true when handled. * @param {Expression} expr expression * @param {CalleeMembers} calleeMembers callee members * @param {CallExpression} callExpr call expression * @param {Members} members members * @param {Range[]} memberRanges member ranges * @returns {boolean | void} true when handled */ const chainHandler = ( expr, calleeMembers, callExpr, members, memberRanges ) => { if (callExpr.arguments.length !== 1) return; const param = parser.evaluateExpression(callExpr.arguments[0]); if ( param.isString() && !getLocalModule(parser.state, /** @type {string} */ (param.string)) ) { const dep = new CommonJsFullRequireDependency( /** @type {string} */ (param.string), /** @type {Range} */ (expr.range), members, /** @type {Range[]} */ memberRanges ); dep.asiSafe = !parser.isAsiPosition( /** @type {Range} */ (expr.range)[0] ); dep.optional = Boolean(parser.scope.inTry); dep._canConcatenate = true; dep.loc = parser.getLocation(expr); parser.state.current.addDependency(dep); HarmonyImportGuard.attachDependencyGuards(parser, dep); return true; } }; /** * Call chain handler. * @param {CallExpression} expr expression * @param {CalleeMembers} calleeMembers callee members * @param {CallExpression} callExpr call expression * @param {Members} members members * @param {Range[]} memberRanges member ranges * @returns {boolean | void} true when handled */ const callChainHandler = ( expr, calleeMembers, callExpr, members, memberRanges ) => { if (callExpr.arguments.length !== 1) return; const param = parser.evaluateExpression(callExpr.arguments[0]); if ( param.isString() && !getLocalModule(parser.state, /** @type {string} */ (param.string)) ) { const dep = new CommonJsFullRequireDependency( /** @type {string} */ (param.string), /** @type {Range} */ (expr.callee.range), members, /** @type {Range[]} */ memberRanges ); dep.call = true; dep.namespaceObjectAsContext = Boolean( options.strictThisContextOnImports ); dep.asiSafe = !parser.isAsiPosition( /** @type {Range} */ (expr.range)[0] ); dep.optional = Boolean(parser.scope.inTry); dep._canConcatenate = true; dep.loc = parser.getLocation(expr.callee); parser.state.current.addDependency(dep); HarmonyImportGuard.attachDependencyGuards(parser, dep); parser.walkExpressions(expr.arguments); return true; } }; parser.hooks.memberChainOfCallMemberChain .for("require") .tap(PLUGIN_NAME, chainHandler); parser.hooks.memberChainOfCallMemberChain .for("module.require") .tap(PLUGIN_NAME, chainHandler); parser.hooks.callMemberChainOfCallMemberChain .for("require") .tap(PLUGIN_NAME, callChainHandler); parser.hooks.callMemberChainOfCallMemberChain .for("module.require") .tap(PLUGIN_NAME, callChainHandler); // #endregion // #region Require bound to a const variable // Track `const NAME = require(LITERAL)` so that static member accesses on // `NAME` (e.g. `NAME.foo`, `NAME.foo()`) are forwarded to the same // `CommonJsRequireDependency` as referenced exports — enabling tree // shaking of CommonJS modules that are imported into a named binding // rather than destructured. parser.hooks.preDeclarator.tap(PLUGIN_NAME, (declarator, statement) => { if (statement.kind !== "const") return; if (declarator.id.type !== "Identifier") return; if (!declarator.init || declarator.init.type !== "CallExpression") { return; } const init = declarator.init; if ( init.callee.type !== "Identifier" || init.callee.name !== "require" || init.arguments.length !== 1 ) { return; } const arg = init.arguments[0]; if (arg.type !== "Literal" || typeof arg.value !== "string") return; // Only attach binding state when `require` resolves to the free // `require` (i.e. it isn't shadowed in the current scope). const requireInfo = parser.getFreeInfoFromVariable("require"); if (!requireInfo || requireInfo.name !== "require") return; /** @type {RequireBindingData} */ const binding = { referencedExports: [], dep: null }; requireBindingData.set(init, binding); parser.tagVariable(declarator.id.name, REQUIRE_BINDING_TAG, binding); return true; }); parser.hooks.expression .for(REQUIRE_BINDING_TAG) .tap(PLUGIN_NAME, (expr) => { const binding = /** @type {RequireBindingData} */ (parser.currentTagData); if (binding) { const properties = parser.destructuringAssignmentPropertiesFor(expr); if (properties && binding.referencedExports) { // `const { a } = NAME` — only the destructured keys are read. const referencedExports = binding.referencedExports; traverseDestructuringAssignmentProperties(properties, (stack) => referencedExports.push(stack.map((p) => p.id)) ); } else { // `NAME` is read as a value (not as the object of a static member // chain), so we have to assume the whole exports object is used. binding.referencedExports = null; if (binding.dep) { binding.dep.referencedExports = null; } } } return true; }); parser.hooks.expressionMemberChain .for(REQUIRE_BINDING_TAG) .tap(PLUGIN_NAME, (_expr, members) => { const binding = /** @type {RequireBindingData} */ (parser.currentTagData); if (binding && binding.referencedExports) { binding.referencedExports.push(members); } // Returning truthy suppresses the parser's fallback chain (which // would otherwise walk `NAME` as a bare expression and trigger our // `expression` hook above, marking the whole namespace as used). return true; }); parser.hooks.callMemberChain .for(REQUIRE_BINDING_TAG) .tap(PLUGIN_NAME, (expr, members) => { const binding = /** @type {RequireBindingData} */ (parser.currentTagData); if (binding && binding.referencedExports) { if (members.length === 0) { // `NAME(...)` — calling the require result directly; the // whole exports object is observable. binding.referencedExports = null; if (binding.dep) { binding.dep.referencedExports = null; } } else { binding.referencedExports.push(members); } } if (expr.arguments) parser.walkExpressions(expr.arguments); return true; }); // Re-exporting the binding lets the require result escape, so the whole // exports object is observable. Stage -10 runs before the harmony bail tap. parser.hooks.exportSpecifier.tap( { name: PLUGIN_NAME, stage: -10 }, (_statement, id) => { const binding = /** @type {RequireBindingData | undefined} */ (parser.getTagData(id, REQUIRE_BINDING_TAG)); if (binding) { binding.referencedExports = null; if (binding.dep) { binding.dep.referencedExports = null; } } } ); // #endregion // #region Require.resolve /** * Processes the provided expr. * @param {CallExpression} expr call expression * @param {boolean} weak weak * @returns {boolean | void} true when handled */ const processResolve = createProcessResolveHandler( parser, options, getContext ); parser.hooks.call .for("require.resolve") .tap(PLUGIN_NAME, (expr) => processResolve(expr, false)); parser.hooks.call .for("require.resolveWeak") .tap(PLUGIN_NAME, (expr) => processResolve(expr, true)); // #endregion } } module.exports = CommonJsImportsParserPlugin; module.exports.createProcessResolveHandler = createProcessResolveHandler; module.exports.createRequireAsExpressionHandler = createRequireAsExpressionHandler; module.exports.createRequireCacheDependency = createRequireCacheDependency; module.exports.createRequireHandler = createRequireCallHandler;