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

Flat hashing model for import maps #3407

Open
jakearchibald opened this issue Feb 27, 2020 · 4 comments
Open

Flat hashing model for import maps #3407

jakearchibald opened this issue Feb 27, 2020 · 4 comments

Comments

@jakearchibald
Copy link
Contributor

Feature Use Case

Since hashing is being rethrought, I wanted to provide some requirements for import maps (and similar systems).

By "import map", I mean any of:

  • Import maps.
  • A browser-level feature like fetch maps or mapping performed by a service worker.
  • A custom URL map built on top of AMD/SystemJS.

Right now, if a leaf module changes, it's hash changes. This means anything which imports it needs to change its hash, to update the reference to the leaf module. This goes all the way up, meaning a small change

Feature Proposal

With a file map, the caching pattern changes:

  • Output will contain both a hashed version and an unhashed version, eg utils-4a13b1c2.js and utils.js. This applies to both chunks and assets.
  • JavaScript files will reference the unhashed version of assets.
  • A map will map from the unhashed version to the hashed version. If the map is not available (eg due to browser support), the unhashed version will download.
  • The hash of a resource is based on its source, and isn't influenced by its dependencies.
  • For patterns that can only map URLs in JS resources: Other resources like CSS cannot perform a map lookup, so these resources will continue to reference hashed versions of resources, and their hash will continue to be influenced by their dependencies.

My proposal is just: Make sure the above possible 😀.

I'll create a demo for import maps showing the current state of things and provide feedback.

@jakearchibald
Copy link
Contributor Author

https://github.com/jakearchibald/rollup-import-maps-demo.

The main thing to note is I had to reimplement hashing. It'd be good if I could use Rollup's hashing implementation, along with the placeholder implementation.

Of course, a custom URL map built on top of AMD/SystemJS would be an order of magnitude more complicated.

@lukastaegert
Copy link
Member

Ok, this is important but will require some thought. In theory, most could be done from plugins today but it could be tedious and error-prone and you could not easily support that asset hashes still consider their dependencies.

It'd be good if I could use Rollup's hashing implementation, along with the placeholder implementation

Sure, it could be a this.hash similar to this.parse to provide a consistent interface so that your plugin would also work in the browser (the Node implementation is just using builtin crypto as this one had the best performance).

To sketch around the problem, a file can now have two names: The actual file name but also a different name under which it is referenced in some places; the other name would come from the import map.

There are several ways to play that:

  • Stick close to the use case of adding or suppressing hashes. We could add a new file name placeholder just for JS chunks with a wild name such as [suppressed-no-dependency-hash]. The logic would be: For the actual file names, this one is replaced with a hash that does not consider dependencies. Inside JS chunks, it is replaced with an empty string. Assets would still use the regular [hash] in their file names. This would probably solve your issue and be really easy to use, it would however dictate very much how you need to write your import map.
  • Add a new hook, e.g. resolveImportUrl, similar to resolveFileUrl, that lets you rewrite imports to your liking based on the actual import file name and the importing chunk. When combined with a [no-dependency-hash], this would also solve your problem but would definitely require a plugin to be used. On the other hand, you could go full import map here, renaming chunks to awesome invented names if you want to.

And maybe there are more, for now I would see this as being in brainstorming stage.

By the way, SystemJS has builtin import map support https://github.com/systemjs/systemjs/blob/master/docs/import-maps.md

For AMD, I guess some work would be necessary. Maybe a feature for the next iteration of rollup-plugin-loadz0r/workz0r/off-main-thread/... 🙄

@jakearchibald
Copy link
Contributor Author

I wrote a plugin that leverages SystemJS's import maps https://gist.github.com/jakearchibald/ee75c204a5fead04672f3046d1fe27d3.

The main difference here is the handling of assets. With chunks, hashing is disabled in Rollup and handled manually, whereas with assets hashing is used and 'undone' within resolveFileUrl. It's the other way around so assets like CSS continue to use hashed URLs.

This is fragile because I'm assuming a lot about where the hash is within the file, but it works pretty well!

@jacekkarczmarczyk
Copy link

jacekkarczmarczyk commented Nov 9, 2022

I wish I've seen this before I started working on not very pretty but working proof of concept ;)
It's not using SystemJS, but I'm going to take a deeper look at your plugin and steal some ideas anyway ("Good coders borrow, great coders steal")
It has now support for SystemJS.
Example usage: vitejs/vite#6773 (comment)

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

3 participants