Skip to content

Instantly share code, notes, and snippets.

@jenseng
Created June 23, 2022 18:27
Show Gist options
  • Save jenseng/1eeb29e68c1bf789d73939b6cad88671 to your computer and use it in GitHub Desktop.
Save jenseng/1eeb29e68c1bf789d73939b6cad88671 to your computer and use it in GitHub Desktop.
`import` a module without caching it
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