mjackson / unpkg

The CDN for everything on npm
https://unpkg.com
Other
2.94k stars 297 forks source link

Use resolved versions instead of semvers when using ?module #129

Open samuelli opened 5 years ago

samuelli commented 5 years ago

Modules should only be executed once. If a module touches globals or has other side effects, they typically break since they assume they are only ever executed once.

For example, the following breaks, despite resolving to the same final URL. This is the correct specified behavior according to the HTML spec (https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier).

<script type="module">
  import 'https://unpkg.com/@polymer/polymer@%5E3.0.0/lib/elements/dom-module.js?module';
  import 'https://unpkg.com/@polymer/polymer@3.0.5/lib/elements/dom-module.js?module';
</script>

I've encountered cases which generate the exact scenario above. The only way for this to be correct is if the request URLs match each other. The simplest approach would be to do the resolution of those semvers up front and inject the resolved versions into the rewritten bare module specifiers.

mjackson commented 5 years ago

Thanks for bringing this to my attention, @samuelli. It's a little odd that the module maps mentioned in the spec don't take into account the redirected URL. In this case, it actually hampers our ability to cache these HTML files served with ?module because @polymer/polymer@^3.0.0 could possibly resolve to 2 different versions if a new version in the 3.0.x range is published between requests.

I agree that fully resolving all URLs in an HTML file ahead of time is the simplest solution. We should probably be doing that work anyway to save on extraneous redirects. I'll try to find some time soon to crank this out. In the meantime, one possible workaround could be to use absolute version numbers to avoid the redirects, though that may not be practical.

samuelli commented 5 years ago

It's not very practical for us to use absolute version numbers, since these are buried in a large dependency tree and every package would have to be updated (in a way that wouldn't be useful to developers).

justinfagnani commented 5 years ago

This is what I was trying to solve with the suggestion of "projects" here: https://github.com/unpkg/unpkg.com/issues/72

The idea being that a project defines an entrypoint from which you can do full version resolution from, and a project URL prefix let's you know which version map to consult for each request.

Another approach would be to reference a package-lock and referrer path in the URL, and do resolution based on the lockfile:

https://unpkg.com/@polymer/polymer/lib/elements/dom-module.js?module&lockfile=@polymer/paper-button/package-lock.json&referrer=@polymer/paper-button/demo/index.html
rslawik commented 4 years ago

I am trying to create a simple landing page for a component and encountered this problem with:

<script type=module>
  import 'https://unpkg.com/@polymer/iron-component-page@4.0.1/iron-component-page.js?module';
</script>

Maybe as a workaround, we could serve:

export * from 'path/with/resolved/version.js?module';

instead of 302 redirect from ^major_version.