nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨

Home Page:https://nodejs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bare specifiers definition.

gitspeaks opened this issue · comments

Affected URL(s)

https://nodejs.org/docs/latest-v20.x/api/esm.html#terminology

Description of the problem

"Bare specifiers like 'some-package' or 'some-package/shuffle'. They can refer to the main entry point of a package by the package name, or a specific feature module within a package prefixed by the package name as per the examples respectively. Including the file extension is only necessary for packages without an "exports" field."

Incorrect, including the file extension in bare specifiers is not necessary for packages with "main" field.

Example:

index.mjs:

import * as module from 'mymodule'
module.greet();

node_modules/mymodule/index.mjs:

export function greet() {
    console.log('Hello from module!');
}

node_modules/mymodule/package.json:

{
  "name": "mymodule",
  "version": "1.0.0",
  "main": "index.mjs",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}
node index.mjs

Hello from module!

Would you like to open a PR to add your proposed changes?

I don't know if your example shows that the sentence is incorrect. It would be incorrect if you were able to show an example of a package with an "exports" field where adding the file extension would be necessary.
IIUC your example disproves the sentence "Including the file extension is always necessary for packages without an "exports" field.", but that sentence is not in our docs.

From the docs: "Including the file extension is only necessary for packages without an "exports" field."

The package in my example does not have an "exports" field and yet it is not necessary to include the file extension to load it.

It's as simple as that.

I don’t see a contradiction, but I’m not a native speaker so maybe there’s some nuance I’m missing. That being said, if someone suggests a better wording, it would likely gets accepted.

I don’t see a contradiction, but I’m not a native speaker so maybe there’s some nuance I’m missing. That being said, if someone suggests a better wording, it would likely gets accepted

I don't understand what you're saying. I didn't suggest anything. I pointed at a false assertion, no more, no less.

I didn’t say you suggested anything.

I pointed at a false assertion

Are you saying that “only necessary” and “always necessary” mean the same thing? I’m not trying to sound dismissive, I’m only trying to express my interpretation of the docs you cited.

I believe @gitspeaks is suggesting that according to the documentation, you must specify the full file path (with extension) when the package doesn't export anything with exports, although main can also serve this purpose.

But, in my opinion, @gitspeaks is misunderstanding the documentation. IIUC It is referring to getting a module by its path, and not by its module name (E.G my-module/my-file.js)

They can refer to the main entry point of a package by the package name, or a specific feature module within a package prefixed by the package name as per the examples respectively

In your example, you are getting the main entry point. Do you also not require an extension when getting a feature module?

@aduh95

Are you saying that “only necessary” and “always necessary” mean the same thing?

In this context, I don't see a reasonable interpretation otherwise.

Quote: "Including the file extension is only necessary for packages without an 'exports' field."

  1. The sentence says nothing about packages WITH an 'exports' field.
  2. If you interpret "only necessary" not as "always necessary," then the logical implication is that there are packages WITHOUT 'exports' fields that must include a file extension, and there are packages that don't.

In other words, the sentence says nothing! Does that seem reasonable to you?

@RedYetiDev I understand the documentation completely.

Here is the example adjusted to show a bare specifier that includes a file extension. Note that the module does not include an 'exports' key.

However, all this is irrelevant to the point I'm making.

index.mjs

import * as module from 'mymodule/index.mjs'
module.greet();

node_modules/mymodule/index.mjs

export function greet() {
    console.log('Hello from module!');
}

node_modules/mymodule/package.json

{
  "name": "mymodule",
  "version": "1.0.0",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}
node index.mjs

Hello from module!

And if you remove the extension?

(Also, if this is irrelevant, than I don't think I am understanding the statement you're making)

And if you remove the extension?

Of course it won't work, the module does not have an export field.

(Also, if this is irrelevant, than I don't think I am understanding the statement you're making)

Read: "Including the file extension is only necessary for packages without an 'exports' field or a 'main' field."

Does this help?

Now, you might ask yourself why I didn't just state: Including the file extension is only necessary for packages without an 'exports' field or a 'main' field from the very beginning. The answer is simple: I don't know if including the file extension is only necessary for packages without an 'exports' field or a 'main' field, or if there are other exceptions.
I just discovered one.

In this context, I don't see a reasonable interpretation otherwise.

If you ask yourself "is it necessary to include the file extension?", the docs responds "only for packages without an "exports" field". The fact that you don't need to provide an extension to load the "main" module doesn't seem to contradict that.

Read: "Including the file extension is only necessary for packages without an 'exports' field or a 'main' field."

That would be incorrect, you still need to include the file extension (e.g. try to load mymodule/index, it will fail no matter if there's a "main" field or not; it could succeed only if there's an "exports" field with a ./index entry (or a subpath pattern that includes ./index)).

I’m sorry, but I’m still not understanding the issue here, I think the docs are correct (as @aduh95 has said)

To sum-up:

import * as module from 'mymodule'

  1. 'mymodule' is bare specifier
  2. 'mymodule' is a name of a package
  3. the project.json does not include exports field
  4. the project.json does include a main field.
  5. No need to specify any file extension.

So, a change like this would be what you find sutable? Or maybe a removal of the note at the end?

Original:

Bare specifiers like 'some-package' or 'some-package/shuffle'. They can refer to the main entry point of a package by the package name, or a specific feature module within a package prefixed by the package name as per the examples respectively. Including the file extension is only necessary for packages without an "exports" field.

Changed:

Bare specifiers like 'some-package' or 'some-package/shuffle'. They can refer to the main entry point of a package by the package name, or a specific feature module within a package prefixed by the package name as per the examples respectively. Including the file extension is only necessary for requiring feature modules in packages without an "exports" field.

If the goal of the 'note at the end' was to simply say that the bare specifier of a 'feature module' is the file name of the feature module prefixed by the package name, then of course I would delete the mention of the 'exports' field of a package, as it is simply irrelevant.

I would just write:

Bare specifiers are module identifiers like 'some-package' or 'some-package/shuffle'. These specifiers can point to the main entry point of a package by using just the package name or to a specific feature module within a package by prefixing the package name to the feature module file name like 'some-package/some-feature.mjs'.

edit: "some-package/some-feature.mjs"

Bare specifiers are module identifiers like 'some-package' or 'some-package/shuffle'. These specifiers can point to the main entry point of a package by using just the package name, or to a specific feature module within a package by appending the feature-module file path to the package name, E.G. some-package/some-feature.mjs.

Note: I've adjusted this from the original, my changes are marked in bold.

@aduh95 would this wording work? (with any slight adjustments that would need to be made)

"by appending the feature-module file path to the package name"

I disagree. "feature-module file path" can be confused with the file's file-system path.

Just add another example with a deeper path:

"Bare specifiers are module identifiers like 'some-package' or 'some-package/shuffle'. These specifiers can point to the main entry point of a package by using just the package name or to a specific feature module within a package by prefixing the package name to the feature module file name like 'some-package/some-feature.mjs' or 'some-package/some-submodule/some-feature.mjs."

file path refers to the path-to-a-file (E.G. /dir/file.txt)
file name refers to the file's basename + extension (E.G. file.txt).

relative file path is probably the best term, with file path in second.

Bare specifiers are module identifiers like 'some-package' or 'some-package/shuffle'. These specifiers can point to the main entry point of a package by using just the package name, or to a specific feature module within a package by appending the feature-module's relative file path to the package name, E.G. some-package/some-feature.mjs.

I suggest:

"Bare specifiers are module identifiers like some-package or some-package/shuffle. These specifiers can point to the main entry point of a package by using just the package name, or to a specific feature module within a package by using the feature module's file path relative to the package name like some-package/some-feature.mjs or some-package/some-module/some-feature.mjs"

or some-package/some-module/some-feature.mjs

This might be redundant, but I'd like for @nodejs/loaders to weigh in on this "issue" in general, that group (including @aduh95) are the final judges, not me.

Alternatively:

"Bare specifiers are module identifiers like some-package or some-package/shuffle. These specifiers can point to the main entry point of a package by using just the package name, or to a specific feature module within a package by using the feature module's file path relative to the package name like some-package/path/to/some-feature.mjs

Including Exported Feature Module Paths:

"Bare specifiers are module identifiers like some-package or some-package/shuffle. These specifiers can point to the main entry point of a package by using just the package name, or to a specific feature module within a package by using the feature module's file path relative to the package name, like some-package/path/to/some-feature.mjs, or by using an exported feature module's path, like some-package/some-feature."