modules
modules copied to clipboard
Spec: Would `!!import.meta ? 'module' : 'not'` be a reasonable ask?
I'm think we all must have considered this at some point, but cannot recall.
Q: Is there a safe way for code to test if it is module or not (ie not early/parse error)?
This code would target runtimes supporting import(…) globally, irrespective of semantics, and so my thinking was a clean nice-to-have here could be !!import.meta ? 'module' : 'not' which should not be too much to ask for… thoughts?
Possibly Related Discussions
import.meta.mainin nodejs/node#49440
If code wants to assert its parse goal, it can do export {} to force ESM or with ({}) {} to force Script.
~~You can also wrap either of those in Function and a try/catch to detect it.~~
You can also wrap either of those in Function and a try/catch to detect it.
This one is more on point, but I hit this issue in node:
// sometimesModule.js — {package: type: 'module'}
console.log(
(function() {
try {
import.meta.url;
return 'module';
} catch (e) {
return 'not';
}
})(),
);
> node sometimesModule.js
SyntaxError: Cannot use 'import.meta' outside a module
at Module._compile (internal/modules/cjs/loader.js:872:18)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:947:10)
at Module.load (internal/modules/cjs/loader.js:790:32)
at Function.Module._load (internal/modules/cjs/loader.js:703:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:999:10)
at internal/main/run_main_module.js:17:11
> node --experimental-modules sometimesModule.js
(node:37127) ExperimentalWarning: The ESM module loader is experimental.
module
So what I was getting at is sometimesModule.js would be an entrypoint that could be portable everywhere and in case it is node, it will either require or import('module').createRequire(…).
If code wants to assert its parse goal, it can do export {} to force ESM or with ({}) {} to force Script.
And so, this is a separate topic, but thanks.
(I crossed out that part of my comment since Function always evaluates as a sloppy Script)
Why would you want a file to be both Module and Script? Can you help me understand the use case?
At the top level this differs between Script and Module.
// maybe "use strict" here if you wanna have a Strict Script
let isModule = this === void 0;
// ... rest of file ...
@SMotaal are you still wanting to pursue adding import.meta to Script or is that enough?
Why would you want a file to be both Module and Script? Can you help me understand the use case?
@ljharb Not a good way for me to be able to reframe problems (ie can you humor me anyway please), but say this is a workshop for newcomers, where they use the sometimesModule.js to bootstrap.
I'm inclined to think that for someone less experienced, an intuitive expectation would be to know for certain that they are not in a module.
As @bmeck points out:
At the top level
thisdiffers between Script and Module.
And certainly, this is not as intuitive, but also worth being aware of. It still can get messy to explain for such audience, though
Because there are other ways for such a module to evaluate with this being undefined that can merely be due to a bug in a some loader on some platform:
const evaluate = (1, eval)(`
function() {
"use strict";
return eval(arguments[0]);
}
`);
It is fair imho to say that semantics of this being undefined and the code being evaluate itself is module or not are rough and hacky to relate to for at least a few folks.
Therefore: The argument I am trying to consider making is that semantically speaking, import.meta is an object in module, otherwise not — and that could just as well be undefined.
(I crossed out that part of my comment since Function always evaluates as a sloppy Script)
Yup, was mid way trying to clean up the code I did towards it and saw it as I replied… thanks though!
It seems to me that newcomers should understand that the two parse goals are different, and which one they’re using, before writing a line of code - just like they’d need to understand which language they’re writing beforehand.
@ljharb I appreciate there being different views on this, and appreciate others appreciating that when it comes to whohow to go about improving opportunities for newcomers learning, it is fair to assume that there will be different schools of thought, all worth appreciating.
Fair?
@SMotaal are you still wanting to pursue adding import.meta to Script or is that enough?
@bmeck Yes please — sorry, was midway in posting :)
@ljharb if we just considered how this plays out if it was introduced, where do you see !!import.meta causing runtime ambiguities or concerns?
@SMotaal showing people the differences is good, but there's no reason to actually rely on these checks in code. Maybe if you're doing some advanced bundling or something, although even then it's iffy.
Some web people wanted import.meta in scripts (as an object) and I'm more interested in pursuing that.
For one, the proposal for it explicitly and intentionally disallows it to be parsed in Scripts.
Some web people wanted import.meta in scripts (as an object) and I'm more interested in pursuing that.
@devsnek certainly… this is the path I was thinking down the road btw.
Something like (but not quite) !!import.meta && (!('type' in import.meta) || import.meta.type === 'module') ? … but I was thinking that would be in progression and open to variation.
So, first we want import.meta to not throw to pan out (the least amount of objections imho being just undefined at first), so this expression then would not be a parse error.
Workable?
For one, the proposal for it explicitly and intentionally disallows it to be parsed in Scripts.
@ljharb Can we know that the intent was to prevent this or could this just have been the leftover from the pre import() revisions?
just to be clear, I'm against import.meta.type. The objects should be identical to the ones in modules.
just to be clear, I'm against import.meta.type. The objects should be identical to the ones in modules.
@devsnek I'm willing to leave this in for the right time, but would it be reasonable to consider letting it afford more meta about its source, irrespective of bikeshedding, fields… etc.?
Side question to help me appreciate things better please… I hope it is fair to ask, is there a sense of reluctance with wanting to block sometimesModule.js from ever panning out?
sometimesModule.js shouldn't be possible. If it is possible, we have a bug.
@SMotaal the intent is explicit: https://github.com/tc39/proposal-import-meta#proposed-solution
sometimesModule.js shouldn't be possible. If it is possible, we have a bug.
@devsnek It would be really helpful to help others understand why it should though? At least I disagree with this, but if there is more to it beyond preference I am more than happy to revise my position. Please help me appreciate your rationale for it.
@SMotaal the intent is explicit: https://github.com/tc39/proposal-import-meta#proposed-solution
@ljharb Assuming you might be referring to this bit (please be more explicit otherwise)…
and should not be repurposed for information about the currently-running classic script.
If so, that is natural in the progression of spec things… as in proposed things must not be watery, they must be explicit (and that is not the same as contention for what is being asked), but later things are subject to elicit such things to be changed, right?
@smotaal ambiguity breeds confusion. This is one of the reasons I'm not a fan of type: module. Changing the location of a file on disk really shouldn't change how it's interpreted by node.
@SMotaal ambiguity breeds confusion. This is one of the reasons I'm not a fan of
type: module. Changing the location of a file on disk really shouldn't change how it's interpreted by node.
@devsnek I am not talking about just node but even node can have more than one way of looking at a file for many reasons — ie same file but not the single instance of some node build — right?
Sure different versions of node could do that, but they could also break your detection system. I don't think that's a path worth going down.
I am still feeling I am missing context which I really am curious about and hope you can appreciate me wanting to step back from those tangents and may be try and approach things differently…
It helps to directly restate the ask here… import.meta not being a parse error being an opinion of equal merit and one held by those using the language and hitting this to want to explore things more closely, as in purely about the semantics of ECMAScript, not specifics of some implementation, including our own work-in-progress, or node in general.
Two views on a matter here is okay with me, but if it is not merely refuting my view because it is opposite to your own, it might help to reconsider things from the other perspective, not consider it being wrong the foregone conclusion (sorry, this is just how it feels from my where I'm sitting) to the discussion, and that would help make this feel like a fair space for debating with good constructive arguments.
Conclusion: This clearly is not wrong from my perspective here, based on this discussion so far, just different and I have not picked up on anything that leads to this breaking semantics (aside from not throwing I mean).
If all you want is a file that could be either, just uses import(), maybe just:
'use strict';
const isModule = typeof require === 'undefined';
Not sure why it would need import.meta - the above seems simpler than the import.meta check.
typeof require
here is fair for node specifically, not generally though — as in sometimesModule.js cannot dictate which runtime and loading approach is used, and just as loading can mean cjs or esm in node, it can mean more than just esm elsewhere because loading existed there too prior to esm times (ie not always just typeof require).
@jkrems fair?
That's where this becomes the better choice.
Yes… but also above.
If this doesn't work due to some loader, then the loader is broken - it's mandated by spec.
here is fair for node specifically
Right, but what exactly do you want to tell apart then? If it's not about node specifically, there's way more than CJS (which isn't an ECMA script) vs. ESM. There's also script, multiple kinds of closure-compiler modules, etc.. Can you explain your use case?
I'll be checking back on this later, feels cyclic at this point, sorry, and really appreciate everyone's input.
@jkrems — sorry I am out of breath 2 hours later and realize you only just joined.
It seems that it is a fair discussion to keep open.