Created
May 12, 2018 04:48
-
-
Save dead-claudia/7e85956b9856c45ca0450e316434bed7 to your computer and use it in GitHub Desktop.
Better module uncached loader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict" | |
const Module = require("module") | |
const loaded = new WeakMap() | |
let visited = new WeakSet() | |
const parents = new Set() | |
function removeRecursive(parent, mod) { | |
const index = loaded.get(mod) | |
if (index == null) { | |
if (visited.has(mod)) return | |
delete Module._cache[mod.id] | |
let curr = mod.parent | |
while (curr != null) { | |
if (curr === parent) { | |
parents.add(mod.parent) | |
visited.add(mod) | |
mod.parent = undefined | |
break | |
} | |
curr = curr.parent | |
} | |
} else if (index === 0) { | |
loaded.delete(index) | |
} else { | |
loaded.set(mod, index - 1) | |
} | |
for (const child of mod.children) { | |
removeRecursive(child) | |
} | |
} | |
function removeModule(mod, key) { | |
if (visited.has(mod)) return | |
const index = loaded.get(mod) | |
if (index == null) { | |
delete Module._cache[key] | |
if (mod.parent != null) { | |
parents.add(mod.parent) | |
visited.add(mod) | |
mod.parent = undefined | |
} | |
} else if (index === 0) { | |
loaded.delete(index) | |
} else { | |
loaded.set(mod, index - 1) | |
} | |
} | |
function clearParent(parent) { | |
let target = parent.children.findIndex(visited.has, visited) | |
if (target >= 0) { | |
for (let i = target + 1; i < parent.children.length; i++) { | |
if (!visited.has(parent.children[i])) { | |
parent.children[target++] = parent.children[i] | |
} | |
} | |
parent.children.length = target | |
} | |
} | |
loaded.set(module, 0) | |
for (const key in Module._cache) { | |
if (Object.prototype.hasOwnProperty.call(Module._cache, key)) { | |
loaded.set(Module._cache[key], 0) | |
} | |
} | |
module.exports = (parent, file, allowMissing) => { | |
if (typeof file !== "string") { | |
throw new TypeError("Expected `file` to be a string") | |
} | |
for (const key in Module._cache) { | |
if (Object.prototype.hasOwnProperty.call(Module._cache, key)) { | |
const mod = Module._cache[key] | |
const index = loaded.get(mod) | |
loaded.set(mod, index != null ? index + 1 : 0) | |
} | |
} | |
try { | |
file = Module._resolveFilename(file, parent, false) | |
} catch (e) { | |
if (allowMissing && e.code === "MODULE_NOT_FOUND") return undefined | |
throw e | |
} | |
try { | |
return parent.require(file) | |
} finally { | |
const child = Module._cache[file] | |
if (child != null) removeRecursive(child) | |
for (const key in Module._cache) { | |
if (Object.prototype.hasOwnProperty.call(Module._cache, key)) { | |
removeModule(Module._cache[key], key) | |
} | |
} | |
for (const parent of parents) { | |
clearParent(parent) | |
} | |
visited = new WeakSet() | |
parents.clear() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment