-
Notifications
You must be signed in to change notification settings - Fork 43
Proposal: Support loading package by own "name" #306
Comments
It'd be great to provide this feature - in both CJS and ESM (i wouldn't want it in only one of them) - but this would conflict with someone manually putting a folder in node_modules with their same package name. I think we'd need a prefix that couldn't possibly be already valid - like |
definitely a cool idea, but I think it's out of scope of this group |
Why? Resolution is part of modules. |
Modules should have the same resolution as CJS, or at least a subset - but not a superset. This is a feature that applies to CJS as well, and it would be a bad idea to add it to ESM without also adding it to CJS. |
@ljharb You've mentioned this approach a few times now. What is the rationale for keeping CJS up to date with the ESM features? It seems odd to try to update the old system to keep feature parity with features of the new system. Potentially it sends mixed messages about the future endorsed practices and places an ongoing tax on the design space. |
CJS isn’t legacy. It’s not “the old system”. It’s one of two first-class module systems that node will be supporting for likely the next decade, if not forever. Hobbling CJS is not an effective means of encouraging adoption of ESM - and any features that only work in ESM will make migration and interop harder. |
Adding features to one distinct system does not hobble or remove the
viability of the other. It is natural for two systems to evolve different
directions. We should not try to treat them as the same system and require
them to have the same features since they are different both in intent of
design and constraints.
…On Fri, Apr 5, 2019, 10:59 AM Jordan Harband ***@***.***> wrote:
CJS isn’t legacy. It’s not “the old system”. It’s one of two first-class
module systems that node will be supporting for likely the next decade, if
not forever.
Hobbling CJS is not an effective means of encouraging adoption of ESM -
and any features that only work in ESM will make migration and interop
harder.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#306 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAOUo0EPkcMj96qRZ8-sT91-qJm0pjn1ks5vd3LmgaJpZM4cdoNc>
.
|
Saying that the import system must be a strict subset of the require system seems to hobble the former. I do agree that both are and will for the foreseeable future be first-class module systems but both will necessarily have unique features based on their properties and constraints. Just given that require is used in the ecosystem with the very specific semantics it has today means that there's a tiny design space. Accepting that as a constraint for import means import will always be a worse require. |
re my comment, i think 1) both systems can get use from this, but 2) if one doesn't have it, it would be confusing for the other to have it. additionally, if we added it and cjs wanted to support it, we would want to make sure the design was good for both systems. This is why i think the discussion should take place upstream. |
I think it is fair to note that if we design ESM to meet the requirements of CJS, then we will inevitably be forced to limit ESM's potential — if people don't like a limited ESM they will not use it. CJS has a legacy, if people want to see it do new things, it is a good thing, because Node.js can decide about any design aspects. ESM has specs, if people want to see it do new things, they need to make sure it conforms to the specs, and we've witnessed first-hand the complexity in making this happen in a controlled and manageable way. So can we say that,
is satisfied if a custom CJS loader can achieve it — then maybe implementing in CJS follows after it proves worthwhile? |
In this case it’s a node-only concern, since ESM has no concept of packages - so no, i don’t think a package-related feature should be built without doing it for both cjs and ESM, where it makes sense (and in this case it makes sense; this is a big existing pain point for cjs in the ecosystem). |
so people are concerned that in trying to bring this feature to both systems, it will be made worse? if that is the case, I would only say you have no way of knowing that's the case, and that users of both systems would appreciate this feature. I'm not saying every feature has to be in both systems, but this one seems reasonable for both. |
Proposal repo created at https://github.com/guybedford/package-name-resolution. |
your proposal seems to be just as viable for cjs as for esm. the dependencies issue listed under cjs affects both. |
@devsnek right, but esm is experimental and can permit breaking changes, while CommonJS cannot. |
Just because ESM permits them doesn’t mean it’s wise to make avoidable ones. If we find a way that works for CJS, then it ofc works for ESM, so why wouldn’t we want to exhaust that option before adding more deviation between the two primary module systems node will be supporting simultaneously for the next decade. |
just to clarify, adding this field is semver minor even when taking dependencies clash into account because it's opt in. |
@ljharb I'm not implying to exclude CJS - merely to test favourability in the more flexible prevue open for ESM today and once refinements are addressed (or the proposed solution is deemed too breaking and subsequently dropped altogether) make the necessary efforts in the more widely used CJS space. Purely from an evolutionary sense is all :) |
@SMotaal if we've identified a workable plan for both, then experimenting with it in ESM would be fine, although I'm not sure what that would solve - this is a stipulated pain point that imo needs no proof, and the suggested solution is what the ecosystem already does in spades, via babel, symlinks, webpack aliases, typescript project references, etc. |
A potential solution using the semi-popular |
My feeling is that this should probably be configurable. I for one would be interested in just using
EDIT: Actually I was confused with the association direction of import maps so no maybe just a field |
There is already an imports field proposal at https://github.com/jkrems/proposal-pkg-exports#2-imports-field which would in theory allow configuring this sort of package-relative loading feature something like - {
"imports": {
"#myroot/": "./"
}
} |
The problem with |
Skipped over this part: I would prefer if this kind of indirection wouldn't require configuration because it already adds additional indirection and complexity to reading code as-is. If every project picks their own way to express it, this would make it unnecessarily hard to understand what's going on imo. |
I highly disagree this should be configurable; that adds a ton of complexity to every resolver out there, including node’s - let alone the conceptual complexity of every codebase either not being able to use an alias out of the box, or using different ones. We need to pick one default, always-on, same-for-everyone alias that’s part of the specifier, so that it’s unambiguous, static (not more package.json interaction), and universally consistent. |
I feel like if it is necessary Node.js can add some separate API for this, but if it for some reason needs to be within |
TC39 doesn’t have any relevance here; there’s no language concept of a “package” and the spec has gone to great lengths to impose no restrictions on specifier contents. |
@Fishrock123 From a web-perspective, this would be something that a dev (or their toolchain) would write into an import map so it's a "solved problem". As @ljharb said, the signal has been consistently that they don't want to be in the business of telling people what kinds of patterns to use for "application-level logic" like this. |
One thing to consider here is how import maps will be generated. Will self-referencing packages have to indicate so in |
@justinfagnani I think either "add it by default" or "have a signal to add" seem reasonable. If we want to be conservative, we could say that using |
I don't think using |
That's totally fair. I was trying to come up with a solution that doesn't require yet-another |
An argument can be made here for this being the abstract Just like the current (
But there are more considerations to keep in mind here:
My personal take:
Recommendation: I would personally argue for bare "name", but for this to work for Node.js side and especially for it to be reliable for tooling, we need a more concrete and visible "package scope" concept and definitions — so endusers could leverage such tooling to opt for more stylistic conventions and/or alternative mapping strategies, potentially even loader hooks, where traceability would (or at least can) be a lot more fine-grained. |
Repeating the name of the package - and renaming it in a bunch of files when a package is renamed - is a tax that shouldn’t be necessary. |
@SMotaal Unfortunately I don't think I wouldn't want to get into the business of trying to verify the |
@jkrems… Absolutely, my If a release of some deeply nested high-demand dependency somehow breaks here…
If we are considering a signifier to be something that will reside in code that is deployed as third-party dependencies (say through NPM) to the enduser's app, and where disambiguation of this shared signifier is solely based on the out-of-band resolution process of package.json files that can be expected to creep into parent paths, I am hesitant to simply compare this being handled directly in Node.js to existing tooling which applies to packages in code bases that will still be built (ie bundled or rewritten to replace the signifier with the actual package name).
|
On second thought, circumventing parent paths to the first "node_module/*" potentially addresses the concern about creep for published packages, specifically. But can we say for certain that resolving the signifier is always going to be clear cut, or do things like symbolic links, flags… etc. leave potential for complicated edge cases? |
This being a runtime behaviour, it is safe to assume that a "package scope" will ultimately be already tracked at some point prior to the possibility of a "scoped" module making this kind of base (ie either bare "name" or signifier) reference. |
Landed via nodejs/node#29327 |
This has been discussed before, but I think it's a good time to consider it now.
A very common problem in Node.js applications is the backtracking problem where you have to always reference modules through
../../components/name.js
.Since we're loading the package.json when checking the module boundary, we thus also know the package.json
"name"
that any given module is in.What we could do is support loading a package by its own package.json
"name"
by default.This would allow conventions where users just set a package.json name and can then use
import "pkgname/components/name.js"
instead.It's a very small feature that seems like it could solve a pain point quite elegantly.
Would be nice to discuss this further at the next meeting.
The text was updated successfully, but these errors were encountered: