WICG / import-maps

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

Will module specifiers support query strings? #134

Closed dcleao closed 5 years ago

dcleao commented 5 years ago

For example, given the import map:

{
  "imports": {
     "@my/generator": "https://my.generator.com/"
  }
}

Above, the module specifier key in the import map would not be allowed to have a query string part (but the module URL it is mapped to could).

Then, in JavaScript code, it would be possible to resolve an import URL containing a query string:

fetch("import:@my/generator?path=a/b/c").then((response) => {
  // ...
});

Would this resolve to calling the URL: https://my.generator.com/?path=a/b/c?

A similar exercise could be made for an ES6 module which the above URL would dynamically generate and that could then be loaded by the dynamic import "function".

I believe this is a compelling use case.

domenic commented 5 years ago

No; bare specifiers are not URLs, and x and x?y are different bare specifiers. You'd need to map them separately.

dcleao commented 5 years ago

Still, you say nothing on the relevance of the use case nor on why it isn't supported. While bare specifiers are not URLs, they do look a lot like URLs — the reference implementation even uses new URL( ... ) to parse them.

dcleao commented 5 years ago

@domenic Could you be so kind to explain why bare specifiers, not being urls, cannot support query strings, or why, in your opinion, the use case is not relevant? Thank you.

domenic commented 5 years ago

Bare specifiers are opaque. foo is a bare specifier. So is foo?bar. They do not have any relationship.

dcleao commented 5 years ago

That's by definition, so not a valid reason, imo. foo is a bare specifier. So is foo/bar. They have a hierarchical relationship, by definition. As Gods of this universe, we could define that foo and foo?bar were related, as per the OP — that was my original intention; not to question what the design allowed at the time, but instead what it could allow.

Anyway, supporting ? characters on bare specifiers with special meaning may seem/be too much. What do you think about the following approach? It still allows mapping bare specifiers to URLs having query strings...

When resolving the URL corresponding to a given bare specifier, the latter is matched against the longest bare specifier prefix in the consolidated import map. The excess bare specifier segments are then "transformed" into excess text appended to the RHS URL. The way this is done, no knowledge of the structure of a URL is necessary.

However, we could argue whether a blind approach is the most useful approach. In some cases we could want to "transform" the excess bare specifiers into additional segments of the path part of the URL, while, in others, we could want to transform these into the value of a specific query parameter (the hash part of the URL is not sent to the server, so its usefulness would be restricted to interpretation by the browser side).

Server-side libraries, such as jax-rs, facilitate "destructuring" of URLs into actual method parameters by specifying a path URL pattern (e.g. /users/{id}). Mapping query string parameters to specific method parameters is equally easy to perform.

I don't think that import maps should make any assumptions on what constitutes a correctly constructed URL, and the current import mapping abilities only allow mapping to certain URL patterns (that can be constructed by appending the excess segments).

To allow more general mappings to URLs, import maps would need to allow specifying where, in the URL of the RHS, the excess bare specifiers would be placed. For example:

Edit: added a trailing / to "@my/generator"

{
  "imports": {
     "@my/generator/": "https://my.generator.com/?path={*}"
  }
}

Then, @my/generator/a/b/c would be resolved to https://my.generator.com/?path=a/b/c.

Recently, another issue was raised, related with / terminated bare specifiers and the existence of a query string in the URL on the RHS: https://github.com/WICG/import-maps/issues/173. This issue brings to attention that URLs on the RHS may need to not be seen as opaque.

Also somewhat related, in that issue, @guybedford raised a possible use case for "cached busting at the module registry" by allowing URLs differing only on the hash part to represent different modules (e.g. /b is not the same module instance as /b#bar). If using the hash comes to make sense in any way, then, the proposed feature would also tie nicely with it.

dcleao commented 5 years ago

Also related, a less orthodox mapping: https://github.com/WICG/import-maps/issues/166

hiroshige-g commented 5 years ago

+1 to not recognizing ? in bare specifiers: it's like one step forward to building a "bare specifier parser" in addition to URL parser, which will be a source of security issues.

When resolving the URL corresponding to a given bare specifier, the latter is matched against the longest bare specifier prefix in the consolidated import map. The excess bare specifier segments are then "transformed" into excess text appended to the RHS URL. The way this is done, no knowledge of the structure of a URL is necessary.

This is to removing the trailing-/ restriction from partial matching of bare specifiers, right? I feel this increases the chance of unintended partial matching. (Also I'm not sure the current partial maching is super nice, given #166 #173 as you mentioned)

hiroshige-g commented 5 years ago

"@my/generator": "https://my.generator.com/?path={*}"

I'm concerned with this powerful mechanism, because the increased complexity might make it harder to infer/validate the import maps spec and behavior, as well as adding "import maps RHS parser" that recognizes {*}.

dcleao commented 5 years ago

Also related, https://github.com/jkrems/proposal-pkg-exports/issues/8.

dcleao commented 5 years ago

Sorry, I just noticed that I should have added a trailing / in the example above, in https://github.com/WICG/import-maps/issues/134#issuecomment-529594023:

{
  "imports": {
     "@my/generator/": "https://my.generator.com/?path={*}"
  }
}
dcleao commented 5 years ago

I'm concerned with this powerful mechanism, because the increased complexity might make it harder to infer/validate the import maps spec and behavior

This serves several use cases.

The one I aim for is to enable calling server-side, dynamically generated modules, for an endpoint which does not follow a REST-like structure. I believe that it's not expected that bare specifiers always map to an existing "file on disk", such as if it was evaluated Node.js. The use case is that of a web server, and web-servers use URLs of various forms to reference resources. These resource can be static or dynamic. I don't see how this makes it harder to validate the import maps behavior, as, in general, URLs are already supported, and validating one type of URL is not harder than validating the other.

Another use case, that I just now realized, is supporting the above mentioned use case, in https://github.com/jkrems/proposal-pkg-exports/issues/8, where something like this is proposed:

{
  "imports": {
     "@my/lib/": "./dist/{*}.js"
  }
}

which constitutes a way to bulk declare all modules in a folder to be accessible without their extension.

justinfagnani commented 5 years ago

@dcleao extensionless import mappings like that are going to much less general in the presence of JSON, HTML, and CSS modules. Generating each entry for each file with a tool will work in the general case though.

dcleao commented 5 years ago

@justinfagnani, as I noted, that's not a use case that I aim for. I just mentioned it because I read elsewhere someone asking for that feature.

ljharb commented 5 years ago

Certainly "generating an entry for each file with a tool" will work, but it would be a very user-friendly feature - either in the initial proposal or as a followon - to support some kind of wildcard/regex/pattern matching to allow semantic minimizing of the size of import maps, without forcing arbitrary coding or transpilation patterns.