Skip to content
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

Will module specifiers support query strings? #134

Closed
dcleao opened this issue May 29, 2019 · 14 comments
Closed

Will module specifiers support query strings? #134

dcleao opened this issue May 29, 2019 · 14 comments

Comments

@dcleao
Copy link

dcleao commented May 29, 2019

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
Copy link
Collaborator

domenic commented May 29, 2019

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

@domenic domenic closed this as completed May 29, 2019
@dcleao
Copy link
Author

dcleao commented May 29, 2019

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
Copy link
Author

dcleao commented Jul 24, 2019

@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
Copy link
Collaborator

domenic commented Jul 24, 2019

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

@dcleao
Copy link
Author

dcleao commented Sep 9, 2019

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: #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
Copy link
Author

dcleao commented Sep 9, 2019

Also related, a less orthodox mapping: #166

@hiroshige-g
Copy link
Collaborator

+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
Copy link
Collaborator

"@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
Copy link
Author

dcleao commented Sep 10, 2019

Also related, jkrems/proposal-pkg-exports#8.

@dcleao
Copy link
Author

dcleao commented Sep 10, 2019

Sorry, I just noticed that I should have added a trailing / in the example above, in #134 (comment):

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

@dcleao
Copy link
Author

dcleao commented Sep 10, 2019

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 jkrems/proposal-pkg-exports#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
Copy link
Collaborator

@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
Copy link
Author

dcleao commented Sep 10, 2019

@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
Copy link

ljharb commented Sep 10, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants