WICG/import-maps

Ignoring query or hash

giltayar opened this issue · 10 comments

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.

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

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.

@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.

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.

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

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.

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.

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!

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#*"
    }
}

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?