fix: do not load source for electron module in ESM loader synchronous flow#46810
fix: do not load source for electron module in ESM loader synchronous flow#46810codebytere merged 1 commit intomainfrom
electron module in ESM loader synchronous flow#46810Conversation
|
LGTM 👍
Yeah first test of its kind I believe, but could we add a utility variant of |
|
@clavin are you planning to add a test to this? |
|
Open to pushback here, but no I don't think the complexity of writing the test code is worth it to prevent this specific bug from regressing. If we really want to test this sort of behavior, we should do a more comprehensively ESM quality initiative. (If it does happen to regress, then definitely yeah add a test.) @codebytere ready to merge if you agree :) |
deepak1556
left a comment
There was a problem hiding this comment.
LGTM, my comment for test was more of a suggestion on how it could be achieved if we are to write one to exercise this code path, not a blocker for this PR.
@clavin can you create a tracking issue for follow-up, thanks!
|
Release Notes Persisted
|
|
I have automatically backported this PR to "37-x-y", please check out #47342 |
|
I have automatically backported this PR to "36-x-y", please check out #47343 |
|
I have automatically backported this PR to "35-x-y", please check out #47344 |
Description of Change
Mirrors a modification in the ESM patch that avoids loading source for the
electronmodule to the same (synchronous) code used for CJS interoperability. This code path can only be triggered in packaged applications.It was an interesting journey figuring out the root cause for this one.
There exists two flows in the ESM loader: asynchronous (ESM) and synchronous (CJS). The second flow enables CJS modules to load ESM modules and vice versa. When a CJS module loads an ESM module, its
imports are loaded synchronously for compatibility.We patch the ESM loader to avoid loading source code for the
electronmodule (because there is none). The patch only applies to the asynchronous flow. The patch also needs to be applied to the synchronous flow, which only runs on theelectronmodule in packaged applications.In an unpackaged application,
default_appis the entrypoint. At the beginning ofdefault_app, theelectronmodule is loaded viaimportas an ESM module. Loading theelectronmodule this way uses the (patched) asynchronous flow. As a side effect, the module instance gets cached.In a packaged application, the app's main script is the entrypoint.
default_appis not present and does not run. As a consequence, the module cache is relatively fresh.The domino effect starts when (1) a CJS module loads via
require(2) an ESM module that loads viaimport(3) theelectronmodule (4) for the first time.12 The ESM loader's synchronous flow does not take the usual cache hit branch and instead attempts to load the module. Since the synchronous flow is not patched to avoid loading theelectronmodule's source code, an error ends up getting thrown.3 💥I also took the opportunity to move some code between patches, but honestly I don't know what goes where, so lmk if there's a better home for these changes. As for testing, I couldn't find a simple way to get our test runner to skip the
default_appentrypoint, so I'm pushing the fix up by itself. If you accept "it works on my machine" though, then rest assured I manually verified this fix.Fixes #46614
Checklist
npm testpassesRelease Notes
Notes: Fixed an error when importing
electronfor the first time from an ESM module loaded by a CJS module in a packaged app.Footnotes
(1) The CJS module is necessary to trigger the synchronous flow; (2) The ESM module is necessary to trigger the ESM loader; (3) The
electronmodule is special; (4) It must be the first time or else the module will be cached. ↩The
electron/js2c/browser_initmodule is loaded at startup, but it is a special case that uses the built-in code cache, completely circumvents most of the module loading code, and is distinct from theelectronmodule. ↩Somewhat interestingly, the thrown error is not from the file system. Instead, it's from a validation check on the resolved module path:
electron:is not a protocol it knows how to load source for. ↩