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

Multiple Versions on a System #5214

Closed
MehrdadKhnzd opened this issue May 10, 2020 · 39 comments
Closed

Multiple Versions on a System #5214

MehrdadKhnzd opened this issue May 10, 2020 · 39 comments
Labels
feat new feature (which has been agreed to/accepted) suggestion suggestions for new features (yet to be agreed)

Comments

@MehrdadKhnzd
Copy link

Hey there, and thanks for your great work!
I wonder if there's a built-in solution for having multiple versions of Deno on a single system. Honestly, I don't want to use stuff like nvm again. Is this feature currently available? Or will it be added to Deno?
Thanks!

@cdaringe
Copy link
Contributor

not a maintainer, but i wouldn't bank on it :/. i'm needing nvm like functionality now too, but i am a big nvm fan :). looks like https://github.com/asdf-community/asdf-deno is goin

@crowlKats
Copy link
Member

the most built-in way is switching deno version with deno upgrade --version <someversion>; tho that will replace the entire executable. i know it isnt the right solution, but it is the best built-in currently (warning: upgrade --version only works since 1.0.0-rc2)

@MehrdadKhnzd
Copy link
Author

MehrdadKhnzd commented May 10, 2020

nvm is good, but it's not enough. It's not that easy and there are different nvms for Windows and Linux, and that's another problem. I think as this project aims to eliminate Node.js problems, it should consider this problem, too. An official, consistent way of handling this problem is way better and I think something like this would be really great:
deno@1.0.0-rc2 run ...
Now that we're in early stages, it's way easier to add these kinda features cause later it gets really harder. Is there any kind of plan for it? This would solve a lot of future pain in advance. :D

@kitsonk
Copy link
Contributor

kitsonk commented May 10, 2020

nvm is a seperate project to Node.js. A community solution to multiple versions of Deno is likely the right place to start something like this.

@Chathula
Copy link

+1 for this. When i first saw deno, i search for this. Only solution for this now is asdf. It is good to have some kind of version management inbuilt with deno.

I am a big fan of nvm. So we need something else for deno.if it is inbuilt. Much better 😍

@MehrdadKhnzd
Copy link
Author

@kitsonk I really think this problem has to be solved inside Deno itself. This is a much-needed feature and it's not that efficient to rely on external tools like nvm. Is there a special reason for leaving this to a community solution rather than to Deno itself?

@kitsonk
Copy link
Contributor

kitsonk commented May 10, 2020

It becomes an recursive type of problem, building into a binary the concept of multiple versions of a binary, and something that is potentially only applicable in certain use cases of which none of us have the experience of how important/meaningful it will be to have multiple runtime versions of Deno at the same time.

Under the concept of "last responsible moment" to make a decision, it should at least wait until we have multiple stable releases. Even then, I would want/expect it to be a seperate tool on the CLI.

@MehrdadKhnzd
Copy link
Author

I don't think that it's recursive. deno command could be that separate tool that manages how to use actual different deno binaries based on their version. In other words, the deno command could turn into an upper-level binary which calls different binaries based on arguments and stuff, and I don't see any kind of recursion in this. Isn't this possible?

@cdaringe
Copy link
Contributor

@MehrdadKhnzd, what other runtimes do this? what other programs do this? can you make a compelling, objective argument as to why this program should?

@jsejcksn
Copy link
Contributor

The existing version managers are all platform-fragmented. While I don't agree that it's deno's responsibility to provide binary-versioning functionality, I do think it's in the project's interest to champion a uniform, cross-platform a solution.

@MehrdadKhnzd
Copy link
Author

@cdaringe For example, we have .NET Core in which you can have multiple versions installed alongside each other, and you can specify which version to use with each project with a simple property in a config file in the project's folder. And this was always a problem for me in Node.js, even with good tools like nvm, it was a pain rapidly switching between different projects with different requirements. I really think this feature should be added to solve a lot of problems, in addition to changing this platform-specific approach to this problem.

@cdaringe
Copy link
Contributor

@MehrdadKhnzd, respectfully, i'm not grokking what's a poor experience w/ nvm? .nvmrc exists to solve this issue. i even aliased builtin cd to test for nvmrc and autoload it.

@kitsonk
Copy link
Contributor

kitsonk commented May 10, 2020

.NET core is not a runtime binary. It is a set of library files. You still have the same version of a compiler.

@MehrdadKhnzd
Copy link
Author

@cdaringe No, that's the problem. It's platform-specific. The Linux version has this support, but the Windows version hasn't. But now I don't request to support a file like .nvmrc, I'm talking about the whole problem, the inconsistencies between tools and platforms, for an every-day problem that exists.

@MehrdadKhnzd
Copy link
Author

@kitsonk I really can't see the difference, because as I know it's the only thing that matters. I can run dead-old projects alongside with new, fresh ones without a problem.

@jsejcksn
Copy link
Contributor

@cdaringe nvm performance is abysmally slow (just google nvm slow to see what I mean) and .nvmrc doesn't autoload by default (vs something like .tool-versions with asdf).

I think everyone is hoping for a better story with deno — something (at minimum) that's:

  • cross-platform, using the same commands everywhere
  • performant
  • supports configuration

Part of the problem is awareness. I think a lot of people default to running programs by calling the associated binary (node/deno) directly vs delegating execution to a shim/version manager binary. I also think the community relies heavily on guidance from the project for awareness of these kinds of options, and that the project does have some responsibility to inform the community of what's possible if it wants to increase adoption.

If the solution is provided by the community, that's great! I just think Deno should help champion it.

@MehrdadKhnzd
Copy link
Author

In addition, I generally don't know how we gonna specify a Deno runtime version for our Deno projects. As you've probably seen with Node.js, when you want to deploy your app into a platform like Heroku, you have to specify the version of Node.js so it can install the correct version of Node.js for your app and run it. But now that we don't have a package.json, I don't know how we can deploy it into different platforms easily, and I'm afraid that this leads to multiple "unofficial" approaches adopted by different platforms, which leads to a lot of inconsistencies.

@axetroy
Copy link
Contributor

axetroy commented May 11, 2020

In addition to asdf, there are other options. Similar to nvm https://github.com/axetroy/dvm

@MehrdadKhnzd
Copy link
Author

@axetroy Thanks for your solution. The problem is that there are at least three versions of this dvm thing, which one should I use? Which one is better? Although I really prefer something that is built inside of Deno, for many reasons, but at least I think that we can have something like what @jsejcksn suggested. If it's the ultimate solution, I think that Deno should help it become the de facto standard, a uniform, cross-platform solution for this painful problem. If it's not, Deno should help at least one of these projects to become mature enough to become the ultimate solution. In addition, as we have seen before, many of these community solutions will fade away in time, and most of them are heavily opinionated, causing a lot of problems in the future.

@maximousblk
Copy link

maximousblk commented May 13, 2020

An easy solution would be some kind of option to rename the deno executable. So, when you would run deno upgrade --retain-previous command (or whatever flag is decided), it would label the older executable with the version it is. So, if you upgrade from deno 1.0.0-rc2 to deno 1.0.0-rc3 it would name the latest version deno and the previous version deno-1.0.0-rc2. That would mean you have both the version on your machine but the latest version is the default. But this would mean you can only keep the latest version as default. Again, an easy solution would be to run something like deno use 1.0.0-rc2 which would rename the selected version to deno and the version that was switched from will be renamed to the corresponding version. also, the deno use command would download the executable if it is not already present on the machine.

That's the advantage that comes with a single executable, use it.

@multics
Copy link

multics commented May 14, 2020

I hope the ecosystem around deno grows, and a version management tool like nvm is definitely a necessary one.

@maximousblk
Copy link

I did a bit of research and according to me, axetroy/dvm seems to be the best.

Why:

  • Single executable (just like deno)
  • Possible .dvmrc support
  • Made in go (and not in javascript)
  • Can manage its own version so you don't need separate package manager for it. (like npm, homebrew, scoop, etc.)

This can be ported over in rust (preferably a separate crate) and then integrated into deno itself.

But here's the biggest issue: If a version manager gets integrated in deno now, you can switch the version to older deno version but cannot switch back because older versions don't have the integrated version manager. If it had to be done it should have been done in the beginning.

Possible solution:

port axetroy/dvm in rust and ship it as a separate optional executable officially.

I'm just saying that an official dvm would be nice. Or at least select one of the dvm as the official one.

@bartlomieju bartlomieju added feat new feature (which has been agreed to/accepted) suggestion suggestions for new features (yet to be agreed) labels May 21, 2020
@dsherret
Copy link
Member

dsherret commented Aug 23, 2020

I've been thinking about this and the ideal solution IMO is:

  1. cd into a project
  2. Do deno run main.ts
  3. It just works using the version of Deno that project expects.
    • No need to remember what version to use.
    • No way to forget to switch the version of the Deno binary then waste time wondering why something's not working.

I don't think a deno-specific solution is the way to go as this is something that could benefit all binaries beyond Deno and it could be used for development on the deno repostory as well.

As has been mentioned, asdf-vm is a good solution, but IMO its fatal flaw is that it's all shell scripts and so doesn't support Windows (WSL is not windows support). I think a rewrite of something with a design like asdf-vm, but with support for Windows is the best way to go here and then for Deno to promote that solution as the default way to install. Alternatively, perhaps there is already something similar that supports all three major operating systems?

@fangmarks
Copy link

fangmarks commented Aug 23, 2020

But here's the biggest issue: If a version manager gets integrated in deno now, you can switch the version to older deno version but cannot switch back because older versions don't have the integrated version manager. If it had to be done it should have been done in the beginning.

@maximousblk That's why @MehrdadKhnzd suggested this so early on. So it'd be possible to switch from Deno v10 to Deno v6 if your Project needs it. It's just to future proof the next versions of Deno.

Though now I'm wondering how it'd work for imported modules. Since even something like https://deno.land/x/mongo@v0.10.1 might depend on a specific version of Deno in that Version, due to various factors like Internal Deno Functions/Methods that are either deprecated on the then latest version or have gotten a "breaking" rewrite between newer versions.

@Soremwar
Copy link
Contributor

@hokkqi The developers of libraries for Deno try to be as self conscious as possible, releasing versions for specific versions for Deno and indicating (in one way or another) which version can you use in what version of Deno

@fangmarks
Copy link

@Soremwar You can write Use Deno vX or Supports Deno v2 and later as often as you want within your README, some people are not going to see that unless you write a function that throws an Error if you're on the wrong version. Which afaik not even People using node do.
Sadly not everyone checks the deno.land/nest.land READMEs when they're copy pasting from somewhere.

@Soremwar
Copy link
Contributor

Soremwar commented Aug 23, 2020

@hokkqi People like that usually don't stick around with Deno too long, mainly cause this ecosystem requires a lot more attention to details like that, reading documentation and such. I call it creating good devs by brute force :)

However I think a library that could allow devs to throw an error in a Deno version lower than expected might be a good addition, since JavaScript doesn't provide a good solution to this issue, hence Deno as a standalone runtime can't do it either

@jsejcksn
Copy link
Contributor

a library that could allow devs to throw an error in a Deno version lower than expected might be a good addition

require-version.ts:

import {satisfies} from 'https://deno.land/x/semver@v1.0.0/mod.ts';

export class VersionError extends Error {
  name = 'VersionError';
}

export function requireDenoVersion (semanticVersion: string): void {
  const currentVersion = Deno.version.deno;
  if (!satisfies(currentVersion, semanticVersion)) {
    throw new VersionError(`Deno version ${currentVersion} does not satisfy ${semanticVersion}`);
  }
}

export default requireDenoVersion;

test.ts:

import {requireDenoVersion} from './require-version.ts';

Deno.test('Deno is at least v1.2.1', () => {
  requireDenoVersion('>=1.2.1');
});

Deno.test('Deno is less than v2', () => {
  requireDenoVersion('<2');
});

Deno.test('Deno is at least v1.9', () => {
  requireDenoVersion('>=1.9');
});

output:

% deno test test.ts
running 3 tests
test Deno is at least v1.2.1 ... ok (5ms)
test Deno is less than v2 ... ok (2ms)
test Deno is at least v1.9 ... FAILED (0ms)

failures:

Deno is at least v1.9
VersionError: Deno version 1.3.1 does not satisfy >=1.9
    at requireDenoVersion (require-version.ts:10:11)
    at test.ts:12:3
    at asyncOpSanitizer (rt/40_testing.js:34:13)
    at Object.resourceSanitizer [as fn] (rt/40_testing.js:68:13)
    at TestRunner.[Symbol.asyncIterator] (rt/40_testing.js:240:24)
    at AsyncGenerator.next (<anonymous>)
    at Object.runTests (rt/40_testing.js:317:22)

failures:

	Deno is at least v1.9

test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out (7ms)

@crowlKats
Copy link
Member

I want to remind people here that deno upgrade supports the output flag, which allows you to have the new "upgraded" version to be in any location and name you want without deleting the existing one.

@lucacasonato
Copy link
Member

What is the concrete proposal here? If there is no proposal this can be closed.

You can already install multiple versions of Deno like this:

deno upgrade --output /usr/local/bin/deno121 --version 1.2.1
deno upgrade --output /usr/local/bin/deno122 --version 1.2.2

Or changing the default installation version: deno upgrade --version 1.2.0

@fangmarks
Copy link

+1 on closing this then, since it's also already documented on deno.land/manual

@dsherret
Copy link
Member

I don't think deno upgrade is a solution since that requires an internet connection and downloads the binary each time (slow), but I don't think the solution should be something that happens in Deno itself... so yes, closing this is the right call.

@caspervonb
Copy link
Contributor

I don't think deno upgrade is a solution since that requires an internet connection and downloads the binary each time (slow)

Suppose we could look in .deno before downloading

@pasha-bolokhov
Copy link

I think the deno upgrade --output is in fact the solution. You can include the version of the executable in the name. What else do you want? If you want to bind to a specific version — this is your solution. It don't need an internet connection — just download it ahead of time (how else do you suppose to get a program if you don't have an internet connection?).

@davidbludlow
Copy link

davidbludlow commented Mar 9, 2023

We should just extend Volta ( https://volta.sh/ ) to handle deno. The benefits:

  • Cross-platform (unlike nvm, asdf, and others)
  • Fast (written in Rust)
  • That way we can use the same version manager for node, deno, pnpm, yarn, and every globally installed npm package
  • Allows you to pin specific versions of a tool to be used with a specific project.
    • That is, you could just add something like "volta": { "deno": "1.31.1" } to deno.jsonc in the root of each of your projects and it would always automatically use the right version of deno in every project, and it would only have to download each version of deno once.

See the page on Why Volta?

@fangmarks
Copy link

Sounds like a generally good idea to me, though I'd pin it using a deno_version, engine, or similar thing, since that won't make it package specific and lets others write "drop in" replacements for, in this case, volta.

Or just generally lets people write software that lets you pin your code to a specific deno version

@kdmadej
Copy link

kdmadej commented Mar 10, 2023

though I'd pin it using a deno_version, engine, or similar thing

Just as an FYI as to why the Volta folks might be against reusing existing keys like engine: volta-cli/volta#355 (comment)

Although that referred to the format of package.json, not sure how that would correlate to the deno.json config as that one doesn't seem to have a concept of an engine property (although I literally started looking into deno a few hours ago so my knowledge on the matter is very limited 😅 )

Moreover, there already is some discussion going on around this topic in the Volta project: volta-cli/volta#731

@fangmarks
Copy link

@kdmadej Yeah, Deno doesn't have a concept of this yet (afaik), which is why I suggested introducing it as a "sensible default" for package/installation managers that might be written for Deno.

It'd be especially helpful if a Project gets Archived/Abandoned and somebody else picks it up later with a new name.

This way we'd only have a

{
	"engines": { "deno": ">=1.5" }
}

instead of having multiple different versions of

{
	"softwareName": { "engines": { "deno": ">=1.5" } }
}

for every single "Manager" that might get written

@felipecrs
Copy link

felipecrs commented May 23, 2023

I was about to open an issue for this, but thankfully I found this conversation.

Deno has this perk of being a swiss army-like runtime for developers which Node never had, like linting, formatting, testing and even benchmarking. Not only that, but even bundling and compiling.

In Node's world, we need to install and configure different tools for each of these purposes, like ESLint, Prettier, Jest, Webpack and so on.

But there is another thing which most projects also uses: a Node version manager like NVM and Volta (U use Volta).

It would be super great if something like this could just work:

// deno.jsonc

{
  "denoVersion": "1.32.1"
}

And when running deno --version:

# No deno.jsonc in this folder
$ cd ~

$ deno --version
deno 1.33.4

# Now there is a deno.jsonc with the content as the example above
$ cd ~/repos/my-project

# Caches deno runtime in the first installation
$ deno --version
Downloading deno 1.32.1...
deno 1.32.1

# Reuses the cached runtime
$ deno --version
deno 1.32.1

$ cd ~

$ deno --version
deno 1.33.4

If some inspiration is needed, Volta is open source, written in Rust as well and is just as cross platform as Deno is (e.g. Windows, macOS, Linux).

Someone may claim that checking the deno.jsonc file on every initialization may make Deno slower. I doubt it is noticeable (Volta is blazing fast), but even if it is, it does not mean it will be always slower.

For example, deno compile can produce a binary which bypasses this version verification. We can also have some sort of environment variable to bypass this version verification, like:

FROM denoland/deno:1.32.1

ENV DENO_DISABLE_VERSION_MANAGER=1

WORKDIR /app

COPY mod.ts deno.jsonc ./

# Deno will never attempt to confirm its version in this container because of this environment variable
RUN deno cache

[...]

That's to say that maybe this issue can be reopened?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat new feature (which has been agreed to/accepted) suggestion suggestions for new features (yet to be agreed)
Projects
None yet
Development

No branches or pull requests