Skip to content

Instantly share code, notes, and snippets.

@dead-claudia
Created May 12, 2018 04:48
Show Gist options
  • Save dead-claudia/7e85956b9856c45ca0450e316434bed7 to your computer and use it in GitHub Desktop.
Save dead-claudia/7e85956b9856c45ca0450e316434bed7 to your computer and use it in GitHub Desktop.
Better module uncached loader
"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