Skip to content

Allow importing using an isolated cache #40594

@dead-claudia

Description

@dead-claudia

Is your feature request related to a problem? Please describe.

  1. I would like to create a mechanism for hot reloading
  2. I would like to be able to execute a module in an isolated context for testing
  3. I would like to be able to start a script using a custom loader (ex: Hashbang not resolving --loader relative to entry #23868)

Describe the solution you'd like
Introduce a vm.importInNewContext(pathToModule, context, options?), where loader instances can be passed via options.loaders and options.aliases can be set to explicitly alias certain paths. The idea is that this will not use the parent import cache or require cache, but its own caches, and that it'll use the loaders specified above for that functionality. Once the reference to this module is lost, if no state external to the module is referenced (like TCP ports or whatnot or passed-in globals), the context should be made eligible for garbage collection.

Describe alternatives you've considered

  • Using child processes with appropriate --loader flags is possible assuming exports are async, but the intermediate layer will be error-prone, and it'll be too slow to use in performance-critical production servers, and is a complete non-starter for testing synchronous functions that act at least in part by observable side effect.
  • I could use the vm modules API, but there's a number of caveats that, while not blocking me entirely, necessarily make it very complicated and brittle:
    • I'd have to reimplement Node's resolution algorithm in its entirety, complete with loaders (if I wanted to support those)
    • If I wanted to ensure modules kept a clean, fully isolated context, I'd also have to both proxy all the various functions and reimplement module.syncBuiltinESMExports(). This would of course significantly slow down load times (a major problem for larger dependencies and applications) as it'd all be implemented in userland.
    • If I wanted to support module.createRequire, I'd have to use a wrapper around that mucks with the CJS module loader's internals somewhat (particularly around Module._cache, Module._initPaths, and friends) just to ensure the cache and resolved paths remain correctly separated from the main tree. (This is very obviously not meant to be publicly supported, and I doubt you'd want to support such a pattern, even though it's possible in theory to do.)
  • https://www.npmjs.com/package/proxyquire and https://www.npmjs.com/package/clear-module could be used together to mostly resolve the issue for CJS modules, but they of course obviously do not work for ESM modules, and they don't actually isolate the graph, only mutate it and change how it resolves.

Note: #36351 will also impact the dynamic import side of this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    esmIssues and PRs related to the ECMAScript Modules implementation.feature requestIssues that request new features to be added to Node.js.loadersIssues and PRs related to ES module loadersmoduleIssues and PRs related to the module subsystem.stale

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions