-
Notifications
You must be signed in to change notification settings - Fork 73
Open
Description
module-alias 与 webpack 打包导致 require.cache 失效
简短描述
- 在使用 webpack 打包时,动态路径的 require 可能被打包为类似 requireEmpty 的形式,导致运行时的 require.cache 与原生 Node 的行为不一致,从而让 module-alias 的 reset() 中清理 require.cache 失效,进而导致别名不生效或缓存残留。
复现步骤
- 在项目中使用 module-alias,并在代码里依赖动态路径(例如通过拼接路径再 require)。
- 使用 webpack 打包(或类似工具),运行打包后的输出。
- 调用 module-alias.reset()(或在测试场景中重置模块路径),发现模块缓存并没有按预期被清理。
实际行为
- reset() 里遍历 require.cache 时无法找到打包后的缓存条目(或调用的 require 被替换),导致无法删除相关缓存,别名映射失效或行为异常。
预期行为
- reset() 能正确遍历并清理对应的模块缓存,使得别名能被正确重置。
根因
- 打包工具会修改或替换全局 require,或将 require 的实现替换为空或打包时的占位(如 requireEmpty)。因此直接使用全局 require/cache 会失效。
最小修复方案(思路)
- 使用 Node 内置模块的 createRequire,在当前文件上下文创建一个可靠的 require(这里命名为 $require),并在需要访问缓存或加载 package.json、访问 require.main 的位置使用 $require 而不是全局 require。这样避免被 webpack 等工具替换的全局 require 影响。
补丁(要做的三处最小替换)
- 在文件里引入 nodePath 后,创建 $require:
// 在 var nodePath = require('path'); 之后增加:
const $require = BuiltinModule.createRequire(__filename || nodePath.dirname(process.argv[1]));- reset() 中遍历缓存时,用 $require.cache 替换 require.cache:
Object.getOwnPropertyNames($require.cache).forEach(function (name) {
if (name.indexOf(path) !== -1) {
delete $require.cache[name]
}
});- 加载 package.json 时使用 $require:
npmPackage = $require(nodePath.join(base, 'package.json'))- 获取主模块时使用 $require.main:
function getMainModule () {
return $require.main._simulateRepl ? undefined : $require.main
}其他备注
- 这些改动是尽量小的本地修复,不会影响模块别名的其他逻辑。
- 已验证:使用 createRequire 后,reset() 能正常删除对应缓存条目,别名重置恢复正常。
module-alias and webpack bundling cause require.cache to fail
Short description
- When bundling with webpack, dynamic require calls can be replaced (e.g. requireEmpty), making runtime require.cache differ from Node's native behavior. This breaks module-alias.reset() cache cleanup, causing aliases to not reset or leaving stale caches.
Reproduction steps
- Use module-alias and require modules via dynamic paths (e.g. path concatenation).
- Bundle the project with webpack (or similar) and run the bundled output.
- Call module-alias.reset() (or reset module paths in tests) and observe that module cache is not cleared as expected.
Actual behavior
- reset() iterates require.cache but cannot find bundled cache entries (or the global require was replaced), so it cannot delete them and alias mapping fails or behaves incorrectly.
Expected behavior
- reset() should properly traverse and clear the corresponding module cache so aliases can be correctly reset.
Root cause
- Bundlers modify or replace the global require (or insert placeholders like requireEmpty). Direct use of global require/cache becomes unreliable.
Minimal fix idea
- Use Node's builtin createRequire to create a reliable require in the current file context (named $require). Use $require for cache access, package.json loading, and main module access instead of the global require to avoid interference from bundlers.
Patch (three/four minimal replacements)
- After importing nodePath, create $require:
// After: var nodePath = require('path');
const $require = BuiltinModule.createRequire(__filename || nodePath.dirname(process.argv[1]));- In reset(), iterate $require.cache instead of require.cache:
Object.getOwnPropertyNames($require.cache).forEach(function (name) {
if (name.indexOf(path) !== -1) {
delete $require.cache[name]
}
});- Load package.json using $require:
npmPackage = $require(nodePath.join(base, 'package.json'))- Access main module via $require.main:
function getMainModule () {
return $require.main._simulateRepl ? undefined : $require.main
}Notes
- These are minimal, local changes that do not affect other module-alias logic.
- Verified: using createRequire allows reset() to remove corresponding cache entries and restores alias reset behavior.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels