nodejs / node

Node.js JavaScript runtime ✨🐢🚀✨
https://nodejs.org
Other
106.56k stars 29.05k forks source link

Support for Import Maps #49443

Open wesleytodd opened 4 years ago

wesleytodd commented 4 years ago

I was hoping to start the conversation around getting Import Map support into core. I figured starting here with a proposal was better than starting right off with a PR.

What Are Import Maps

This proposal allows control over what URLs get fetched by JavaScript import statements and import() expressions. This allows "bare import specifiers", such as import moment from "moment", to work.

The proposal was mainly targeted at browsers where URL imports have many downsides without bare specifier support. It enables a standardized map file format to be used when resolving import specifiers, giving developers more control of the behavior of import statements.

Here is an example of the format:

{
  "imports": {
    "todayis": "node_modules/todayis/index.js"
  },
  "scopes": {
    "node_modules/todayis": {
      "english-days": "node_modules/english-days/index.json"
    }
  }
}

Proposal link: https://github.com/WICG/import-maps

Why should they be supported in Node.js?

Currently we use the structure of the filesystem and a resolution algorithm to map import specifiers to files. These files are typically installed by a package manager in a structure which the Node.js resolution algorithm knows how to resolve. This has some drawbacks:

  1. It is slow
  2. It can lead to unexpectedly resolving modules
    • if you have a node_modules at your filesystem root for example
    • if your package manager has hoisted a transitive dep and you access it from the top level
  3. Tools are required to implement copies of the Node.js resolution logic
  4. Users and package managers jump through hoops to try and make the filesystem performant

If we had import maps we could circumvent most of this. Package mangers can generate an import map, enabling perf improvements and simplicity in their implementations. It increases startup performance of apps because they don't have to do as much filesystem access.

One interesting example of what import maps enables is filesystem structure independent workspaces (think yarn workspaces but without the requirement of the modules being under the same root directory).

Implementation

As an example implementation I created this gist:

https://gist.github.com/wesleytodd/4399b2351c59438db19a8ffb1f3fcdca

To run it:

$ git clone git@gist.github.com:4399b2351c59438db19a8ffb1f3fcdca.git hello-today
$ cd hello-today
$ npm it

This uses an experimental loader which loads an importmap.json and falls back to the original filesystem lookup if it fails. I am also pretty sure this very naive implementation is missing edge cases, but in these simple cases it appears to work.

Obviously for support in core we would not use a loader, but I think the rest would be similar. Open questions I have are:

Where would node find the importmap.json?

My first idea is at node_modules/importmap.json. I think this would be expected behavior from users if their package managers started writing this file.

How would users override the importmap.json?

For this I think a reasonable approach would be a cli flag (--importmap) and a package.json ("importmap": "./importmap.json") field.

Do we want to wait for browsers to standardize import maps?

https://github.com/nodejs/node/issues/49443

I think that this is a very valid concern. Is there a way to help push that forward? The benefits are pretty large in node IMO, and it would superseded all the work currently being done on yarn pnp and npm 8. If we let those go forward but then this spec lands it might be even worse for shifting the community.

Could we release it as flagged & experimental until browsers standardize? This would mean users could opt in, but as it changed we could follow along.


Thoughts? Next steps?

bmeck commented 4 years ago

@wesleytodd the concern isn't that loaders or policies make import maps undesirable, but how import maps can be picked up and properly mesh with those features. I don't think either loaders or policies are a means to dissuade import maps, but without a story on how things like loaders can instrument/reflect upon the import maps loaded it seems hard to add import maps as they don't have a clear integration plan. Same for policies.

jkrems commented 4 years ago

Speaking of the spec work: It's not like we have to implement import maps right now to be actively involved in that spec work. And it's not like a non-browser implementing something called "import maps" will necessarily influence a web spec with the same name. Import maps aren't a JavaScript spec and they're unlikely to become one (because neither the people behind the spec nor the people on the TC39 side would want that afaik).

There are multiple people from the node.js side talking to people involved in the import maps spec and implementation in browsers. There's an important distinction between "is node influencing the shape of import maps" and "is node implementing import maps today using the exact spec that may or may not (!) one day ship unflagged in browsers".

There are expectations in node that plain don't exist in browsers. And at the same time, the import maps spec is in a very specific part of its lifecycle: There's an attempt to find a minimal spec that can be standardized for the web and then built upon. We already know that this minimal spec is a) not sufficient for the features we'd like to support for module loading in node and b) potentially going to be extended in the future.

I have every plan to continue to engage with import maps as it evolves, as do other node collaborators. So far I don't have a reason to believe that node implementing the current spec would sway the future direction any more than those current engagements. I don't think we're a follower here just because we don't have the minimal spec implemented in node core.

zackschuster commented 4 years ago

i'll add that "implementing specs before they're stabilized" has historically led to significant problems elsewhere (e.g. typescript, babel) and imo should not be considered viable due to those risks.

ljharb commented 4 years ago

@jkrems builtin modules will require an import-map-like facility to be able to proceed.

jkrems commented 4 years ago

@ljharb You mean within Ecmascript? If so, how would that fit into the spec? I personally would be surprised if that level of resolution detail would leak into builtin modules on the ecmascript level. I would expect that to stay a host concern.

ljharb commented 4 years ago

Yes, and that's a difficult challenge for the champions of that proposal.

Starcounter-Jack commented 4 years ago

It is for the host to resolve the module-specifier but not to dictate the shape of it (as the module may be generic/host-invariant).

For example, if some library imports the function add from a module MyMath, it doesn't know if the resolve will be file based, network based or already loaded in a game executable. So it must simply import {add} from "MyMath".

So, to for a host to REALLY support ESM, it should:

  1. allow module configuration proportional in complexity to module use.
  2. allow said configuration method to be clearly discoverable

In Chromium and Deno, the solution to (1) and (2) is imports: { "MyMath", "/whatever/my-math.js" }.

So, what is the solution in Node?

(imperative loader hooks fails at (1) and other suggestions at least fails at (2)).

bmeck commented 4 years ago

I don't think either your point 1 or 2 is failing currently, but it certainly isn't the same as import maps. Improvements to UX are always possible, but I don't see how the last comment is a claim that import maps are the way to solve things.

Starcounter-Jack commented 4 years ago

@bmeck

I don't think either your point 1 or 2 is failing

I don't understand. The example wants to import add from MyMath using Node. What method is not failing on 1 and 2?

Starcounter-Jack commented 4 years ago

I don't see how the last comment is a claim that import maps are the way to solve things.

I agree. It is merely a way. What is the Node way with respect to the import {add} from "MyMath" example?

Starcounter-Jack commented 4 years ago

"implementing specs before they're stabilized" has historically led to significant problems elsewhere (e.g. typescript, babel)...

It is a balance. The specs that are created in a vacuum have a tendency to fail miserably. So somebody has to lead. Specs that are created in a vacuum can have no feedback loop. This does not mean that everyone has to lead. For example, when IE did not lead, others browsers had to.

jkrems commented 4 years ago

What is the Node way with respect to the import {add} from "MyMath" example?

The same as with almost every other tool (bundlers, linters, etc.): Create node_modules/MyMath and export it from there. :)

Specs that are created in a vacuum can have no feedback loop.

I think multiple people have pointed out that node collaborators are actively involved with the import map spec work. So I'm not sure I follow why you suggest that it's happening in a vacuum..?

Starcounter-Jack commented 4 years ago

Create node_modules/MyMath and export it from there

It was the generic libary that imported MyMath. The user code imports the generic library. The user is not the author of the generic library. Both the generic library and MyMath follows ESM and are host agnostic. Would not your suggestion require me to alter the foreign library source code?

The same as with almost every other tool (bundlers, linters, etc.)

So node will require bundlers and linters to be able to consume host agnostic ES modules? This clearly a disadvantage compared to tools supporting import-maps.

bmeck commented 4 years ago

@Starcounter-Jack

I don't understand. The example wants to import add from MyMath using Node. What method is not failing on 1 and 2?

  1. allow module configuration proportional in complexity to module use.

https://nodejs.org/api/policy.html#policy_dependency_redirection looks very similar to import maps except that the policy file doesn't do scoping currently; as does a loader resolve() hook.

  1. allow said configuration method to be clearly discoverable

--loader and --policy are both CLI arguments as would any such --importmap CLI argument. I am unclear on what makes any of them more discoverable than the other.

jkrems commented 4 years ago

So node will require bundlers and linters to be able to consume host agnostic ES modules? This clearly a disadvantage compared to tools supporting import-maps.

No, it just uses the same way to resolve bare specifiers so that the code works consistently when used in node or outside of node. Just because they all share the same resolution logic doesn't mean that you have to use all of them.

The user is not the author of the generic library. Both the generic library and MyMath follows ESM and are host agnostic. Would not your suggestion require me to alter the foreign library source code?

No need to change any of the code. Let's say the library was downloaded from https://example.com/my-math.mjs:

mkdir -p node_modules/MyMath
curl -O node_modules/MyMath/my-math.mjs https://example.com/my-math.mjs
echo '{"exports": "./my-math.mjs"}' >node_modules/MyMath/package.json

There's no change to my-math.mjs required. And if the library is coming from the npm registry (to get reliable versioning etc.), then it's enough to npm install my-math.

bmeck commented 4 years ago

Apologies if we are being a bit one sided; I don't think we are trying to state that import maps are not a UX improvement, but they are still in the realm of concerns above and understanding why improving our existing features is not a desirable alternative is needed in my viewpoint.

Starcounter-Jack commented 4 years ago

I am unclear on what makes any of them more discoverable than the other. Of course, I might be mistaking. This is clearly subjective. BUT....

...I consider most contributors to this thread to be above average in Javascript experience. And it is not clear to me of loaders, export fields, or policies is the way to run the ESM.

[EDIT: After some input later in this issue thread, it is clear that the NodeJs solution is export fields. I believe they solve the challenge quite well]

Imagine a scenario where you give an assignment such as the one below to some Javascript developers. Try to rid yourself of bias and guess the outcome. What is your belief the outcome would be?

Challenge

You are the author of usercode.js. You are the consumer of module someoneslib. The module someonelib and its dependencies are written without any specific host in mind. Their only dependency is the Ecmascript specifications. Your task is to run usercode.js. You are allowed to alter usercode.js, but not the foreign libraries. Please solve the task in Node, Chromium and Deno.

Please report back on 1) time required; 2) discoverability; 3) easy-of-use; 4) performance; and 5) maintainability with respect to each host.

usercode.js

import { trippleadd } from "someoneslib"
console.log( trippleadd(1,2,3)

someoneslib.js

import {add} from "MyMath"
export function trippleadd( a, b, c ) {
   return add(add(a,b),c)
}

my-math.js

export function add(x,y) {
   return x+y;
}
Starcounter-Jack commented 4 years ago

Apologies if we are being a bit one sided; I don't think we are trying to state that import maps are not a UX improvement, but they are still in the realm of concerns above and understanding why improving our existing features is not a desirable alternative is needed in my viewpoint.

Maybe it is just me not knowing what the existing features really is. So I took the time to formalize the problem (see challenge above) such that the solution could be presented in a more precise way. Otherwise the discussion may bend towards politics and bias (me saying that I "like import maps" or someone else saying "Firefox is not using it" is not really a constructive computer science based critique of a concept or a Spec).

bmeck commented 4 years ago

@Starcounter-Jack I'm keen to understand your needs but you are starting to make leading questions and seem to have a desired answer rather than talking about the feature and how it could be integrated or how existing workflows need to be improved/why existing workflows shouldn't be the way to approach things. All of your last comment is personal and even theoretical, a lot of it merely could be finding the right docs and improve those.

Maybe it is just me not knowing what the existing features really is.

This is a good bit of feedback that we need to add more workflow docs. Right now our docs don't compare our features against other runtimes and maybe they could.

Starcounter-Jack commented 4 years ago

I'm keen to understand your needs

The need is not really mine. The motivation is simply to be able to run pure ESM code. If the above problem description is not enough to outline the problem, it must be due to my shortcomings in explaining them. Maybe the background section (by @domenic) does a better job (it is just 17 lines of text). It can be found here (https://github.com/WICG/import-maps). I really have nothing more to add.

zackschuster commented 4 years ago

@Starcounter-Jack

It is a balance. The specs that are created in a vacuum have a tendency to fail miserably. So somebody has to lead. Specs that are created in a vacuum can have no feedback loop. This does not mean that everyone has to lead. For example, when IE did not lead, others browsers had to.

agreed. consensus seeking is the appropriate way to find that balance here.

Starcounter-Jack commented 4 years ago

...you are starting to make leading questions and seem to have a desired answer

Sometimes, that's how we feel when someone is arguing their case. My intent, however, is for the discussion be technical rather than emotional. I don't really care what the solution is and I am not emotionally attached to import-maps, but I strongly agree with @domenic about the problem definition. I have provided a simple example in code and maybe a simple configuration file that illustrates the difference between the two approaches would be more constructive. Consider my 2 cents delivered for whatever it was worth.

GeoffreyBooth commented 4 years ago

The module someonelib and its dependencies are written without any specific host in mind.

☝️ This is the key part, as far as I'm concerned. How are someonelib's dependencies specified?

In my opinion it's an unfortunate part of the ECMAScript Modules spec that specifier resolution is left to each runtime to decide. I assume this was done to allow Node to keep its bare specifiers ("mymath") and probably its legacy automatic extensions ("./file") but it means in practice that there's no standard defining allowable specifiers across runtimes. Import maps are a stab at defining such a standard, and that's why the effort is valuable.

It'll be a long time before import maps are not only standardized but also supported in all not-EOL runtimes (between browsers, Node and Deno); but fortunately it's possible to write cross-compatible code today, using a specifier like "mymath" that gets defined via package.json for Node and via import maps for Deno and browsers. Yes, when/if Node adds support for import maps that would mean that you could drop the package.json and just use import maps instead, at least for specifying dependencies; that's why we're interested in supporting import maps. But it would basically be a subset or complement of what Node has now, not necessarily an enhancement; its value is that it would be cross-compatible.

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

If someonelib is intended for Node...

[EDIT: Rereading you post, you did not really refer to someonelib being intended for node but rather meant that someonelib as configured for node, right? then the below comment is moot]

That would defy the purpose of moving modules to the language specification rather than the host specification.

The challenge states that:

The module someonelib and its dependencies are written without any specific host in mind.

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

In my opinion it's an unfortunate part of the ECMAScript Modules spec that specifier resolution is left to each runtime to decide.

I agree.

but fortunately it's possible to write cross-compatible code today

You are probably right. I have not tried if export fields (I assume that that is what you are referring to) solves the problem. If so, our team managed to miss them when trying to run things similar to the example above but managed to find import-maps in Deno. So maybe it is just UX as @bmeck suggested.

If the problem is solved without the need for loader hooks or tooling by a mere set of maps in package.json, why not wait with import maps? At least until one more browser vendor hops onboard.

Maybe making us developers stumble over export fields when reading on how to use ESM a little bit earlier would suffice. I will let you know if that works as a replacement as we have a significant amount of ESM code on other hosts.

Mapping should be the very next thing you learn how to do after groking export and import from as hard-coded resolution should be considered bad practice.

GeoffreyBooth commented 4 years ago

The challenge states that:

The module someonelib and its dependencies are written without any specific host in mind.

As far as I'm aware, this is not currently possible. As Node doesn't support import maps and other runtimes don't support package.json, there's currently no universal way to define a module's dependencies.

I assume you are referring to export fields?

Yes, "exports" was written specifically to be compatible with import maps. The idea is that the "exports" field could be converted into an import map by a tool. https://github.com/jkrems/proposal-pkg-exports#1-exports-field

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

Yes, "exports" was written specifically to be compatible with import maps. The idea is that the "exports" field could be converted into an import map by a tool. https://github.com/jkrems/proposal-pkg-exports#1-exports-field

I learn everyday. This is great.

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

there's currently no universal way to define a module's dependencies.

Good enough. It should be trivial to translate maps. We have a fair amount, so I'll give a field report from userland later on for what it is worth (we are planning to move a fairly large code base running on Chromium and Deno over to Node).

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

In my opinion it's an unfortunate part of the ECMAScript Modules spec that specifier resolution is left to each runtime to decide.

Yeah... it is kinda messy right now. At least a set of best practices for resolution patterns and formats covering methods for file, network and embedded resources in declarative, static, dynamic and imperative settings. Maybe even expanded semantics on versioning etc. The Ecmascript language spec basically states that a module-specifier is a string literal. Leaves rather much to the imagination as a source for disagreement...

guybedford commented 4 years ago

If Node.js is ever to support import maps natively, this would definitely be a longer term goal for the project - there are quite a few hurdles first - http/https module fetching and possible fetch support (a lot of the caching, agent sharing, HTTP/2 transparency would be really nice to just build on top of fetch work). In addition a good security model for fetch and module execution would be important to define.

I do really like the idea that Node.js or the OpenJS foundation should participate in the import maps specification process though - it does seem a little skewed for these specs to be without participation from other engines.

That said I'm not sure I see a way for this to be realistically possible given the history of web spec participation here.

ljharb commented 4 years ago

I don't think it's a given that node's implementation would support http/https URLs at all; there's no reason import maps has to be blocked on that.

giltayar commented 4 years ago

I believe there is another important reason for Node.js (and/or the npm package manager people) to be involved in import maps, and it has nothing to do with Node.js implementing import maps: I believe we should strive towards a future where any npm install (or yarn/pnpm) will create a directory structure that can both be executed by the Node.js runtime and an import map can be generated from all the package dependencies that allows an import-map compliant runtime to use that same directory/package structure. Theoretically, this can probably happen without Node.js' (or deno, or...) involvement, but Node's involvement can make sure that this will work.

arcanis commented 4 years ago

From my perspective, this discussion is heavily premature, distracting from the important work that first needs to be done on the loader API before picking additional resolution "standards" to be agreed upon. This, in turn, hurts implementers waiting for those APIs to be stabilized.

If you want import maps, I'd suggest to first prove the point by implementing a loader for them and giving it traction (like the esm module did). If it's worthwhile, it'll be time to decide whether it should be in Node or not.

we should strive towards a future where any [yarn install] will create a directory structure that can both be executed by the Node.js runtime and an import map can be generated from all the package dependencies that allows an import-map compliant runtime to use that same directory/package structure

This is already something that we keep in mind and might happen later in the future once we've clearly identified the pros and cons. It won't, however, happen anytime soon, and there are half a dozen other ways to reach this state - some of them having nothing to do with import maps.

Again, we don't need import maps. We need something to experiment with import maps and other strategies.

Starcounter-Jack commented 4 years ago

@GeoffreyBooth

I agree that there are questions of how useful import maps really would be to Node. The new package.json "exports" implements a lot of the same functionality, with additional features...

Import maps is about code consumption. I struggle to find a way to configure node to run these two simple files in a root directory.

./helloworld.js

import { foo } from "bar"
console.log( foo() );

./some-resolve-for-bar-123.js

export let foo = ( ) => "Hello World"

In Deno, Edge, Chromium and system.js I would provide the configuration { imports: { "bar", "./some-resolve-for-bar-123.js" } }, but it appears to me that node cannot be configured to resolve the "bar" bare import without forcing the files to be moved or altered. Is this true or am I missing some aspect for the exports field? The consumer of "bar" should not have to commit to "bar" ending up in the same package or a different one. After all, modules are not necessarily packages.

Starcounter-Jack commented 4 years ago

From my perspective, this discussion is heavily premature

To early to follow a final spec, but almost too late to lead. If the spec needs to change due to Node input, it is better to have the discussion before a fait-a-compli. As implementations start popping up, that appears to be about now.

jkrems commented 4 years ago

If the spec needs to change due to Node input, it is better to have the discussion before a fait-a-compli.

This presumes that the spec didn't already change because of input from node. It did. Afaik the existence of scopes for example is a direct result of node influencing the spec.

MylesBorins commented 4 years ago

As someone who was involved in coming up with the proposal I would like to state that Node.js, and specifically our support for bare specifiers, was the initial motivation for the entire specification.

I have been an advocate for import-maps themselves as well as ensuring node's input was being shared with the folks working on the spec for the last 3 years.

So while this thread may make it seem like Node.js has not been involved, the project has been active and influential in this spec since its inception.

On Mon, Jun 1, 2020 at 12:10 PM Jan Olaf Krems notifications@github.com wrote:

If the spec needs to change due to Node input, it is better to have the discussion before a fait-a-compli.

This presumes that the spec didn't already change because of input from node. It did. Afaik the existence of scopes for example is a direct result of node influencing the spec.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nodejs/node/issues/49443, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADZYVZKOUP4BVRLWXCP7NTRUPHI5ANCNFSM4KLAZCJQ .

Starcounter-Jack commented 4 years ago

@MylesBorins Great to hear about Nodes.js involvement in the spec. That feels comforting. If anyone is interested, we will probably polyfill import-maps using loader hooks while waiting for native support or another standard.

joeldenning commented 4 years ago

For any interested, I have polyfilled import maps via Node loaders at https://github.com/node-loader/node-loader-import-maps. I don't offer this in attempt to sway the conversation about whether NodeJS itself should support import maps - just as an option for people wanting to try import maps in NodeJS now.

dmichon-msft commented 2 years ago

I see a lot of comments in this thread about generating import maps from the exports field in package.json, but from my time working on the tooling for Rush, the main thing I would be looking for from an import map is how to find entire packages; where to find a file within the package is a solved problem with multiple extant solutions. The package manager should ideally be able to generate an import map without any knowledge of the exports field or indeed any information about the contents of specific packages.

Imagine, if you will:

my-package/test.js

import { FileSystem} from '@rushstack/node-core-library/lib/FileSystem';

This is really two problems: 1) In scope my-package, where is @rushstack/node-core-library? 2) Once I have found @rushstack/node-core-library, resolve ./lib/FileSystem.

The package.json exports field provides a robust facility for solving problem (2), and there is no particular reason that import maps need be concerned with it at all in the Node environment. If the performance overhead of loading those package.json files once for each package during the runtime of the tool is an issue, then the metadata from the exports field could be dumped into a single cache file alongside or integrated with the import map for performance.

Problem (1) is what I really need an import map for, so that the relative positioning of my-package and @rushstack/node-core-library can be completely abstracted away from the runtime or build tooling. Information about conditions is for the most part irrelevant to this stage, since completely replacing an entire package depending on environment is rare and not generally supported by the package manager to begin with. One major use case for which I need this abstraction is to be able to consume the same monorepo project from two or more other monorepo projects with different peer dependency configurations.

A custom loader may work, certainly I already poke enough into the various parts of the toolchain to be able to enforce it and inject whatever necessary overrides into the various tools (SASS, TypeScript, Jest, webpack, Node itself) to make them behave, but I always prefer cleaner solutions where they exist.

ljharb commented 2 years ago

The node resolution algorithm already answers the first part, for both CJS and ESM.

dmichon-msft commented 2 years ago

Every single time I work on optimizing the performance of tooling, step 1 is invariably "how can I do less of the incredibly slow node resolution algorithm?"

GeoffreyBooth commented 2 years ago

Related: https://github.com/nodejs/loaders/issues/26

ljharb commented 2 years ago

The slow part is the part that exports helps with - the package part isn’t slow unless you have to traverse upwards for node_modules folders :-)

lorenzodallavecchia commented 2 years ago

The big problem of the Node resolution algorithm is that it requires a concrete node_modules tree to traverse.

bmeck commented 2 years ago

Slow progress is being made in the area of policy compatibility but since policies have more features we still need a translation layer to be written up. Newest node has an example of emulating import maps: https://nodejs.org/dist/latest-v17.x/docs/api/policy.html#example-import-maps-emulation . It is lacking robust import maps tests and patterns which have slightly different rules from the string list that import maps use. If anyone wants a mentor in helping with this, I can mentor them through the process.

jolleekin commented 2 years ago

Please educate me if I'm missing something, but package duplication is the biggest and unavoidable problem of the NodeJs ecosystem.

There's one simple use case that NONE of the existing package managers (npm, yarn 1, yarn 2, and pnpm) can handle. It is as follows

You're developing two local packages a and b simutaneously

At anytime, there are two instances of c

This undesirable behavior is due to an inherent design flaw with the node_modules folder. To solve this issue, we need to

This solution is what Import Maps is trying to do.


PS:

You may say npm dedup can help, but there are two problems with it

  1. It shouldn't have existed in the very first place
  2. It doesn't handle all cases (such as the one above)

PPS:

In Dart's ecosystem, package duplication never happens. Dart's Pub package manager stores published dependencies in a global cache and generates a package_config.json file for each local package. This file is similar to an import map. There is no local folder similar to node_modules or .yarn/cache.

ljharb commented 2 years ago

@jolleekin that's not what import maps is trying to do at all; import maps is explicitly trying to allow bare specifiers to work in browsers, and only that.

Duplication is a necessary part of a non-broken package management system; one that doesn't allow it is inherently broken.

jolleekin commented 2 years ago

@ljharb

that's not what import maps is trying to do at all; import maps is explicitly trying to allow bare specifiers to work in browsers, and only that.

What I mean is if NodeJS and NPM implement something similar to import maps, package duplication can be completely avoided.

Duplication is a necessary part of a non-broken package management system; one that doesn't allow it is inherently broken.

Did you mean maintaining backward compatibility? NodeJS and NPM can support something similar to import maps and fall back to the legacy node_modules if no import maps exist.

In my opinion, if a package management system allows duplication, it is broken. It just doesn't make sense to have two instances of a package at both design time and runtime. Package duplication is the biggest road block for me when developing JS packages.

ljharb commented 2 years ago

It does, when an inherent part of the module system is that you can edit a dependency on disk.

Anything where duplication is a problem, is meant to be a peer dep - that solves the problem.