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

Ignoring query or hash #251

Closed giltayar closed 2 years ago

giltayar commented 3 years ago

Currently there is no way to specify that the query part of a url be ignored, e.g. given

{
  "imports": {
    "./relative-src.mjs": "./relative-dst.mjs"
  }
}

There is no way to specify that ./relative-src.mjs?x=4 or ./relative-src.mjs#x map to ./relative-dst.mjs (with or without the appropriate hash or query).

Why is this important? Currently, in Node.js (and, I'm also assuming, in the browser), query parameters and hash are used as "cache busters", and enable us to reload a module, even if it was already loaded by the runtime. You can see an example of this cache-busting in Node.js in this article: https://dev.to/giltayar/mock-all-you-want-supporting-es-modules-in-the-testdouble-js-mocking-library-3gh1

Unfortunately, if there is an import map, there is no way to implement this functionality because all query/hash "variations" cannot be added to the importmap (and even if it was possible, it is not something that we would want to do).

I see two ways to deal with it:

  1. Ignore the hash when searching for a specifier in the importmap, and if found, add the hash to the resolved outcome. This will work for Node.js, but if cache-busting is implemented in the browser using queries (hashes won't work), then that won't work.

  2. Add a feature to importmaps to enable wildcarding query or hashes.

Personally, I prefer option 1, as it does not entail radical changes to the spec, and intuitively makes sense to me, but of cours any option that enables us to do some kind of cache-busting is welcome.

ljharb commented 3 years ago

The nature of URLs should mean that all of those already automatically map to the same thing.

domenic commented 3 years ago

On the web we don't distinguish between different parts of the URL. This is in fact why cache-busting of the sort you describe works; the browser sees them as two different URLs and thus does not reuse the cached entry. This treatment of different URLs as different is a foundational part of web infrastructure and not something import maps is going to go against.

Instead, you should update your import map when you update your URLs.

giltayar commented 3 years ago

@domenic the problem is that I don't know what all those URLs are going to be, as the cache-busting mechanism can generate an infinite amount of them.

I believe we will need some kind of mechanism in the import map to define that. At the very least (as I said in proposal #1) that hashes should anyway be ignored, just like the browser ignores them when sending the path to the server. Doing that would solve the Node.js cache busting mechanisms being used in ESM loaders.

And it makes sense anyway to ignore the hash when resolving a URL, because while it is strictly part of the URL, it is a part of the URL that is NOT sent to the server.

giltayar commented 3 years ago

The nature of URLs should mean that all of those already automatically map to the same thing.

@ljharb - exactly. And ee need a mechanism in the import maps to specify exactly that: that "all these" urls should resolve to the same target, no matter what is in the query parameters or hashes.

For hashes it comes naturally: resolving should ignore the hash. For query parameters it is more difficult as some kind of wildcarding mechanism needs to be set in place. Me? I'm OK with just changing the spec to have it ignore hashes.

domenic commented 3 years ago

Your cache busting mechanisms which generate new URLs for your resources need to also update your import map.

giltayar commented 3 years ago

Your cache busting mechanisms which generate new URLs for your resources need to also update your import map.

Which would be perfect, but that means there should be a mechanism for dynamically updating the import map.

giltayar commented 3 years ago

Actually, that wouldn't work either, because the esm loader (in my case) doesn't understand that it's running under a source map and wouldn't understand how to update the import map.

domenic commented 3 years ago

Which would be perfect, but that means there should be a mechanism for dynamically updating the import map.

There is: when you generate new files that need to be cache-busted, you generate a new .html file containing the import map.

Actually, that wouldn't work either, because the esm loader (in my case) doesn't understand that it's running under a source map and wouldn't understand how to update the import map.

That sounds like a good feature request for your tool!

Jamesernator commented 2 years ago

You could probably do what you want here if matching becomes possible:

// import-map.json
{
    "imports": {
        "./path/to/file.js": "./path/to/other.js",
        "./path/to/file.js?*": "./path/to/other.js?*",
        "./path/to/file.js#*": "./path/to/other.js#*"
    }
}
He110te4m commented 10 months ago

When I use esm.sh, I add a query parameter to my path, like this:

import useSWRInfinite from "swr/infinite";
{
  "imports": {
    "swr/": "https://esm.sh/swr@2.2.2?deps=react@17.0.2/"
  }
}

I got the same warning. Is that normal?