denoland / website_feedback

For reporting issues & suggestions for deno.com and deno.land
9 stars 1 forks source link

Allow semver ranges and identifiers in urls #1

Closed jimsimon closed 6 months ago

jimsimon commented 4 years ago

The website should be able to resolve semver symbols. Being able to use semver to dedupe dependencies is an important step towards facilitating the development of medium to large web apps using Deno. I believe some other github redirectors already support this as well. While we could use those CDNs instead, the deno.land registry is currently the only place that exclusively lists deno modules. It may be possible to build further deduping tools once basic semver support is in place.

Some examples of what URLs would look like: https://deno.land/std@^0.50.0/path/mods.ts https://deno.land/std@~0.50.0/path/mods.ts https://deno.land/std@>=0.50.0/path/mods.ts https://deno.land/std@0.49.0||^0.51.0/path/mods.ts https://deno.land/std@0.49.0-0.51.0/path/mods.ts

hayd commented 4 years ago

This seems like a recipe for breaking. I guess I am bias/prefer udd-style fragments (where dependency urls are only updated explicitly by the maintainer, not randomly by a user).

Despite this being relatively standard it has always seemed crazy to me... What is the benefit?

jimsimon commented 4 years ago

So a lockfile (which deno supports) allows you to fix the versions to a degree. Some way to do resolution overrides also helps (import maps might provide this). So there are ways to do so, and nothing I'm proposing stops you from using fixed versions in your modules if your preference is to avoid them.

The main benefit of using semver is runtime performance of larger web apps (client primarily, but also server apps to a much lesser degree). Without semver and dependency deduping, you start getting unwieldy bundle sizes due to multiple versions of the same dependency being bundled. Take the following dependency tree as a really simple example:

MyApp dependencies
  - A@1.0.0 (1kb)
  - B@1.0.0 (1kb)
    - A@1.0.1 (1kb)

If we use fixed dependency versions, then two copies of dependency A will end up in our bundle. However, if we use semver ranges of ^1.0.0 and ^1.0.1 for dependency A can resolve both to 1.0.1 because semver tells us they're backwards compatible. The end result is that only one version of dependency A is included in our bundle resulting in 1kb less of JavaScript to send over the wire, and then parse and execute in the browser.

Now extrapolate this over hundreds of dependencies many of which are larger than our 1kb examples. Some common ones that often cause this kind of issue are lodash (and it's various subpackages), jQuery, react, moment, and smaller utility libraries like leftpad and is-promise. Larger projects can quickly end up with huge amounts of unintended bundle bloat that becomes noticeably detrimental to performance if deduping isn't done. These same issues can pop up with server-side apps if the amount of code that needs to be parsed and executed becomes quite large. It's generally not too bad for something like an app packaged and deployed with docker because you expect relatively slow startup times. But it can be quite expensive and noticeable when you're dealing with something like lambdas/cloud functions.

The kicker with all of this is that it can be pain in the butt to manage even with a good dependency manager. For example yarn is notoriously bad at semantically deduping dependencies. So much so that third party tools have been created to do additional deduping logic on yarn.lock files after they are generated/updated.

Taking a look at udd, it seems to take an approach where the package author doesn't trust the upstream dependency authors to correctly follow semver constraints. Traditional package managers rely on that trust at their core, but also provide ways to compensate when that trust is violated (either intentionally or by accident). It's an interesting reversal of the paradigm that is probably useful for server apps, but as far as I can tell (and I might be wrong) it does nothing to help with deduplication for client apps.

JohanWinther commented 4 years ago

Taking a look at udd, it seems to take an approach where the package author doesn't trust the upstream dependency authors to correctly follow semver constraints. Traditional package managers rely on that trust at their core, but also provide ways to compensate when that trust is violated (either intentionally or by accident).

Wouldn't relying on the deno.land url to handle the semver identifiers be bad whenever trust is broken because the site has no way to compensate on a per-user basis? Or am I missing how this compensation is handled by package managers today?

I think semver handling should be done by package managers that figure out the optimal dependency graph (by recognizing semver in URLS) and then populate $DENO_DIR. Of course, you could try to solve this by making the same URL serve different versions, like you suggest, but deduplication would then only work for dependencies that are on a package registry which handles the identifiers correctly. If some of the dependencies aren't then you are back to square one and need to handle this on the client side with your package manager anyway.

lucacasonato commented 4 years ago

I am against this for the same reason as @hayd. Also this is currently not possible due to rate limits on GitHub's API for getting releases for a repository. Also a user has no way to lock the semver version they receive because Deno's lock file does not store the final URL after redirects, only a hash of the content. So every request would have to reevaluate the semver range again (and potentially serve a different version).

Swap76 commented 4 years ago

May be in future can build a tool which will update the dependencies by following various rules and that will solve the problem I think

KnorpelSenf commented 3 years ago

I fail to see how external tooling around the CLI can help here. If I download a script, and it specifies the exact versions of other scripts, and if this leads to duplicate code, then the only possible scenario is that I get duplicate code. I'm not sure it is preferable to ignore the exact versions of scripts, and populate $DENO_DIR with dependencies other than those specified, because that creates issues that are just impossible to fix from anyone's side.

I also don't see how I as a user could solve this issue with tools like udd, it cannot go and modify the import URLs of the scripts I'm downloading, correct? So the baseline here is that I have to contact the maintainers of these scripts to release new versions just to import updated dependencies. If they don't, then I'm just screwed. Given them semver ranges would allow updates without them becoming active for every single patch release of every dependency.

I might not care about having the same files over and over again for server-side applications because the difference in startup time is probably not even measurable, but that certainly excludes me from using deno bundle because I'd then ship hundreds of KiB of redundant JS on my site.

This seems like a recipe for breaking.

But https://deno.land/x does support not specifying a version number at all, which will deliver the most recent version. I would argue that support semver ranges is rather a step forward from this point of view, because it allows to add at least some constraints to what code is downloaded. One case where this would be very helpful is when I put out tutorials on the internet where people copy & paste the link for a one-off execution. At the point of writing, I don't know if the next major version will still work with my code examples.

The web supports loading scripts via semver, cf. https://unpkg.com/. Even loading npm packages in Deno supports semver ranges, cf. https://www.skypack.dev/. Why can't we have that for Deno modules?

Ironically, a workaround right now is to circumvent https://deno.land/x and to upload the Deno code to npm, so it can be imported with semver through skypack.

KnorpelSenf commented 3 years ago

https://github.com/EdJoPaTo/deno-semver-redirect (written in Rust) solves this problem already by wrapping deno.land/x.

For instance, https://dsr.edjopato.de/grammy/0.x/mod.ts will parse the semver specifier and then redirect you to the correct latest 0.x version on deno.land/x, so you can use these URLs in import specifiers.

tani commented 3 years ago

I created it with Deno Deploy. https://lib.deno.dev

KnorpelSenf commented 3 years ago

@tani are there any differences in functionality?

tani commented 3 years ago

My service is friendly with Deno community.

and I like this domain lib.deno.dev. I would like to use pkg.deno.dev like pkg.go.dev but it was taken.

wperron commented 3 years ago

@tani I took a quick look at your project over the weekend, it looks interesting! I wouldn't be against merging it if you want to open a PR implementing it on this repo. the deno.land website is already running on Deploy so it should be pretty easy. One thing I would want to see on that PR though would be unit tests; Your implementation seems to work using Regex and I would want to be sure that it works as expected before merging it.

tani commented 3 years ago

Thank you for pushing me to make a pull request. Now, I added (almost) exhaustive tests. Please see this file. https://github.com/tani/lib.deno.dev/blob/main/mod.test.ts

KnorpelSenf commented 1 year ago

@tani are you going to attempt a PR? I've been using lib.deno.deno for as long as it exists now and it'd be great to finally see some official support for this approach.

EDIT: I saw https://github.com/denoland/dotland/pull/1826#issuecomment-1161530348 now, so that means this issue can be closed as won't fix?

felipecrs commented 1 year ago

This is great news to me, and I think a lockfile addresses all concerns regarding "randomly breaking". Perhaps you can consider adding some new linter rule to the CLI that complains if a floating version specifier is used towards deno.land and no lockfile is found?

KnorpelSenf commented 1 year ago

This is great news to me

How is it great that this won't be implemented anytime soon?

felipecrs commented 1 year ago

Misinterpretation from my part then.

dsherret commented 6 months ago

Semvered specifiers are now possible with JSR (https://jsr.io/) and with npm specifiers. I think we can close this one.