-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
Import.meta.require #21317
Import.meta.require #21317
Conversation
Marking as |
As long as (There's plenty of use cases for conditional synchronous/immediate/same-tick imports that the JS language doesn't provide for, and that includes being able to conditionally bring in ESM) |
@ljharb this implementation uses the exact same mechanism to create the module / require object as we use in the CJS IIFE. TLDR, this require is identical from the require in CJS and will inherit any changes without us having to make changes in this implementation... it is an instantiation and assignment. |
I'm -1 on this for two reasons:
Edit: 3. Universal workflows - #21317 (comment)). |
@guybedford ftr, it wouldn't interfere with those benefits if rollup took the time to implement them for static CJS, which is identically as tree-shakeable as ESM - iow, the only "interference" would be because rollup only has partial support for treeshaking modules - where "modules" includes both ESM and CJS. |
lib/internal/process/esm_loader.js
Outdated
if (req !== undefined) | ||
return req; | ||
const url = new URL(meta.url); | ||
const path = url.pathname; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use getFilePathFromURL from internal/url here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
@@ -3,20 +3,38 @@ | |||
import '../common'; | |||
import assert from 'assert'; | |||
|
|||
const fixtures = import.meta.require('../common/fixtures'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be exposed by common.mjs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that using it this way offered an extra smoke test for import.meta.require.
more than happy to change it though
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at best we can take it as an excuse to build up common.mjs... i don't like the idea of "smoke tests" but that's just an opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I think this PR should include the documentation about this feature. |
If we do go through with this, I'd prefer we remove some things that might get confusing like |
require.resolve uses require.extensions, and it will break a bunch of use cases if import.meta.require doesn’t respect them. |
👍 for removing the properties if they exist (e.g. |
@ljharb it would continue to function off the |
@bmeck would you like to push a fixup commit to remove the properties you think shouldn't be exposed? |
@guybedford to your two points
There will be a follow up PR to this in which I plan to propose removing transparent interoperability. It seems to me like this specific point only becomes an issue if we remove that capability. In the mean time, with the current implementation, individuals are free to statically import a cjs module or dynamically import it. If people are planning to dynamically bring in CJS it does seems odd to require them to wrap it in a process via dynamic import. When I propose removing transparent interoperability I plan to implement a way to trap errors related to importing common.js and give extremely clear errors about how to use import.meta.require. As it stands right now people already need to know the "type" of the module as CJS cannot do named exports. I personally ran into this exact problem trying to
While I will agree that this is a potential edge case I am not convinced that this specific case significantly breaks expectations. People are already using both edit: @guybedford I've moved the copy from our conversation over to the modules issue as I think that might be a better place to have the conversation... leaving this issue to focus on technical merits of the implementation. Feel free to respond in either thread |
One more CI, should hopefully fix windows error https://ci.nodejs.org/job/node-test-pull-request/15443/ @mcollina I've made some basic docs changes. LMK what you think. Will expand as implementation is clearer |
21b9753
to
f236623
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
Another important point here is that here is no way for browsers to provide With transparent interop on the other hand, something as simple as a package name map could provide this support. |
Ok, one more CI now that the properties have been removed as requested above. I've also documented these. If anyone has ideas on how to improve docs please feel free to push a fixup commit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm against this so long as we can support the same use cases through transparent interop, for reasons as described in #21317 (comment).
lib/internal/process/esm_loader.js
Outdated
delete req.cache; | ||
delete req.extensions; | ||
delete req.main; | ||
delete req.paths; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
req.paths
do you mean req.resolve.paths
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this confusion - would it be better to keep this to a minimal "only expose the pure function without any additional properties"? E.g. import.meta.require = actualRequire.bind(null)
to get rid of all potential properties..?
EDIT: This was meant as a "for the initial implementation".
One of @jkrems questions got lost in a refactoring
|
People use |
Keeping things simple, e.g. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to cross ref a recurring comment on PRs that are doable in userland JS that occured in the createRequireFunction
PR and affects this one as well : #19360 (comment)
A number of members of core have concerns about adding APIs that can be recreated in userland. This PR in particular can be recreated by using the example userland implementation of createRequireFunction
and adding the following to the top of any module that wishes to have import.meta.require
:
import Module from 'module';
function makeRequire(filepath) {
const m = new Module(filepath, null);
m._compile('module.exports=require', filepath);
return m.exports;
}
// extract https://github.com/nodejs/node/blob/9deca876bb94626564184ad263ff80dc8042808b/lib/internal/url.js#L1395-L1403
// to get getPathFromURL
import.meta.require = makeRequire(getPathFromURL(import.meta.url));
As this comment consistently arises in a variety of location I'd like to delay both this PR and the one referenced until a quorum on what is required to justify implementation of new APIs into core related to these features. Both are able to be implemented purely in JS and core contributors consistently comment about how we should not add features that can be recreated using purely JS userland implementations.
@bmeck well:
This will not land without further discussion anyway :) |
@benjamingr true, but that is a different reason than my current blocker. |
@bmeck well, |
@benjamingr per my comment in #19360 (comment) , I note that while The experimental status of ESM is unrelated to the ability to recreate this PR in JS which is the claim for why this PR and others cannot land. Even without regard of this being an addition to the ESM bootstrap, the addition of this is possible using JS alone unless we cannot access the CJS module system from ESM which seems problematic if we intend to use CJS within future applications. We can talk about the claim of features being implementable in JS as being a blocker and if that is a valid argument, but it is being used in multiple places by multiple people and I am using it here. |
Right, but it's not using a public API (it's using In fact - this PR is exactly exposing a capability that is not possible in userland JS without accessing internal APIs. |
@benjamingr we have public APIs using
I disagree on |
I think there's an important distinction to be made between "fragile implementation details that the ecosystem depends on" and "official public APIs". Because otherwise this just becomes a circular argument. Yes, we can't remove or rename If you are suggesting to make That being said - I can understand your frustration. The somewhat arbitrary use of "can be done in userland" without any clear rubric for what it actually means opens the door for people shutting down APIs they don't like or don't think are important because technically any API could be done in userland with enough imagination. Which is problematic and worth addressing imo. |
I've outlined the basic rules in #19360 (comment). Seems clear enough to me but happy to take questions. |
Correct me if I'm wrong but doesn't this introduce some load order problems in the load graph? @bmeck would probably be more in tune with the details than myself. |
@Fishrock123 you can only use |
I think we should kick this to the modules working group then since @MylesBorins has already expressed that is his goal for the future. |
b1d4068
to
bf9a18c
Compare
This adds require to the import.meta object This can be used as a mechanism to get interoperability between common.js and esm.
bf9a18c
to
cd7191c
Compare
rebased against master and added @zenparsing's fix to support node_modules |
Closed in favor of nodejs/ecmascript-modules#1 |
Hey All,
This builds on top of @targos's earlier implementation of
import.meta.require
. It has been refactored to work with our current layout for the module system. I've also added some basic tests, let me know if you think we need something more robust.@nodejs/modules I am not planning to land this without consensus from the group, but I think that this is a necessary base feature no matter what implementation we move forward with. I'll open a corresponding issue to discuss.