Created
June 23, 2022 18:27
-
-
Save jenseng/1eeb29e68c1bf789d73939b6cad88671 to your computer and use it in GitHub Desktop.
`import` a module without caching it
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
import fs from "fs/promises"; | |
import url from "url"; | |
import vm from "vm"; | |
/** | |
* Import a single module without caching it; if you call this function again the module will be re-imported | |
* | |
* Moderately leaky workaround for https://github.com/nodejs/modules/issues/307 | |
* | |
* Note: | |
* * Requires --experimental-vm-modules --experimental-import-meta-resolve | |
* * Has a memory leak due to https://github.com/nodejs/node/issues/33439 (and possibly also V8?), but is | |
* less leaky than this workaround: https://github.com/nodejs/modules/issues/307#issuecomment-764560656 | |
* Tested both approaches importing a ~2.5MB module hundreds of times, memory grew at half the rate | |
* * Dependencies are imported normally, so those do not get re-imported | |
* * Could be sped up with createCachedData, at the expense of greater memory usage | |
*/ | |
export async function uncachedImport(specifier) { | |
const moduleUrl = await import.meta.resolve(specifier); | |
return vm.runInThisContext(`import(\"${specifier}\");`, { | |
async importModuleDynamically() { | |
const module = new vm.SourceTextModule(await fs.readFile(url.fileURLToPath(moduleUrl), "utf-8"), { | |
importModuleDynamically: realImport, | |
initializeImportMeta(meta) { | |
meta.url = moduleUrl; | |
}, | |
}); | |
await module.link(realImport); | |
await module.evaluate(); | |
return module; | |
}, | |
}); | |
} | |
const _cache = new Map(); | |
// need to wrap real sub-imports in a vm.Module | |
async function realImport(specifier) { | |
if (_cache.has(specifier)) { | |
return _cache.get(specifier); | |
} | |
const mod = await import(specifier); | |
const result = new vm.SyntheticModule(Object.keys(mod), function () { | |
Object.entries(mod).forEach(([key, value]) => { | |
this.setExport(key, value); | |
}); | |
}); | |
_cache.set(specifier, result); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment