-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
[Feature Request] Package.json Root / Base Directory #21787
Comments
Posting a link as the entirety of an issue submission is not very helpful, especially if the link in question becomes invalid at some point. Can you please elaborate here instead? |
Sure. It would be nice if there was a For example suppose we have an install in
We could then This eliminates the need to compile typescript into a different folder and then copy the |
If a consumer of your package decides they want to import, say, your |
No you would still do that exactly the same way you are doing it now.
This is independent of package managers. Package managers are responsible for downloading a package and managing dependencies correspondingly. All this does is allow the For example right now if we do:
Node expects the package structure to be laid out like this:
So developers usually create a So for example if the |
If it is truly a trivial change, it might be easier to reason about this and discuss it if it's a pull request. A test using stub modules you create in the For reasons that I hope are easy to understand, a lot of core devs are exceedingly reluctant to see anything change in the module resolver unless absolutely necessary, so please expect lots of questions. I know you were just throwing out a possible syntax and not the required syntax, but |
cc @nodejs/modules |
Unless CJS has a way to designate "not the root of the package" as the root dir for resolution, I don't think it would be appropriate for ESM (or WASM, or any other future module type) to have that capability. |
Node.js has no concept of packages (at least in CJS)(note that a package is not the same as a module). Currently the only field in |
@richardlau right - i'm suggesting that node could look at an additional field to set the directory that all requires of the package resolve relative to - and if that feature existed for CJS, it would also hopefully work for ESM (and it would make sense for both). |
Another idea would be to allow |
i think this would be better suited in ESM as a resolve hook. what if cjs could resolve the current package it was in? e.g. your package is named |
Yes it should work for anything (CSS, json, xml, ESM, ...). For example suppose we had a project with all sorts of resources that needed to be compiled and it had source with
And all of these were compiled into a
And now we wish to load package resources that have been distributed to NPM. So lets call the package
This is the location that all the resources have been compiled to. We do Node would then resolve the path |
The more common case (not xml, svg, or css) would be "i have all my code in This feature would allow any package using babel to support cleaner deep requires. |
I think that the total impact would make economic sense as well as far as developer efficiency goes. For example projects like RxJS remap all compiled resources into a directory structure that is different from what we see on Github. Personally when I need to see the source, I like to open the |
@oleersoy for the record, you can already do that, unless the package has gone out of its way to exclude their raw source from the npm package. |
@ljharb True - In some cases. I think it's not so much that they are going out of their way to exclude sources, it's just that it makes sense to just publish compiled output since since that is what the clients will be requiring. For example for Typescript we have to compile the For example here is the project I'm working on that made me think that the feature would be useful: https://github.com/fireflysemantics/validator The distribution process works like this (Roughly):
So now there is a mismatch between what is published and what is in github and the symmetry is difficult to correct, if not impossible. |
That doesn't make any sense. How is |
I see your point. If the client is attempting to access resources that are essentially meta resources like So it seems the only way to elegantly support it would be to add something like |
I'm somewhat reluctant to introduce this change. It would create packages that work only from a specific version of Node.js forward, and complicate maintainance for modules authors. |
@mcollina after properly understanding @patrickroberts objection I agree that the semantics of However it would still be nice if Node had a way to do this. So the goals would be:
This way we could:
That way we can more effectively debug NPM modules like RXJS or other Typescript / Any script projects that must create dist directories in order to be able to publish the ES5 source to NPM. So we could just set a On of the benefits of this is that if someone is currently using babel to compile from Related MaterialCurrently struggling with Typescript related scenario here: |
I think this touches on a generic need for intercepting incoming/outgoing requests in various ways of loading resources. I'm hesitant to do anything right now while we talk about loader hooks as I feel this feature may have cross cutting concerns with things like making files unavailable outside of the package for encapsulation purposes. Overall, I'm not sure we need this feature to be a field in Right now a package can point to other locations with I do think you can fully do this as you publish however at least for this specific case (things like encapsulation for private files cannot be done right now). You can always just ship your |
@mcollina that’s also true of every v8 upgrade, and every addition to core modules - a new module, or any new API or option. |
@ljharb None of those things introduce a new package format. We are shipping esm because that's part of the language, and that would be highly disruptive already. Adding one more package format would only complicate things in the long run. The amount of disruption introduced by this is far greater than adding a new module or API to me. |
In my experience that's what most NPM packages that are compiled do, however this creates a dynamic where if we want to further investigate parts of a package, we need to clone the git repository, compile the package, and install the package locally from the distribution directory ( So in terms of workflow and eco system efficiency this is more costly because it:
|
@mcollina this could be as simple as providing a new resolver function like So new libraries that load dependencies that are compiled can use I suspect that as we move to `import { foo } from 'boo'; like syntax this will naturally replace require() in 99% of all development scenarios (So I'm assuming ES6 / Typescript ) like scenarios occupy 99% percent of the primary development space for programmers using Node. |
How so? If they compile and change things, they could always use source maps
I don't understand this comment, can you expand on what is more expensive. Writing a new package, maintaining an existing package, time to load at runtime, etc. |
Source maps point us from some compiled output back to the original source location. But if Typescript developers are packaging their compiled output only, then the utilization of the source map is limited IIUC.
Sure - take this library for example. You'll see there is a So that was about 15 minutes of extra work that would not have been needed if Node supported a Now since this is done, there is no clean way for me to include the entire github repository in the package. So I essentially have to publish the So if someone wants to debug something using the original source they have to clone the repository, add logging statements, update tests, etc. and then recompile and reinstall the module in the client that is using it. |
They can contain both source location and content by using "sourcesContent". What is missing?
I might recommend putting the
Is this burden 15 minutes everytime you publish? Or could it be a project bootstrap like so many other workflows use. I would think this is minimal since all the steps described above could be automated.
This seems odd to me, why do you want the github repository for an installed package instead of the interface that the package seeks to ship (via files)?
How are they doing this? I ask because in general I would not support editing your |
I'm not saying the feature isn't valuable to have, just that it needs to go through more rigorous design phases and seeing how it can already be achieved today and if implemented what it would affect in the future. |
One pain point I come across frequently with --experimental-modules is to determined the location of the package.json (ie the root) from within the module. Require had various ways to do this, but I have not found a way to do this without actually traversing paths from I raise this because I think it is related, if a module can inquire about it's root, it would be possible to further allow telling a module of any root. Although other than this issue, I did not come across a reason to need to coerce a resolution root. |
@oleersoy if you have control on a package and want to force |
Any mechanism for a module within a package to locate the package root would need to be present in CJS as well as ESM. Currently, you'd recursively walk upwards until you found a |
@ljharb I am totally for the CJS == ESM aspect, I just figure that with require.resolve, ESM is at a disadvantage. |
ESM surely needs some sort of |
@bmeck Do you have an example of a typescript repository setup that has this enabled so that we can see the process? I think in general people take the path of least resistance. The simplest path to publish to NPM is to specify a base directory. Everything else is more work. So the short answer the What is missing question is Simplicity. The longer answer is unit tests, access to the original source the way it was written ... can we add logging statements using the source map?
So we are devs. Once we get used to a certain flow the setup becomes trivial. It could be a project bootstrap, but as you have probably noticed the approach to project layout in the Javascript world is not the most standardized in the world. Everyone has their own favorite approach to doing things. I for example use a simple
It's nice to be able to read up on a a project in the github repository or in VSCode and see the same picture. It's even nicer to be able to change the project directly in the
Again people are lazy (Or seek the path of least resistance). If devs can look in the If we make them jump through 3 more hoops to get the setup they need to properly test something, then this is less likely to occur, and the net effect of that on the entire NPM ecosystem is sizable. |
Hi folks, I am looking for a way to have UMD/CommonJS/ES Modules builds in the same package, and still allow cherry pick of individual methods. While the first part solved by using So as I got it - now there is no way to declare base dir for the different case? It would be nice to allow an object value to be assigned to like this: {
"main": {
"dir":"dist/cjs/",
"name":"deepdash.js"
},
"module":{
"dir":"dist/esm/",
"name":"deepdash.js"
},
"browser": "dist/umd/deepdash.min.js"
} this way |
Jumping on this even though it's a year after the main discussion happened. Have the core maintainers changed their mind about this? I also think there is immense value here and it's worth continuing the discussion.
What if After all, the addition of a And this way, it is opt-in and wouldn't break anything unless package developers wanted to use the new syntax and manually rolled out the changes themselves. |
The SystemJS loader has a feature similar to this in the form of Import Maps. TypeScript has a feature like this in the form of Path Mappings, though its purely for design-time module resolution when working with complex build systems and doesn't affect runtime behavior If {
...
"paths": {
"api/*": ["dist/api/*"],
"*": ["*", "dist/*"]
}
} Then |
moving into the future, this seems like a good case for loaders. We try to avoid adding stuff to package.json because it really slows everything down. |
@rbuckton The latest node (12.9) does support something similar although it's still behind the flag {
"name": "pkg",
/* [...] */
"exports": {
"./foo": "./target.js",
"./bar/": "./dist/nested/dir/"
}
} Now |
It seems like the exports-map neatly solves this problem. Is there any danger of it going away in the future? As far as I can tell it addresses all the concerns addressed here and in #14970 with no particular downsides. |
The syntax I posted above should be fairly stable. I wouldn’t expect exports to go away completely at this point. What may still change while are details about the array/conditional exports syntax. But path mappings should stay the way they are. |
Closing since exports maps landed in 13.x 🎉 |
Is there a way to polyfill this for older node versions?
|
https://stackoverflow.com/questions/51313753/npm-package-json-base-root-property?noredirect=1#comment89604253_51313753
The text was updated successfully, but these errors were encountered: