Skip to content

src,lib: implement import.meta#18368

Closed
targos wants to merge 1 commit into
nodejs:masterfrom
targos:import-meta
Closed

src,lib: implement import.meta#18368
targos wants to merge 1 commit into
nodejs:masterfrom
targos:import-meta

Conversation

@targos

@targos targos commented Jan 25, 2018

Copy link
Copy Markdown
Member

The feature is still behind the --harmony-import-meta V8 flag.
This commit implements the C++ callback that is required to configure
the import.meta object and adds two properties one property:

  • url: absolute URL of the module
    - require: CommonJS require function

/cc @nodejs/esm @MylesBorins @nodejs/tsc

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

ESM

@targos targos added dont-land-on-v4.x esm Issues and PRs related to the ECMAScript Modules implementation. labels Jan 25, 2018
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. labels Jan 25, 2018
Comment thread doc/api/esm.md Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit: we usually lowercase primitive types in docs (i.e. {string})

@guybedford

Copy link
Copy Markdown
Contributor

Is the idea with import.meta.require to then implement defaulting ".js" loads from ES modules as being treated as ES modules themselves? I think we should be clear exactly what that proposal is, so it can be adequately reviewed. It could also make sense to separate this out into a separate PR with the full proposal to help focus discussion.

Comment thread doc/api/esm.md Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you link to the require() docs here.

@bmeck

bmeck commented Jan 25, 2018

Copy link
Copy Markdown
Member

@targos can we split out import.meta.require for now since thats a bigger talk than the non-controversial import.meta.url

@targos

targos commented Jan 25, 2018

Copy link
Copy Markdown
Member Author

@bmeck done. I kept the JS initialization function for later use.

@guybedford guybedford left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@targos

targos commented Jan 25, 2018

Copy link
Copy Markdown
Member Author

@ljharb ljharb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this add some tests that import.meta.nothing is an error, as well as import.meta.toString?

@bmeck

bmeck commented Jan 25, 2018

Copy link
Copy Markdown
Member

@ljharb is the following check fine?

assert.stictEqual(Object.getPrototypeOf(import.meta), null);
assert.deepEqual(Object.keys(Object.getOwnPropertyDescriptors(import.meta)), ['url']);

Comment thread src/module_wrap.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm wondering if there's any perf hit with moving this to the js callback. if there isn't i would suggest doing that just for consistency.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean by passing the URL string to the JS callback?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no i mean like

importMetaCallback(wrap, meta) {
  // attach wrap.url to meta in a safe way here
}

@ljharb

ljharb commented Jan 25, 2018

Copy link
Copy Markdown
Member

@bmeck should probably be gOPDs, but sure, that sounds great!

Comment thread test/es-module/test-esm-import-meta.mjs Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per #18368 (review) we can add

assert.stictEqual(Object.getPrototypeOf(import.meta), null);
assert.deepEqual(Object.keys(Object.getOwnPropertyDescriptors(import.meta)), ['url']);

@apapirovski apapirovski Jan 25, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the second line use Reflect.ownKeys(import.meta) instead? Or am I missing something?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems fine

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change ['urls'] to [{ enumerable: true, writable: false, configurable: false, value: 'url' }], eg

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reflect.ownKeys is good because it also covers symbols; but it doesn't cover descriptors.

@MylesBorins

Copy link
Copy Markdown
Contributor

As import.meta will require a flag in V8 to turn on. Does it make sense to make the --experimental-modules flag also flip the appropriate V8 flag?

@devsnek

devsnek commented Jan 25, 2018

Copy link
Copy Markdown
Member

probs not, we don't do it for import() and the features are still experimental above node's proverbial head.

@MylesBorins

MylesBorins commented Jan 25, 2018

Copy link
Copy Markdown
Contributor

@devsnek I plan to open a PR to do the same for import() fwiw

edit: both features are shipping in chrome with the flag turned off... the flag currently is only turned on in V8 to embedders from having the apis called without the callback being set (would have an unhandled rejection)

Comment thread src/module_wrap.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiny nit: Can you use Environment::GetCurrent(context)? Getting it from the isolate only looks up the context on the isolate and takes it from there

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah thanks! I didn't know there was a Environment::GetCurrent(context)

@Fishrock123

Copy link
Copy Markdown
Contributor

Can we add meta.dirname, meta.filename, and meta.isMain?

@bmeck

bmeck commented Jan 26, 2018

Copy link
Copy Markdown
Member

@Fishrock123 you can get dirname and filename from the url, and they get normalized always when they go through becoming a URL (thank goodness). I'm neutral to isMain but feel like thare are various ways to figure it out as well, just nothing convenient like the dirname or filename solution.

@Fishrock123

Copy link
Copy Markdown
Contributor

you can get dirname and filename from the url

I'm not really sure that means we should force users to always parse the url when there is already a precedent set here.

I'd love to know how you can figure out inMain without doing it internally, but we'll still need it if doing so is difficult.

@devsnek

devsnek commented Jan 26, 2018

Copy link
Copy Markdown
Member

personally i'm -1 to dirname/filename. you have your url which is generally enough and to be honest the cases where you need the filename of the file you wrote are imo generally rare enough to warrant you having to parse the url yourself.

@bmeck

bmeck commented Jan 26, 2018

Copy link
Copy Markdown
Member

@Fishrock123

I'm not really sure that means we should force users to always parse the url when there is already a precedent set here.

The precedent exists but normalization of \\ to / simplifies things and fixes some common cross platform bugs, also .url is compatible between both Node and browser environments. Even if we supplied .filename there are also some problems of passing it around to import() etc. if you intended to preserve query and hash fragments. I see history in .dirname / .filename but don't think that is enough when the workflow exists with .url and avoids some compatibility both with OS and host environment considerations.

I'd love to know how you can figure out inMain without doing it internally, but we'll still need it if doing so is difficult.

Parsing out process.argv/process.cwd() vs the location identifier, we used to do this way back when at Nodejitsu and the technique still works. Very ugly to do though. Has a nice benefit of wrappers being able to setup a new "main" entry point without spawning a new process though.

@bmeck

bmeck commented Jan 29, 2018

Copy link
Copy Markdown
Member

@jdalton the main attraction to frozen things like that is that you can't bail out of static analysis if it becomes mutable. Bailing out is probably fine if people have to do it for browsers anyway I think, but still a little bit of a question on who is actively wanting to rewrite .url and why instead of doing some source code transform.

@ljharb

ljharb commented Jan 29, 2018

Copy link
Copy Markdown
Member

@jdalton I just said it'd be unfortunate; not that i'd "fight" for it. I could ask the same question of browsers - why would they ship a fully unlocked descriptor without consulting with node first? "Interoperable" could also mean that browsers ship a non-writable non-enumerable descriptor, for example.

@jdalton

jdalton commented Jan 29, 2018

Copy link
Copy Markdown
Member

@bmeck

The main attraction to frozen things like that is that you can't bail out of static analysis if it becomes mutable.

I think it's totally fine to bring those things up as additions or changes to proposals/specs/browsers-early-implementations. However, the ship has kinda sailed on the import.meta.url front for now and the PR should align with how it is in browser-land. If it's changed later, after spec/browser discussions or whatever, then great!

Comment thread src/module_wrap.cc Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we just return and leave the object empty? The upcoming vm.Module PR will make it possible to have Modules that are not in the core module map.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't the vm.Module code just delete the property if it is configurable?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but this line throws an error. We don’t want that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove the throw, but we will probably have to come up with a solution to configure import.meta in vm.Module

@targos

targos commented Jan 30, 2018

Copy link
Copy Markdown
Member Author

@BridgeAR BridgeAR added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jan 31, 2018
@jdalton

jdalton commented Jan 31, 2018

Copy link
Copy Markdown
Member

@targos Just curious, can you check that eval("import.meta") errors in ESM.

For example in Chrome:

eval("import.meta")
// throws "SyntaxError: Cannot use 'import.meta' outside a module

@targos

targos commented Jan 31, 2018

Copy link
Copy Markdown
Member Author

@jdalton This is already tested by V8:

assertThrows(() => eval('import.meta'), SyntaxError);

@jdalton

jdalton commented Jan 31, 2018

Copy link
Copy Markdown
Member

@targos Yep. I know Node had to do some extra work to make static import errors more clear, so I was curious if things were OK for import.meta.

@targos

targos commented Jan 31, 2018

Copy link
Copy Markdown
Member Author

@jdalton Here is the output:

$ cat test.mjs

eval("import.meta");


$ ./node --experimental-modules test.mjs
(node:16949) ExperimentalWarning: The ESM module loader is experimental.
SyntaxError: Cannot use 'import.meta' outside a module
    at file:///home/mzasso/git/nodejs/node/test.mjs:2:1
    at ModuleJob.run (internal/loader/ModuleJob.js:106:14)
    at <anonymous>

@targos

targos commented Jan 31, 2018

Copy link
Copy Markdown
Member Author

I had to rebase because of a conflict.
New CI: https://ci.nodejs.org/job/node-test-pull-request/12847/

@jdalton

jdalton commented Jan 31, 2018

Copy link
Copy Markdown
Member

Here is the output:

Thanks! It looks like it's missing the arrow stack decorator.

@TimothyGu

Copy link
Copy Markdown
Member

Other than the conflict, is there anything preventing this from getting merged?

Implement the C++ callback that is required to configure the
`import.meta` object and add one property:
- url: absolute URL of the module
@BridgeAR

BridgeAR commented Feb 1, 2018

Copy link
Copy Markdown
Member

One more CI before landing: https://ci.nodejs.org/job/node-test-pull-request/12877/

@BridgeAR

BridgeAR commented Feb 1, 2018

Copy link
Copy Markdown
Member

Landed in 9e1a6f8

@BridgeAR BridgeAR closed this Feb 1, 2018
BridgeAR pushed a commit to BridgeAR/node that referenced this pull request Feb 1, 2018
Implement the C++ callback that is required to configure the
`import.meta` object and add one property:
- url: absolute URL of the module

PR-URL: nodejs#18368
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
@targos targos deleted the import-meta branch February 1, 2018 12:56
@addaleax addaleax removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Feb 4, 2018
MayaLekova pushed a commit to MayaLekova/node that referenced this pull request May 8, 2018
Implement the C++ callback that is required to configure the
`import.meta` object and add one property:
- url: absolute URL of the module

PR-URL: nodejs#18368
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. esm Issues and PRs related to the ECMAScript Modules implementation. lib / src Issues and PRs related to general changes in the lib or src directory.

Projects

None yet

Development

Successfully merging this pull request may close these issues.