-
Notifications
You must be signed in to change notification settings - Fork 30.2k
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
export
spec clarification with require
xor import
and non-JS cases
#41686
Comments
@nodejs/modules |
A package name on the command line is “whatever the package’s package.json says the format of the entry point is”, which is deterministic from the file extension of the main/exports dot, and optional “type” field. There wouldn’t be any standard behavior for module types that don’t exist, like css or html. |
Ok, that makes sense. I'll do that. Thanks! |
Technically from HTML there's a valid 3rd option ("script"?) in addition to
That feels sensible, partially also because I'm not sure what the semantics are of "including JS from CSS" (does it fail if the CSS isn't imported in turn, transitively, by some other JS..?). Effectively, this seems like something that might have to be up to tools because these non-JS edges may have wildly different semantics across tools (e.g. import-CSS as a side effect vs. as importing a stylesheet object). My guess is that just considering those to be But my cop-out answer would be "node isn't in the best position to make a recommendation because it lacks domain expertise". I would expect this question to require a chat between parcel/esbuild/webpack/rollup... because in that group there's a higher chance of an informed outcome. :) |
Node.js itself does not support package resolution for the entry point so does not hit this problem. Node.js mains can only be direct file system paths, and then Node.js uses the standard format algorithms (as mentioned by @ljharb) to determine the initial module format. So the entry-as-a-package problem is unique to build tools. In my own tooling I make |
Thanks so much for your replies.
I'm not sure either. This just isn't allowed in esbuild (it's a build error). I think this case would be more for other non-JS assets that end up using the
I don't think the file extension applies here because the command line isn't a file, and doesn't have an extension. This corresponds to someone doing What I took this to mean was to inspect the
I could also see " |
@evanw type module changes what .js means but it doesn’t force import; i can still require a package with type module if it’s main/dot points to a .cjs file (and probably also a .json file) |
I believe you're talking about the extension of {
"name": "pkg-foo",
"exports": {
".": {
"import": "./foo.mjs",
"require": "./foo.cjs"
}
}
} We are trying to figure out what conditions to apply so we can figure out what file to use as the entry point. We don't know whether to apply Maybe you're saying esbuild should just not apply the |
this seems to have some overlap with determining which loader to initiate for the entry point as in #41552 |
@evanw i see what you mean. since node's default entry point type is CJS, and will remain so for the foreseeable future, that's what i'd suggest assuming. Packages that aren't concerned with backwards compatibility (imo, user-hostile ones) omit "main" entirely, so a fallback to "main" isn't something you can rely on. |
@ljharb the entry point isn't CJS there is a function that determines which loader is used |
@bmeck Good to know! If it's a package name then, how does that function determine it? |
@ljharb CLI args are always converted to a file path (either as url or path string depending) so you cannot ref a package name. |
gotcha. and what if i do |
@ljharb that is actually complex... it first does a CJS resolve against the full file path (normally , not always) and then determines if it should do an ESM or CJS load operation which can be a bit thrashy |
Sounds like "CJS is the default" would apply, then, altho with an ESM fallback. |
@ljharb that isn't what happens though |
node/lib/internal/modules/run_main.js Lines 30 to 45 in 775bfd1
|
I just ran a test of the other bundlers: https://github.com/evanw/entry-point-resolve-test. Webpack and Rollup are consistent with each other, and Parcel just consistently fails to handle this case. It seems like the rules should be as follows:
Since the other bundlers are consistent and it sounds like perhaps there isn't strong consensus here, I think I should probably just do what they do. |
I agree with this approach. I think for most cases, if the author has included Where does |
Couldn’t the ordering of the conditions matter? That way, whatever they put first is the priority. |
I went with |
Affected URL(s)
https://nodejs.org/api/packages.html#conditional-exports
Description of the problem
I'm coming here from evanw/esbuild#1956. Specifically the esbuild bundler implements node's spec for
exports
inpackage.json
files. Node's documentation forexports
says this:This is what esbuild implements. The case I'm looking for clarification on is that there are packages that just have
require
andimport
but notdefault
. This is reasonable as the example in the documentation also doesn't include adefault
condition, and the documentation saysimport
andrequire
are mutually exclusive (i.e. exactly one should be present).However, esbuild performs the following kinds of path resolution:
import-statement
require-call
entry-point
import-rule
url-token
I understand what should happen with the first two but not with the last three. An entry point is path resolution that happens due to a package name provided on the command line. There is no import or require in that case. And the last two happen when you import things from CSS (something a bundler has to deal with) where there is also no JS
import
statement orrequire
call. If esbuild supported importing things from HTML, which it may one day, there would also be those cases to consider.Right now esbuild handles these non-JS cases by still running the
exports
logic but just without theimport
orrequire
conditions active, since it's neither an import nor a require. But then that breaks when there's nodefault
condition. Do you have any opinion for what should happen here, as the authors of this specification? Some options:import
orrequire
and fail path resolution if nothing applies (esbuild's current behavior)import
orrequire
and fall back to legacymodule
/main
fields if nothing appliesimport
orrequire
to apply arbitrarilyimport
andrequire
exports
rules at all and only use legacymodule
/main
fieldsThe text was updated successfully, but these errors were encountered: