-
Notifications
You must be signed in to change notification settings - Fork 44
How do we handle dynamic specifiers (without dynamic import)? #7
Comments
i would be up for unscoped require from the module module or import.meta.require, but definitely not scoped require from an imported module |
I'm -1 on the builtin module. This seems to go directly against the spirit of TC39 (as I understand it). |
I'm a huge +1 on |
+1 to |
I can open a pr for that in a few hours unless someone else wants to take it |
-1 on My reasoning is this: ESM is async, and this is not going to change, AFAICT. Developers working with ESM will have to live with that asynchronicity through various means. Having a way to workaround that asynchronicity will mean that when the module they import will move from CJS to ESM, they will have to rewrite the code to deal with that. Yes, because top-level await is not yet a thing in JS, they have to wrap their dynamic import in an async IIFE, but that's the way it is currently with ESM. Once developers move to ESM land, they need to start thinking ESM-think and not import their CJS-think into it. So, yes, -1 on adding |
@giltayar there are all sorts of sync apis that exist in node. To me the "async" nature of ESM has to do with the initial module graph, there is 0 guarantee that the execution with make it through the entire graph without hitting a sync api. That being said I recognize that I am conflating "dynamic imports" + "cjs interop"... although it is hard to separate the two when cjs can be used for dynamic moduless. edit: keep in mind that |
@MylesBorins - I am not against As for async/sync - it's not the sync-ness of the api that bothers me, but rather it's the fact that we're importing a module in a sync way in an ESM module that should allow only async importing, and which when that imported CJS module will be migrated to ESM will anyway need to be rewritten as an async import (because, as you said, require does not work for ESM). |
@giltayar I do think it is worth thinking about the initial graph and subsequent graphs as different beasts. While they may share a cache, when you dynamically import a module you are essentially creating a new graph. |
@MylesBorins - interesting point of view (initial and subsequent graphs)!. To continue that way of thinking, and if I understand where you're coming from, then from the ESM point of view you are creating a new graph even if you are synchronously importing a CJS module. Synchronicity does not help you with "extending" the existing graph, because, by decree, ESM's initial graph must be statically analyzable. And dynamic import, whether sync or async, is not. So we're not gaining anything with synchronous |
If I, as a user, can write a global |
@weswigham A global |
@TimothyGu I'm not sure that the technical considerations for the |
Especially, since, as I said, I could write a package that does this today, and offer a better experience with an |
I've kicked off #10 to discuss interop... this issue should likely stick to the initial thread of dynamic imports, although I recognize they are very very intertwined |
Something worth considering is that if we were to add such a feature to core, it will probably never be removed because of userland dependency on it. For examples of such, see On the other hand, a userland module would have this flexibility. And we (Node.js core) wouldn’t have to deal with the issue of tricky edge cases with |
@MylesBorins Oops, just saw your comment. Will move this over in my next comment, if any. |
I'm a big fan of punting this if top level await is currently being specified, adding |
I would say that any module loading a CommonJS script is opting out of browser compatibility. |
@jkrems even with being able to tell that for a single type of import you won't be able to tell that for other types that might not work cross env, like HTML modules. CJS should not be treated as unique when we have other module types in the same category of removing cross env compatibility. |
what @jkrems says +
I also agree if that's the case. |
I'm not convinced we should solve this use case. I'm not sure why "without dynamic import" is a requirement here. We should just tell people they can do: (async () => {
if (process.env.NODE_ENV === 'production') {
env = await import('./prod.js');
} else {
env = await import('./dev.js');
}
})(); And then drop the iife once top level await lands. In any case, I don't think this should block shipping modules. |
IIFE only works well for the main module. I don't think this should block anything but I wanted to know what other people thought about this. I'm not going to push hard on this because there are "solutions" (IIFE and point 1 in the OP), but to me they are more workarounds than first class features. I guess it's fine if we are sure that top-level await eventually makes it to the spec. |
Isn't the main module where 99% of the time you decide dev VS prod dependencies, though? In any case even this syntax doesn't look so bad to me: import(`./${process.env.NODE_ENV || 'dev'}.js`).then(module => {
const stuff = await module.default || module;
stuff.toDo();
}); But the main issue here is that whatever module you used to load dynamically via |
That's true (and unfortunate) - like all async code it's contagious.
I agree, it's not that optimal (or great) but in all honesty I'd expect things like conditional requires to simply stop existing when people start using ESM - since the pattern won't be available to them people will stop using it - and I'm fine with sacrificing a tiny bit of expressiveness for more static module code.
No one can promise that - but I think that we should at least try |
@WebReflection - yes, import.meta.require would solve the problem of async, but as I said above, it would just delay the problem till the module is converted to ESM (which we MUST assume is the end goal of all modules, at one time or another). So, yes, it would alleviate the pain, but only temporarily. And that's, I believe, the feeling here— (and as I will stress again, I am not against |
Just to make sure I'm on the same page since I haven't been following discussion nearly as long as some of you - |
Import.meta.require would only support loading cjs
…On Wed, Feb 7, 2018, 9:57 AM Benjamin Gruenbaum ***@***.***> wrote:
Just to make sure I'm on the same page since I haven't been following
discussion nearly as long as some of you - import.meta.require as in
allowing require in ESM through import.meta right @giltayar
<https://github.com/giltayar> ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAecV5zuMWju5ED4JKbC8KLHHI-78SVEks5tSbm7gaJpZM4R5xqU>
.
|
Yeah, in that case I'm pretty sure I think we should give top-level await a chance and solve this later. To clarify - I do think there should definitely be a way of loading cjs from mjs. I'm specifically referring to dynamic config. |
There is no facility in ESM to do conditional static imports; while I'd love to see that added to the language, I don't think it's node's place to address that - and thus I don't think it should block shipping modules. |
@targos this has been an interesting discussion, given the consensus so far - is there anything further to discuss here in your opinion? |
@benjamingr I don't think so. Thank you all for your input. |
+1 to import.meta.require. |
ESM cannot load a module "synchronously" with a dynamic specifier. Until we have top-level await, I think we need a supported way to do it. Two use cases:
I can think of three solutions:
import.meta.require
require
function (npm proposal)The text was updated successfully, but these errors were encountered: