Closed jkrems closed 4 years ago
/cc @nodejs/modules-active-members FYI
with require, you can use path functions to alter the specifier you pass in, so you don't necessarily need createRequire
; is this an issue because there's no similar URL navigation functions for use in import()
?
createRequire
exists because it's the only way to get access to a require
without creating a cjs module, but import()
exists everywhere. It seems to me like what we actually need is an exposed loader.resolve
.
It seems to me like what we actually need is an exposed loader.resolve.
Sure, we could have a loader.resolve
instead but it would be a bit more verbose in what I expect to be the more common case (load relative to). It would also imply exposing a loader
. Maybe {url,module}.urlFromSpecifier(specifier, base)
would be easier to add?
Also, import.meta
may be expanded in the future. In which case the local import
plus resolveSpecifier
isn't enough to get that data.
Yeah there are a lot of options, I just dislike curried import as a core API. More generally I'm thinking of patterns like import(z.resolve(x, y))
or z.import(x, y)
.
import.meta.resolve
has been long-considered a web possibility in future. The key question there is sync or async, which has ramifications for our resolver and loaders as well. As I've said before this is an area where Node.js may have to make the first move with the web to follow on compat, as opposed to the usual pattern where we can follow web specs as the source-of-truth as it were. But some collaboration may be needed on this.
I'd be ok with an async import.meta.resolve
but have concerns about it being synchronous. Additionally, whatever the API, it should be made so that it doesn't appear to have problems if https://github.com/sebmarkbage/ecmascript-asset-references moves forward.
One thing I'd like to bring up again is that the issue covers both relative import and getting access to an equivalent import.meta
object. The latter isn't super valuable right now (since we only expose .url
) but may be more valuable in the future if we keep adding things to the meta object. If it would be just a resolution API, I'd vote for new URL('import:x', base)
, betting hard on sync/static resolution.
if you want an import.meta object I think you should need a reified source text module. we shouldn't be creating fake ones.
So, I think that we want to distinguish finer details about createImport
, it is not clear cut as createRequire
:
createImport
as a direct first-class conforming helper would be with (module.scope) { eval('specifier => import(specifier)') }
(theoretical).
createImport
as an indirect/symbolic first-class conforming helper would be referrer => specifier => import(resolveModuleURL(specifier, referrer))
where resolveModuleURL
would be the wrapper for the host resolver behaviour from the referrer.
Going from the theoretical (1) to the practical (2) can outline some of the concerns about passing around things like import.meta.resolve
.
Instead, I'd like to find a lower-level way to expose the theoretical one, ie you cannot import cleanly per-specs if you are doing it on behalf of a module before or without that module being one β at least not for first-class instrumentation/tooling code (unless it wants not to be).
So once we have the module, we want to marshal calls from all related createImport()
functions through it, and that is as simple as exposing (internally at least) the evaluated wrapper inside the scope (ie after binding).
What we can do is consider createImportResolver
and createRequireResolver
.
Update β I am backtracking here a bit because host resolve and host import are separated out for a good reason, if you are going to
import(createImportResolver(r)(s))
you are not importingr
but you are also not accounting for the effects of doing so.Update β It also helps to consider if this resolver would be wired to the actual resolver instance (ie affect state for subsequent
import
) or not.
I'd vote for new URL('import:x', base), betting hard on sync/static resolution
@jkrems worth noting that the way new URL(β¦)
behaves about schemes will take some work, we want to resolve against file:
or http:
first and then swap the prefix:
we want in place β I'm concerned here with a little more than Chromium's URL
implementation.
Note β May be this becomes a little relevant β sorry for the hard read
if you want an import.meta object I think you should need a reified source text module.
Can you produce a complete one with the VM library? (A runInThisContext for modules, kinda?) The APIs I've seen all seem to expect the caller to provide the import meta and dynamic import implementation... But if you can, you could always just make a module with that (at a similar path to the desired url), and then have it export a wrapper around its import/import.meta?
@weswigham I think the issue here is that import.meta
implies an import should take place (or at least that early errors don't prevent it) and that is assuming too much about things (at least if we are considering import.meta
to become spec at some point, unless I'm not looking in the right place(s), it is not).
Fair to note, it not being that means we are not really breaking the spec, but I am not sure it is favourable to be too literal here (even I would see the value of not being literal here).
can y'all expand on why you need the meta object from a source text module? it seems like a rather random request from my perspective, so more info would help.
It's the most likely place to put APIs that are module-relative. It's definitely speculative at this point. If we never add any interesting APIs to import.meta
, it won't matter.
I strongly disagree there is a need for a new dynamic import, and we also have the ability to achieve the same goals via import.meta.resolve
now.
Is your feature request related to a problem? Please describe.
Right now we can easily require files relative to a given location. The same isn't possible for
import
. One possible use case is "import third party tool X relative to the working directory from within a globally installed CLI tool".Example: https://github.com/zeit/now/blob/7e75d8c1a3485b7121f919e5035dc174ae9d629a/packages/now-next/src/dev-server.ts#L14
Describe the solution you'd like
Note:
$import.meta
exposes the same API as the usualimport.meta
but would get a clean copy. It would not be the same object as the meta object forfile:///path/to/cwd/.app
if a module with that URL actually exists.Describe alternatives you've considered
One alternative would be to use
require
for resolution but that has the downside of not matching whatimport
resolution would do. It would also not give access to theimport.meta
APIs.