Uh oh!
There was an error while loading. Please reload this page.
esm: implement import.meta.main - #32223
Conversation
Uh oh!
There was an error while loading. Please reload this page.
jasnell
commented
Mar 12, 2020
What would the value be in a Worker thread? |
aduh95
commented
Mar 12, 2020
Good question! With the current implementation, it is |
devsnek
left a comment
There was a problem hiding this comment.
I'm against this for reasons outlined in the issue
hybrist
left a comment
There was a problem hiding this comment.
I might be convinced otherwise if there's overwhelming support for this feature but I have some concerns about this pattern (see issue comments). My concerns are broadly:
- Usually
import.metadoesn't change based on how and when the module has been imported. It's already "magic ephemeral data", let's not make it more dynamic and magic. - This pattern encourages writing code that's inherently untestable without setting up a custom module loader from scratch.
- (More optional preference) I would vastly prefer a solution that properly encloses optional code that is meant to run as main and doesn't also allow sprinkling that behavior into random expressions. One example I suggested was to export a main or startup function for this purpose.
aduh95
commented
Mar 13, 2020
@jkrems regarding your first point, having a way to tell if current module is the entry point is a motivation clearly stated in the I think your second point meets @devsnek's: using import{isMainThread}from'worker_threads';if(!isMainThread||!import.meta.main){process.emitWarning(newError('This module should be run from CLI.'));}Regarding your third point, while it'd fine with me, I fail to see how exporting a |
devsnek
commented
Mar 13, 2020
i think package exports can disallow importing your cli entrypoint. I also believe that "you've imported the wrong file" isn't specific to cli entrypoints, there are lots of files that libraries have that shouldn't be directly imported, which is why we should seek more general solutions. |
Boolean value to check if a module is run as entry point of the current process. Fixes: https://gtihub.com/nodejs/modules/issues/274
addaleax
left a comment
There was a problem hiding this comment.
I’m good with this, personally.
8ae28ff to
2935f72Compareaduh95
commented
Aug 27, 2020
Do we want to reconsider this? Asking because it's been recently brought up in #34882, it seems there are users looking for it. |
guybedford
commented
Oct 5, 2020
The use of The other benefit of I think treating any new context as supporting One pattern I also really like with exportfunctionlib(){// ...implementation..}if(import.meta.main){assert.strictEqual(lib('unit'),'test');}where the tests are run by just running During a build, @jkrems perhaps that counters your untestable argument in (2) :) I do like the idea of having an exports condition, but that seems complementary to this proposal. Would seeing progress on that help overcome your and @devsnek's concerns here? |
hybrist
commented
Oct 5, 2020
What I think is very unfortunate about those kinds of tests, is that they'll never run in a browser without building. So it's effectively creating a test pattern that is browser-incompatible. Not something that node has to care about but I would prefer if we wouldn't encourage the creation of node-only (or bundler-only) code.
It's still "untestable" with the exception of exactly this case: The code inside of the block is a test itself, will only ever run as a subprocess, and doesn't require any testing/assertion framework (block-scoped
Afaik deno is still much smaller as an ecosystem than nodejs (let alone the browser). So adding a module system feature to nodejs because deno is doing it when the feature cannot be used in browsers (likely in perpetuity), isn't really convincing to me. All that being said: These are all ecosystem concerns, not nodejs concerns. I'd be willing to dismiss my block to this change if there's a way to import a module as main without spawning a subprocess. That would make it somewhat testable at least and enable simple wrapper binaries. |
Technically, it could be run on the same process using
I suppose the web could also implement If I'm being honest, the same argument applies to |
hybrist
commented
Oct 5, 2020
I don't think that's true. It's fairly simple to run a file using import{main}from'./entrypoint.js';main();There's no need to parse & transform |
aduh95
commented
Oct 5, 2020
Yes sorry, I meant the fact that the HTML standard might implement I think you're making a valid point with the browser compatibility thing, and I don't have any argument to counter that 😅 |
hybrist
commented
Oct 5, 2020
Ah yes, sorry. Misread your comment about native browser support. :) |
ExE-Boss
commented
Oct 5, 2020
@jkrems The build step is about removing Example:Input:// src/foo.jsif(import.meta.main){thrownewError(`${import.meta.url} is not an entrypoint module`);}exportfunctionfoo(){/* ... */}// src/main.jsimport{foo}from"./foo.js";export*from"./foo.js";if(import.meta.main){console.log(foo());}Output:// dist/bundle.js// src/foo.jsfunctionfoo(){/* ... */}// src/main.jsif(import.meta.main){console.log(foo());}export{foo}; |
Yes, that's the problem. In the example above (where the thing inside of |
guybedford
commented
Oct 6, 2020
@jkrems it will likely be down to something like VM / compartments / realms to allow defining |
hybrist
commented
Oct 6, 2020
I think that really doesn't address the usability concerns, just like loader hooks in node wouldn't. E.g. let's say somebody wrote two worker entrypoints, both using I get that the current UX ( Maybe there could be an API like |
rektide
commented
Feb 25, 2021
please ship this. it's a huge help for a problem countless people run into regularly. allegedly it has risks and/or may not be 100% perfect for every use case (frankly i don't understand most of the concerns) but this seems straightforward & super helpful in 99.99% cases. not shipping it is really hurting us all very much. if we need a more foibled fancy alternative, let it emerge over time on some other import.meta. give us this straightforward common sense help which we very much need now. |
guybedford
commented
Jul 17, 2024
This sounds distinct from what is being discussed in #53882. It might even be a separate property like |
avivkeller
commented
Jul 17, 2024
I'm not saying it's the solution do that problem, I'm just saying it was referenced, and the sources for the feature (this) are seemingly stale, so I wanted to verify they were still being worked on. (Sorry if I worded my last comment poorly) |
GeoffreyBooth
commented
Jul 17, 2024
I think since Deno supports this property we should add it if we can. I think we should go through the same process with the WinterCG registry that we went through for |
avivkeller
commented
Sep 13, 2024
(AFAICT there are no specific issues/PRs blocking this issue) |
ljharb
commented
Sep 14, 2024
The block is because of the still unresolved request for changes on the PR; it should remain. |
avivkeller
commented
Sep 14, 2024
The blocked label is specific for issues/PRs blocking something, so I was trying to declutter. Feel free to re-add if needed. |
ljharb
commented
Sep 14, 2024
I dont have the ability to re-add it; it’s also blocked on WinterCG though. |
aduh95
commented
Sep 14, 2024
Is it? AFAICT |
ljharb
commented
Sep 14, 2024
That’s just documentation; it’s not the same as WinterCG having agreed on an interoperable implementation. |
jasnell
commented
Sep 21, 2024
Correct, the |
guybedford
commented
Sep 24, 2024
@aduh95 as authored here is it set to true when importing the main entry point from a worker? |
guybedford
commented
Sep 24, 2024
And just to be clear, my previous approval still stands. I wonder if we can get an update from @jkrems? |
It still feels like an awkward design choice because of things like "can't easily wrap" but those gaps could be filled with loaders or better core APIs in the future. If nobody else has pushed a better API in X years, there's a good chance that making it easier to write more interoperable code is worth it. Would be great to have some canonical definition of the exact semantics that can be shared across runtimes. But worst case, that's what major versions are for..? Willing to dismiss my review here to unblock progress. |
It's been 5 years. It's unlikely that a better alternative materializes.
| // Alphabetical | ||
| if (experimentalImportMetaResolve) | ||
| meta.resolve = createImportMetaResolve(url); | ||
| meta.main = Boolean(this?.isMain); |
There was a problem hiding this comment.
| meta.main=Boolean(this?.isMain); | |
| meta.main=!!this?.isMain; |
There was a problem hiding this comment.
Is there a performance merit to this? or is it for brevity / for consistency? (out of interest)
| moduleWrap.callbackMap.set(module, { | ||
| initializeImportMeta, | ||
| initializeImportMeta: isMain ? | ||
| FunctionPrototypeBind(initializeImportMeta, { isMain }) : |
There was a problem hiding this comment.
| FunctionPrototypeBind(initializeImportMeta,{ isMain }) : | |
| ()=>initializeImportMeta({ isMain }) : |
i believe an arrow is faster than binding
Lordfirespeed
commented
Apr 8, 2025
Is it all good if I pick up from here in a new PR? It seems a bit unfair to expect @aduh95 to be keeping on top of it after 5 years 😂 |
aduh95
commented
May 26, 2025
Superseded by #57804 |
Boolean value to check if a module is run as entry point of the current
process.
ES module authors need a way to determine if their code is run as CLI or as a dependency. #49440 have some proposal, I am implementing
import.meta.mainbecause:import.metaproposal.Fixes: #49440
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes