- Version: Electron 2.0.0-beta.x
- Platform: macOS 10.13
- Subsystem: electron/node
After over a month of testing all aspects of Node's new loader infrastructure in electron, only one issue in my opinion remains to be resolved and in my best estimation it needs to be in electron/node.
Setup: (steps to use Node's loader)
// Construct
const Loader = process.NativeModule.require('internal/loader/Loader');
const loader = new Loader(`file://${__dirname}`);
// Configure (abstract)
loader.hook({
resolve(specifier, referrer, resolve) {
// Custom resolution logic …
// return {url: ..., format: ... }
// Or defer to default resolver
return resolve(specifier, referrer);
}
});
// Import a module
loader.import('./module.js', `file://${__filename}`);
Problem
// Import a module (works the first time)
loader.import('./module.js', `file://${__filename}`);
// Re-Importing a module fails *** throws ***
loader.import('./module.js', `file://${__filename}`);
The loader's internals are not designed to work in multi-context environments. Both Electron and NW.js present the same issue where the loader associates the "evaluated" namespace of the module to the current node context which seems to not behave the same here as it does in node.
The end result is that a module will load fine on first import where the loader holds a direct reference to it, but as soon as it is imported again (if even on the next line) then the loader uses the stored reference in the module map expecting it to point to the context-bound instance of the module.
Unlike Node, in both Electron & NW.js, this instance would be undefined.
Workaround
It takes two ugly but effective steps (all kosher and pure JS). 1. Override the loader's import method so that it keeps a reference of the first instance of the module on the actual JS instance of the module wrap (ie moduleWrap[Symbol.for('module')]
). 2. At the same time, make sure to always create a separate loader instance per context (in Electron, I create one for main, and one in preload which is reliable both in preload as well as the associated window).
Recommendation
How Electron or NW.js can best go about resolving this depends on their multi-context architectures, and best left to those more knowledgeable. However, from all my research and testing, I am almost certain that correctly associating contexts with modules is somewhere in src/module_wrap.cc
.
I believe that Node's loader will take little effort to make it ideal for mainstream use in Electron. If you are looking into it, I am very interested and would be happy to exchange recipes regarding other related obstacles. As it stands, the loader is very stable if you know what to expect, and it takes a lot of patching. I managed to do it all in JS and without any custom rebuilds. If this will eventually become mainstream, I honestly think some effort will be needed to properly support it by the platform.