WICG / import-maps

How to control the behavior of JavaScript imports
https://html.spec.whatwg.org/multipage/webappapis.html#import-maps
Other
2.65k stars 69 forks source link

Recursive resolution #261

Open kitsonk opened 2 years ago

kitsonk commented 2 years ago

I searched the issues but couldn't find anything relevant.

I wonder if there would be the potential for some form of recursive resolution. For example, if I am mapping a set of bare specifiers to URLs, I might have a base URL where I want to update, while having all the other bare specifiers update. For example, I would like to do something like this:

{
  "imports": {
    "__base": "https://example.com/polyfills@1.0.0",
    "pkg_a": "__base/pkg_a/index.js",
    "pkg_b": "__base/pkg_b/index.js"
  }
}

Currently, the specification doesn't support this type of recursive lookup. This would make it easier to maintain the map from a human perspective, but also potentially has benefits for procedural generation.

joeldenning commented 2 years ago

This sounds similar to https://github.com/WICG/import-maps/issues/137.

kitsonk commented 2 years ago

Somewhat related I suspect, though the solution was cascading independent import maps. That would work, but I guess I am being more explicit about allowing specifiers to be recursively re-mapped. Though of course this would be a problem:

{
  "imports": {
    "a": "b",
    "b": "a"
  }
}

Of which the resolution algorithm would need to guard against infinite recursion.

The challenge with #137 is that all the approaches required some variation of multiple import maps, which is complex and hasn't really moved forward because of the complex nature of how to composite them. I guess I am looking for a solution that would work with a single import map, which makes it easier for the end implementor to maintain more complex scenarios of dependency management.

domenic commented 2 years ago

My opinion is these kinds of ease-of-authoring features are best done in tools that generate import maps, not in the import maps themselves.

piscisaureus commented 2 years ago

@domenic

My opinion is these kinds of ease-of-authoring features are best done in tools that generate import maps, not in the import maps themselves.

I think import maps are for humans - they should be easy to maintain.

If this using import maps requires a tool, why wouldn't we just make that tool that rewrite import statements in the original source code and forego using import maps altogether?

domenic commented 2 years ago

The idea is to enable tool-less deployment, not tool-less development. I.e. you generate your import map using a tool and then you put it in your HTML and the browser can now understand bare specifiers.

lewisl9029 commented 1 year ago

I would love to see just a single level of recursion supported to enable mapping of directories to individual files with content hashes.

Using an example of directory mapping from the readme, this works fine if the filenames match the desired final mapping exactly:

{
  "imports": {
    "lodash": "/node_modules/lodash-es/lodash.js",
    "lodash/": "/node_modules/lodash-es/"
  }
}

lodash/flatten.js will map to /node_modules/lodash-es/flatten.js, which exists in this scenario.

But an important use case for import maps is mapping away hashes in filenames, so if all of lodash's files are hashed:

{
  "imports": {
    "lodash": "/node_modules/lodash-es/lodash-16f9d819a.js",
    "lodash/": "/node_modules/lodash-es/"
  }
}

Then lodash/flatten.js wouldn't work, because only lodash/flatten-1234abcde.js exists.

I'd like to be able to set up 1 mapping entry for every file to map away hashes (required for hashed modules to be able to relatively import each-other without hashes):

{
  "imports": {
    "/node_modules/lodash-es/lodash.js": "/node_modules/lodash-es/lodash-16f9d819a.js",
    "/node_modules/lodash-es/flatten.js": "/node_modules/lodash-es/flatten-1234abcde.js",
    // ...
  }
}

And then still be able to add an additional layer of mapping on top of the mapped entries to support this super common pattern:

{
  "imports": {
    "/node_modules/lodash-es/lodash.js": "/node_modules/lodash-es/lodash-16f9d819a.js",
    "/node_modules/lodash-es/flatten.js": "/node_modules/lodash-es/flatten-1234abcde.js",
    // ...
    "lodash": "/node_modules/lodash-es/lodash.js",
    "lodash/": "/node_modules/lodash-es/"
  }
}

It's true that we could always generate the entire list of directory mappings statically at build time, but it would require double the number of entries involved, and basically make directory mapping a useless feature as soon as hashed filenames are introduced. Instead, if we could support just a single level of recursive resolution, which has a well-bounded runtime cost and 0 risk of infinite recursion, we could send a lot less import map data over the network and make them easier to generate and work with for tooling authors.

gewoonwoutje commented 1 year ago

The recursiveness can be prevented by using another schema. By taking advantage of the fact that "imports" are on a separate level, you could add another level to create vars or base urls.

{
  "bases": {
    "polyfills": "https://example.com/polyfills@1.0.0"
  },
  "imports": {
    "pkg_a": "polyfills/pkg_a/index.js",
    "pkg_b": "polyfills/pkg_b/index.js"
  }
}

Or some form of templating syntax:

{
  "vars": {
    "polyfills": "https://example.com/polyfills@1.0.0"
  },
  "imports": {
    "pkg_a": "${polyfills}/pkg_a/index.js",
    "pkg_b": "${polyfills}/pkg_b/index.js"
  }
}
trusktr commented 1 year ago

The idea is to enable tool-less deployment, not tool-less development.

Please consider how many people are discluded if we think this way. There are a lot of buildless developers.