-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ESM module reloading and module graph #51
Comments
To refine what I was suggesting in the meeting maybe we could create a standard but flagged way to do this (TC39 proposal?). For example |
I should comment here months ago, but it's never too late. HMR is supported by all major bundlers, a bit defferently in every case, so there is no real "standard". So which parts are needed for HotModuleReplacements:
let someModule = require('./module');
module.hot.accept('....', () => {
// cache has been cleared, just re-require module
someModule = require('./module');
});
As a result, the main issue to resolve is actually how to "accept" and "reconcile" the update.
I am thinking - it is possible to have an explicit hot import - However, this is not letting to implement some custom update logic, which might be needed, and supported by bundlers... and which I never seen used. |
to be clear, I think what we're talking about is not the browser, or how a bundler must work around the limitations, but rather what Node.js can add (beyond the ES spec) to support what tools running in Node.js need and expect from if Node.js declines to support these use cases--I don't think it will, but if it did--it would place a significant barrier to using non-transpiled ESM in Node.js code. unfortunately, it seems like it's not a barrier that devs see until they've already started driving forward using native ESM in Node apps |
Per our discussion, this is what's needed:
|
Modules (CJS or ESM) don't have parents in that way, because they're evaluated only once. In other words, the entire concept of "parent" is wrong and flawed, CJS never should have had it, and ESM shouldn't get it. What are the use cases that think they need it? |
I'll let @theKashey explain. |
(if he doesn't want to: in a nutshell, I think it has to do with being able to mock one "use" of a module, but not another) |
Frankly speaking, The So parent information is needed to maintain module graph integrity in a constant time, right now it requires a full traverse of existing graph to reconstruct child->parent connection, and still let's you create an isolated "areas", where a child has a reference to a deleted parent, or a parent has a reference to a deleted child. |
This is also a good case. The golden rule of "mock only what you own", or direct dependencies. However, it does not require access to the module cache, as it should occur on, let call it, "import time". In cjs terms - after |
Right, but you'd do that with import maps or something like it - not at runtime in the module that's being imported. I certainly see a use case for listing all parents of a module - ie, all importers - but that information would need to be statically determinable prior to the module's evaluation, and would thus not include dynamic importers, only static ones. I'm still unclear about the usefulness of that at runtime (as opposed to the imo more typical approach that would generate a dependency graph in advance, and then use it at runtime). |
In "runtime" it this information might be not so useful, as long as HMR is not expected to be an "often" event, so it's ok to use any other "slow" path.
But not always. const module = import(`./dynamic-module-${letter}`) From my point of views |
@theKashey and if that module was previously loaded, it would never be evaluated again, so any "parent" it was able to see would have been the first importer, not the It simply makes no sense for a module to evaluate with any knowledge of its own consumers. |
Firstly we are not talking about evaluation, but something after it - already established module graph. 👉Module reloading can happen only after the loading. |
If it's from an already established module graph, then it makes total sense to expose the graph in some way! However, I don't think it should be called a "parent" since module graphs are not parent-child relationships. |
We probably just went to deep and talking about details we don't own, and so don't need. There is no need to give us an access to some standard module system - it at least require throughful development of that structure, and will concrete some realisation. All we need is:
A week ago I've found that the majority of cache-delete operations(99.9%) actually leading to the memory leak. Ie deleting a module leaves reference to it in a parent, or a children; keeping references to children in the module as well. And the root cause - actually undocumented, and not expected to be "hacked", module graph structure. |
Nothing has change with Node.js 14 ? |
@searls 👋 we've had this issue open for quite some time, that we'd like to make sure that it's possible to reload ESM modules in Node (to provide features like proxying.) I'd noticed that quibble supports ESM modules. Are you finding that the platform already provides all the functionality that you need? |
Thanks for reaching out! @giltayar is our resident ESM expert—what say you? |
You can find all the sordid technical details here: https://dev.to/giltayar/mock-all-you-want-supporting-es-modules-in-the-testdouble-js-mocking-library-3gh1 The TL;DR is this: while you cannot unload a module, you can use loaders to ensure that each time you want, a new version of the module will be loaded on Note that using a loader means adding |
Also you can use the same method as Deno, adding a |
@Ayfri I use a query parameter, but it's the same method. Where does demo use this? |
I'm still trying to figure out how to reload a module anytime it or any of its dependencies are modified. The closest I've been able to get is this:
While that correctly reloads the module when it is directly modified, it doesn't reload when a dependency of the module is modified. For example, if EDIT: I'm already using the |
In a nutshell, we need to be able to "unload" an ESM module, which is not supported. Tooling needs this for reloading files (e.g. in a tool's "watch" mode) or mocking modules (using proxyquire, rewiremock, etc.)
Ref: nodejs/node#49442
The text was updated successfully, but these errors were encountered: