Install multiple versions of a dependency #5499

Closed
denis-sokolov opened this Issue Jun 17, 2014 · 139 comments

Comments

Projects
None yet
@denis-sokolov

Currently a package can have only a single version of a dependency defined.
I have a need to install multiple versions of a dependency at once.
This is a subset of aliasing features that were rejected in #2943.

In my use case I have a library (frozen-express) that can during runtime take an object produced by another library (Express app) and do useful things with it.
I support multiple versions of Express.

During development I want to be able to test my application with different versions of my dependency. I could fake both versions of Express, but I consider that using a real Express app is a better deal. The tests become more of integration tests as opposed to unit tests, but that only makes them more useful.

I could use npm install express@3 && npm test && npm install express@4 && npm test, but that is very significantly slower than running my entire test suite.
In addition, this wrecks any chance of receiving proper code coverage reports.
Obviously, I have code that conditionally applies to one or another version, and no code coverage tool understands that, if I need to run npm test twice (or more times).

The best workaround is, unfortunately, abusing the npm database. A single-line module express3 that depends on express@3 and exports it solves all my problems.

Perhaps this feature request is a tiny bit more viable than #2943?

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Jun 17, 2014

Also consider the following use case: an application depends on a useful-util-lib@3. A version 4 of the library comes out and developers want to use it in their application. However, the application contains quite a bit of code that relies on a version 3 lib. Until the time comes to upgrade that all at once, new code continues to depends on version 3, increasing the upgrade burden.

If, however, the requested feature was implemented, the developers could begin using version 4 of the dependency, and refactor old code incrementally.

I believe this is an important step to allow for better, more up-to-date codebases.

Also consider the following use case: an application depends on a useful-util-lib@3. A version 4 of the library comes out and developers want to use it in their application. However, the application contains quite a bit of code that relies on a version 3 lib. Until the time comes to upgrade that all at once, new code continues to depends on version 3, increasing the upgrade burden.

If, however, the requested feature was implemented, the developers could begin using version 4 of the dependency, and refactor old code incrementally.

I believe this is an important step to allow for better, more up-to-date codebases.

@mgol

This comment has been minimized.

Show comment Hide comment
@mgol

mgol Jul 29, 2014

Yes please. I've been wishing for this functionality for some time; it's hard to impossible to test with different versions of external packages otherwise.

mgol commented Jul 29, 2014

Yes please. I've been wishing for this functionality for some time; it's hard to impossible to test with different versions of external packages otherwise.

@sebdeckers sebdeckers referenced this issue in gruntjs/grunt-contrib-handlebars Sep 10, 2014

Closed

Handlebars as option #117

@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 21, 2014

+1

We could learn from Bower. A sample bower.json looks like:

{
    "name": "My Project",
    "version": "0.0.0",
    "dependencies": {
        "jquery": "~2.1.1"
    },
    "devDependencies": {
        "jquery-legacy": "jquery#1.11.1"
    }
}

Thus my bower_components folder contains two folders - jquery and jquery-legacy - each with a different version of jQuery.

npm could implement it identically - except using @ instead of #.

+1

We could learn from Bower. A sample bower.json looks like:

{
    "name": "My Project",
    "version": "0.0.0",
    "dependencies": {
        "jquery": "~2.1.1"
    },
    "devDependencies": {
        "jquery-legacy": "jquery#1.11.1"
    }
}

Thus my bower_components folder contains two folders - jquery and jquery-legacy - each with a different version of jQuery.

npm could implement it identically - except using @ instead of #.

@othiym23

This comment has been minimized.

Show comment Hide comment
@othiym23

othiym23 Oct 22, 2014

Contributor

I have a hard time believing that it would be possible to constrain a solution to this problem in such a way that it wouldn't be subject to the same complications that @isaacs was so wary of in #2943 and #798. In addition, I have written tests that depend on multiple versions of dependencies (I wrote a thing that ran a complex test suite against every published version of node-mongodb, which was an interesting experience I will, with luck, never be asked to repeat), so I know this isn't the only way to solve that particular problem.

Bringing Bower into the discussion is an interesting wrinkle, because it makes me wonder what impacts a change like this might have on the front end, both good and bad. Bower's ability to install the same files to the same place and provide an explicit mechanism for reconciling which file gets written is a strength, but the dependency hell this process can engender is a worrisome weakness. This is more or less the inverse of that situation, but I'd be interested in hearing from anyone who thinks this might be applicable for browserify / atomify / other front-end component workflows.

I'm uncertain that the benefits outweigh the risks, particularly with this solution. I don't feel as strongly about it as @isaacs, but I also am wary.

Contributor

othiym23 commented Oct 22, 2014

I have a hard time believing that it would be possible to constrain a solution to this problem in such a way that it wouldn't be subject to the same complications that @isaacs was so wary of in #2943 and #798. In addition, I have written tests that depend on multiple versions of dependencies (I wrote a thing that ran a complex test suite against every published version of node-mongodb, which was an interesting experience I will, with luck, never be asked to repeat), so I know this isn't the only way to solve that particular problem.

Bringing Bower into the discussion is an interesting wrinkle, because it makes me wonder what impacts a change like this might have on the front end, both good and bad. Bower's ability to install the same files to the same place and provide an explicit mechanism for reconciling which file gets written is a strength, but the dependency hell this process can engender is a worrisome weakness. This is more or less the inverse of that situation, but I'd be interested in hearing from anyone who thinks this might be applicable for browserify / atomify / other front-end component workflows.

I'm uncertain that the benefits outweigh the risks, particularly with this solution. I don't feel as strongly about it as @isaacs, but I also am wary.

@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 22, 2014

The above Bower example comes from a project of mine which is a webapp supporting only IE9 and up. Thus I use jQuery 2.x. However, I needed to write tests that check that my app degrades successfully on IE8. Thus my test code uses jQuery 1.x.

Today I got the same situation in another project where I needed again two different installations for a node module - one for my production code and one for my test code.

To make multiple versions of the same node module viable it would be important to install the additional versions through aliases like jquery-legacy in my Bower example. To use this version e.g. the test code would have to explicitly require('jquery-legacy'). This means that there is always a primary version of a module. (The one installed by its name and not through an alias.) npm could choose the primary over secondary versions in any dependency resolution algorithm that might need to be extended.

IMHO the cases of requiring multiple versions are rather rare. But sometimes this feature would be very helpful. Possibly we could say that someone who would use such an advanced feature is pretty knowledgeable and knows what he is doing.

The above Bower example comes from a project of mine which is a webapp supporting only IE9 and up. Thus I use jQuery 2.x. However, I needed to write tests that check that my app degrades successfully on IE8. Thus my test code uses jQuery 1.x.

Today I got the same situation in another project where I needed again two different installations for a node module - one for my production code and one for my test code.

To make multiple versions of the same node module viable it would be important to install the additional versions through aliases like jquery-legacy in my Bower example. To use this version e.g. the test code would have to explicitly require('jquery-legacy'). This means that there is always a primary version of a module. (The one installed by its name and not through an alias.) npm could choose the primary over secondary versions in any dependency resolution algorithm that might need to be extended.

IMHO the cases of requiring multiple versions are rather rare. But sometimes this feature would be very helpful. Possibly we could say that someone who would use such an advanced feature is pretty knowledgeable and knows what he is doing.

@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 22, 2014

Maybe @sindresorhus could quickly give his two cents on why Bower needed the "jquery-legacy": "jquery#1.11.1"-aliasing-of-a-different-package-version-feature. Sindre, plenty kudos if you jump in! Or point to a collaborator of yours. Thanks!

tl;dr: @othiym23 asks:

it makes me wonder what impacts a change like this might have on the front end, both good and bad.

Maybe @sindresorhus could quickly give his two cents on why Bower needed the "jquery-legacy": "jquery#1.11.1"-aliasing-of-a-different-package-version-feature. Sindre, plenty kudos if you jump in! Or point to a collaborator of yours. Thanks!

tl;dr: @othiym23 asks:

it makes me wonder what impacts a change like this might have on the front end, both good and bad.
@sindresorhus

This comment has been minimized.

Show comment Hide comment
@sindresorhus

sindresorhus Oct 22, 2014

👎 I think this is a really bad idea. Fwiw I was against doing that in Bower.

👎 I think this is a really bad idea. Fwiw I was against doing that in Bower.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 22, 2014

In #2943, Isaac has argued a single point: require('underscore') returning lodash is confusing.
I couldn't agree more.

This feature request, however, would never introduce anything confusing like that.
Consider that semantically two versions of a package can be as different as two packages.
In fact, I'd say what really identifies a package is its name and version.
Thus in my code I'd want to write var legacyExpress = require('express@3'); (or require('express', '3') or whatever).
This is because to my code, express 3 and express 4 are two separate packages, and if it was express and slowpress, I wouldn't have a problem, but now I do.

Thus the main Isaac's criticism of #2943 does not apply here at all.

In #2943, Isaac has argued a single point: require('underscore') returning lodash is confusing.
I couldn't agree more.

This feature request, however, would never introduce anything confusing like that.
Consider that semantically two versions of a package can be as different as two packages.
In fact, I'd say what really identifies a package is its name and version.
Thus in my code I'd want to write var legacyExpress = require('express@3'); (or require('express', '3') or whatever).
This is because to my code, express 3 and express 4 are two separate packages, and if it was express and slowpress, I wouldn't have a problem, but now I do.

Thus the main Isaac's criticism of #2943 does not apply here at all.

@othiym23

This comment has been minimized.

Show comment Hide comment
@othiym23

othiym23 Oct 23, 2014

Contributor

Thus the main Isaac's criticism of #2943 does not apply here at all.

I don't believe this to be true, and the jQuery example @analog-nico sketches explains why. Anything that puts something in a folder on disk named differently from what's in package.json raises a variation of the problem @isaacs described.

Thus in my code I'd want to write var legacyExpress = require('express@3'); (or require('express', '3') or whatever).

require('express@3') will work with the Node module loader, but require('express', '3'), along with anything that requires changes to the Node module resolution algorithm, is a non-starter. That said, that is even more of a potential footgun than the original proposal, and therefore even less likely to get the support of the npm core team.

Contributor

othiym23 commented Oct 23, 2014

Thus the main Isaac's criticism of #2943 does not apply here at all.

I don't believe this to be true, and the jQuery example @analog-nico sketches explains why. Anything that puts something in a folder on disk named differently from what's in package.json raises a variation of the problem @isaacs described.

Thus in my code I'd want to write var legacyExpress = require('express@3'); (or require('express', '3') or whatever).

require('express@3') will work with the Node module loader, but require('express', '3'), along with anything that requires changes to the Node module resolution algorithm, is a non-starter. That said, that is even more of a potential footgun than the original proposal, and therefore even less likely to get the support of the npm core team.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 23, 2014

Anything that puts something in a folder on disk named differently from what's in package.json raises a variation of the problem @isaacs described.

But that's exactly it.Unlike #2943, I don't want to do that!
I want to require express and express@3 in my package.json.
I want those to be installed in directories express and express@3 on disk.
I then want to use those in my code using require('express') and require('express@3').

but require('express', '3'), along with anything that requires changes to the Node module resolution algorithm, is a non-starter.

What is the point of criticizing bikeshedding? If require('express@3') works, I'm more than happy.

Anything that puts something in a folder on disk named differently from what's in package.json raises a variation of the problem @isaacs described.

But that's exactly it.Unlike #2943, I don't want to do that!
I want to require express and express@3 in my package.json.
I want those to be installed in directories express and express@3 on disk.
I then want to use those in my code using require('express') and require('express@3').

but require('express', '3'), along with anything that requires changes to the Node module resolution algorithm, is a non-starter.

What is the point of criticizing bikeshedding? If require('express@3') works, I'm more than happy.

@othiym23

This comment has been minimized.

Show comment Hide comment
@othiym23

othiym23 Oct 23, 2014

Contributor

I want to require express and express@3 in my package.json.
I want those to be installed in directories express and express@3 on disk.
I then want to use those in my code using require('express') and require('express@3').

Where does express@3 come from? If you're aliasing it in package.json, there's a thing on disk that has a name different than its name on the registry, which is the exact thing that @isaacs was objecting to in #2943.

Contributor

othiym23 commented Oct 23, 2014

I want to require express and express@3 in my package.json.
I want those to be installed in directories express and express@3 on disk.
I then want to use those in my code using require('express') and require('express@3').

Where does express@3 come from? If you're aliasing it in package.json, there's a thing on disk that has a name different than its name on the registry, which is the exact thing that @isaacs was objecting to in #2943.

@othiym23

This comment has been minimized.

Show comment Hide comment
@othiym23

othiym23 Oct 23, 2014

Contributor

What is the point of criticizing bikeshedding?

There are hard constraints on how far the bikeshedding can go, and it's useful to know where the boundaries of the design space are. People regularly make feature requests of npm that can't be satisfied without making dramatic modifications to frozen Node APIs.

Contributor

othiym23 commented Oct 23, 2014

What is the point of criticizing bikeshedding?

There are hard constraints on how far the bikeshedding can go, and it's useful to know where the boundaries of the design space are. People regularly make feature requests of npm that can't be satisfied without making dramatic modifications to frozen Node APIs.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 23, 2014

there's a thing on disk that has a name different than its name on the registry

I must be missing something. The original problem of confusion between what's installed is clear - is it lodash or is it underscore. In my example it's clear to everybody - it's express version 3.
Consider @3 as part of syntax, same as node_modules/. I wouldn't imagine you saying that node_modules/express is not the same as express in the registry, "because it has node_modules/ in the front.
Or consider installing it into node_modules/express/_versions/3 and then require('express/_versions/3').

And I wouldn't even call it aliasing in package.json. Consider:

{
  "devDependencies": {
    "express": "^4.0.0",
    "express@3": "^3.0.0"
  }
}

It's like a different package, which it kind of is.

there's a thing on disk that has a name different than its name on the registry

I must be missing something. The original problem of confusion between what's installed is clear - is it lodash or is it underscore. In my example it's clear to everybody - it's express version 3.
Consider @3 as part of syntax, same as node_modules/. I wouldn't imagine you saying that node_modules/express is not the same as express in the registry, "because it has node_modules/ in the front.
Or consider installing it into node_modules/express/_versions/3 and then require('express/_versions/3').

And I wouldn't even call it aliasing in package.json. Consider:

{
  "devDependencies": {
    "express": "^4.0.0",
    "express@3": "^3.0.0"
  }
}

It's like a different package, which it kind of is.

@othiym23

This comment has been minimized.

Show comment Hide comment
@othiym23

othiym23 Oct 23, 2014

Contributor

OK. I understand what you're proposing now, and I understand why you want it, but my reservations remain. Thanks for taking the time to explain it, though.

Contributor

othiym23 commented Oct 23, 2014

OK. I understand what you're proposing now, and I understand why you want it, but my reservations remain. Thanks for taking the time to explain it, though.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 23, 2014

Thank you for your work at clarifying my proposal.

If reservations still remain, perhaps limiting the feature only to devDependencies would make it easier to agree with? By limiting the feature so strongly we'd avoid unexpected consequences and abuse, but solve the primary use case mentioned in this topic.
In particular, devDependencies only really matter to the package developers anyway.
But I understand if you consider having different functionality between *dependencies even more awful than the alternative. :)

Thank you for your work at clarifying my proposal.

If reservations still remain, perhaps limiting the feature only to devDependencies would make it easier to agree with? By limiting the feature so strongly we'd avoid unexpected consequences and abuse, but solve the primary use case mentioned in this topic.
In particular, devDependencies only really matter to the package developers anyway.
But I understand if you consider having different functionality between *dependencies even more awful than the alternative. :)

@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 23, 2014

Consider @3 as part of syntax

This is a good point @denis-sokolov. In contrast to my Bower example we should find a solution like the one you suggested that does not allow renaming the package. Your suggested solution would cover all my use cases as well.

Let me just throw in a variation of your solution to see what options we might have.

We could also make the notation more compact:

{
  "devDependencies": {
    "express": "^4.0.0, ^3.0.0"
  }
}

The first version number would always be the preferred version to use. Then we could require them like this:

require("express"); // -> Version 4
require("express/_versions/4"); // -> Version 4
require("express/_versions/3"); // -> Version 3

Consider @3 as part of syntax

This is a good point @denis-sokolov. In contrast to my Bower example we should find a solution like the one you suggested that does not allow renaming the package. Your suggested solution would cover all my use cases as well.

Let me just throw in a variation of your solution to see what options we might have.

We could also make the notation more compact:

{
  "devDependencies": {
    "express": "^4.0.0, ^3.0.0"
  }
}

The first version number would always be the preferred version to use. Then we could require them like this:

require("express"); // -> Version 4
require("express/_versions/4"); // -> Version 4
require("express/_versions/3"); // -> Version 3
@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 23, 2014

I did consider such syntax, @analog-nico.
There's a risk associated with it, though, if you require more than a major version.
Consider:

{
  "devDependencies": {
    "express": "^4.0.0, ^3.1.0, 3.0.5"
  }
}

Now how do I require version ^3.1.0? If I require('express/_versions/3') it's unclear if I mean 3.0 or 3.1, but if I require('express/_versions/3.1'), we need to install the latest 3.x version 3.99.0 into a directory 3.1, which is that evil confusion Isaac wants to avoid.

If we use my proposed syntax all of that is avoided as I directly alias short names with requested versions:

{
  "devDependencies": {
    "express": "^4.0.0",
    "express@3": "^3.1.0",
    "express@3.0": "3.0.5"
  }
}

Installing 3.99 into a directory 3 is not controversial, as well as installing 3.0.5 into 3.0,
and my requires are explicit as well.

I did consider such syntax, @analog-nico.
There's a risk associated with it, though, if you require more than a major version.
Consider:

{
  "devDependencies": {
    "express": "^4.0.0, ^3.1.0, 3.0.5"
  }
}

Now how do I require version ^3.1.0? If I require('express/_versions/3') it's unclear if I mean 3.0 or 3.1, but if I require('express/_versions/3.1'), we need to install the latest 3.x version 3.99.0 into a directory 3.1, which is that evil confusion Isaac wants to avoid.

If we use my proposed syntax all of that is avoided as I directly alias short names with requested versions:

{
  "devDependencies": {
    "express": "^4.0.0",
    "express@3": "^3.1.0",
    "express@3.0": "3.0.5"
  }
}

Installing 3.99 into a directory 3 is not controversial, as well as installing 3.0.5 into 3.0,
and my requires are explicit as well.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Oct 23, 2014

Of course, npm should avoid the following illegal syntax:

{
  "devDependencies": {
    "express@3.0.9": "^4.0.0"
  }
}

Of course, npm should avoid the following illegal syntax:

{
  "devDependencies": {
    "express@3.0.9": "^4.0.0"
  }
}
@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 23, 2014

If reservations still remain, perhaps limiting the feature only to devDependencies would make it easier to agree with?

+1 although I understand that handling dependencies and devDependencies differently is not so nice. However, as I see it, for multiple versions in devDependencies there are perfectly valid use cases when writing tests. My guts say that multiple versions in dependencies -> production code shows that developers didn't properly design or maintain their code base.

If reservations still remain, perhaps limiting the feature only to devDependencies would make it easier to agree with?

+1 although I understand that handling dependencies and devDependencies differently is not so nice. However, as I see it, for multiple versions in devDependencies there are perfectly valid use cases when writing tests. My guts say that multiple versions in dependencies -> production code shows that developers didn't properly design or maintain their code base.

@analog-nico

This comment has been minimized.

Show comment Hide comment
@analog-nico

analog-nico Oct 23, 2014

@denis-sokolov I prefer your solution now.

@denis-sokolov I prefer your solution now.

@g-div g-div referenced this issue in devinivy/dogwater Dec 23, 2014

Merged

Add hapi.js 8 support #2

@pderaaij

This comment has been minimized.

Show comment Hide comment
@pderaaij

pderaaij Jan 9, 2015

Whats the status on this issue? We are in need for such a solution so we can use multiple versions of a dependency. Our use case is the following.

We have a dependency that contains schema object which are information contracts. Our application using these schema objects need to support multiple versions of these schemas so we can send out the correct information based on the version of the schemas used by the consumer.

So we want to define a dependency on tag V1 of schemas and tag V2 on schemas. Within the application we'll do the logic of requiring the correct version, but for now it isn't possible to define the different versions as a dependency in the package.json.

It seems to me that the proposed solution in this issue will help us out, so I'm curious what the state of this issue is.

pderaaij commented Jan 9, 2015

Whats the status on this issue? We are in need for such a solution so we can use multiple versions of a dependency. Our use case is the following.

We have a dependency that contains schema object which are information contracts. Our application using these schema objects need to support multiple versions of these schemas so we can send out the correct information based on the version of the schemas used by the consumer.

So we want to define a dependency on tag V1 of schemas and tag V2 on schemas. Within the application we'll do the logic of requiring the correct version, but for now it isn't possible to define the different versions as a dependency in the package.json.

It seems to me that the proposed solution in this issue will help us out, so I'm curious what the state of this issue is.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Jan 9, 2015

Interesting use case, @pderaaij. I like it.

There's a possible cricitism: versions of your schemas should not necessarily be tied to versions of your schema package. Consider that if V1 and V2 are used in production, they're both still actual, so perhaps the versioning distinction should happen inside a single version of the schema package.

As for what the state of the issue is, the answer, I think, is the same as with most other feature requests: npm devs are flooded with work.

Interesting use case, @pderaaij. I like it.

There's a possible cricitism: versions of your schemas should not necessarily be tied to versions of your schema package. Consider that if V1 and V2 are used in production, they're both still actual, so perhaps the versioning distinction should happen inside a single version of the schema package.

As for what the state of the issue is, the answer, I think, is the same as with most other feature requests: npm devs are flooded with work.

@medikoo

This comment has been minimized.

Show comment Hide comment
@medikoo

medikoo Jan 9, 2015

I think this change will require major changes to node's modules resolution logic, which I think it's no go, and not really worth it.

If someone has really such rare use case, he/she should probably include needed modules versions directly in a project, and require it as e.g. require('./lib/express/v2'), require('./lib/express/v3')

@pderaaij how do you imagine require'ing different versions of same package in your module? e.g. if package is name schema, normally you require it with require('schema'). How do you see require'ing distinctively two different versions of schema within one module?

medikoo commented Jan 9, 2015

I think this change will require major changes to node's modules resolution logic, which I think it's no go, and not really worth it.

If someone has really such rare use case, he/she should probably include needed modules versions directly in a project, and require it as e.g. require('./lib/express/v2'), require('./lib/express/v3')

@pderaaij how do you imagine require'ing different versions of same package in your module? e.g. if package is name schema, normally you require it with require('schema'). How do you see require'ing distinctively two different versions of schema within one module?

@pderaaij

This comment has been minimized.

Show comment Hide comment
@pderaaij

pderaaij Jan 9, 2015

@denis-sokolov Well I can't entirely agree on that, although I understand your remark. But the package containing the schemas should only contain that schemas. Not also the logic of choosing the correct version. For consumers there only should be one package containing the schemas, not more than that.

@medikoo We're thinking about using a solution like the rewire module or a dynamic requiring mechanism. We are not entirely sure yet. I see some possibilities though.

pderaaij commented Jan 9, 2015

@denis-sokolov Well I can't entirely agree on that, although I understand your remark. But the package containing the schemas should only contain that schemas. Not also the logic of choosing the correct version. For consumers there only should be one package containing the schemas, not more than that.

@medikoo We're thinking about using a solution like the rewire module or a dynamic requiring mechanism. We are not entirely sure yet. I see some possibilities though.

@denis-sokolov

This comment has been minimized.

Show comment Hide comment
@denis-sokolov

denis-sokolov Jan 9, 2015

@medikoo, the question of a syntax has been discussed for a while in this topic. For example:

"express@3": "^3.0.0"
require('express@3');

This works without any changes to core Node APIs.

Your proposal of including the dependencies inside the project is equal to abandoning npm and handling dependency management manually.

@pderaaij, consider a package schemas providing the following API:

var schemas = require('schemas');
var v1 = schemas.v1;
var v2 = schemas.v2;

There is no logic in the schemas package, just schemas themselves, and they are distinguished by js property names (or function call parameters, or whatever), while the package itself may be at npm version 83.
I'm just trying to clarify that your npm module version does not have to correlate to schemas version.

@medikoo, the question of a syntax has been discussed for a while in this topic. For example:

"express@3": "^3.0.0"
require('express@3');

This works without any changes to core Node APIs.

Your proposal of including the dependencies inside the project is equal to abandoning npm and handling dependency management manually.

@pderaaij, consider a package schemas providing the following API:

var schemas = require('schemas');
var v1 = schemas.v1;
var v2 = schemas.v2;

There is no logic in the schemas package, just schemas themselves, and they are distinguished by js property names (or function call parameters, or whatever), while the package itself may be at npm version 83.
I'm just trying to clarify that your npm module version does not have to correlate to schemas version.

@medikoo

This comment has been minimized.

Show comment Hide comment
@medikoo

medikoo Jan 9, 2015

@denis-sokolov that way indeed it can be solved without altering node core. I can imagine it shouldn't be that difficult to implement in npm, as it won't overlap with other features

medikoo commented Jan 9, 2015

@denis-sokolov that way indeed it can be solved without altering node core. I can imagine it shouldn't be that difficult to implement in npm, as it won't overlap with other features

@matthew-dean

This comment has been minimized.

Show comment Hide comment
@matthew-dean

matthew-dean Jan 9, 2015

+1. I also would love to be able to install / consume multiple versions of a package in a production app. In the case of compilers, when there are breaking changes, some users want to choose which version of a compiler they use, if they wrote older code targeting an older compiler feature set. The only way I'd see how to do that is to install packages of different versions.

+1. I also would love to be able to install / consume multiple versions of a package in a production app. In the case of compilers, when there are breaking changes, some users want to choose which version of a compiler they use, if they wrote older code targeting an older compiler feature set. The only way I'd see how to do that is to install packages of different versions.

@devinivy

This comment has been minimized.

Show comment Hide comment
@devinivy

devinivy Jan 10, 2015

+1 when a peer dependency spans multiple incompatible versions of the same package, the compatibility of each of those versions need to be testable– so they need to be able to be required as separate dev dependencies.

+1 when a peer dependency spans multiple incompatible versions of the same package, the compatibility of each of those versions need to be testable– so they need to be able to be required as separate dev dependencies.

@silkentrance

This comment has been minimized.

Show comment Hide comment
@silkentrance

silkentrance Jan 11, 2015

@denis-sokolov Making this feature available from only the package.json or the optional npm-shrinkwrap.json is fine, but it would be even nicer to also be able to use the command line for such a purpose.

And, looking at the existing usage for npm install, I find that the @ is already in use, e.g.

npm install <pkg>@<tag>
npm install <pkg>@<version>
npm install <pkg>@<version range>

Not considering the other usages where one passes in a folder, tar ball or tar ball url or git url.

For this, we would have to provide either an --alias=<alias name> option, which is something that was rejected in the past, or extend upon the package parameter above. And, since the @ is already reserved for separating the version / tag from the package name, this would require something else, for example a single : colon?

Using the colon actually works just fine, e.g.

cd /tmp
mkdir test\:3
echo "module.exports.a = 1" > test\:3/index.js
node
> t3 = require('./test:3');
{ a: 1 }

I don't know how this behaves on the Windows platform, however, Meteor are using this sort of scheme for naming their packages, e.g. <atmosphere account name>:<package name>.

Now one could use either package.json or the CLI, e.g.

globally: npm install -g express:3@^3.0.0
locally: npm install express:3@^3.0.0

... "dependencies" : {
      "express:3" : "^3.0.0"
    }

@denis-sokolov Making this feature available from only the package.json or the optional npm-shrinkwrap.json is fine, but it would be even nicer to also be able to use the command line for such a purpose.

And, looking at the existing usage for npm install, I find that the @ is already in use, e.g.

npm install <pkg>@<tag>
npm install <pkg>@<version>
npm install <pkg>@<version range>

Not considering the other usages where one passes in a folder, tar ball or tar ball url or git url.

For this, we would have to provide either an --alias=<alias name> option, which is something that was rejected in the past, or extend upon the package parameter above. And, since the @ is already reserved for separating the version / tag from the package name, this would require something else, for example a single : colon?

Using the colon actually works just fine, e.g.

cd /tmp
mkdir test\:3
echo "module.exports.a = 1" > test\:3/index.js
node
> t3 = require('./test:3');
{ a: 1 }

I don't know how this behaves on the Windows platform, however, Meteor are using this sort of scheme for naming their packages, e.g. <atmosphere account name>:<package name>.

Now one could use either package.json or the CLI, e.g.

globally: npm install -g express:3@^3.0.0
locally: npm install express:3@^3.0.0

... "dependencies" : {
      "express:3" : "^3.0.0"
    }

@dustinfarris dustinfarris referenced this issue in dustinfarris/ember-django-adapter Jan 13, 2015

Closed

testing with multiple versions of ember and ember-data #54

@isaacs

This comment has been minimized.

Show comment Hide comment
@isaacs

isaacs Jan 22, 2015

Member

I don't think that we need new fanciness for this. It's a rare edge case, and a confusing thing to implement in a general way.

Just make a package like this:

{ "name": "express3",
  "version": "1.0.0",
  "description":"Express version 3",
  "dependencies": { "express":"3" } }
// index.js
module.exports = require('express')
Member

isaacs commented Jan 22, 2015

I don't think that we need new fanciness for this. It's a rare edge case, and a confusing thing to implement in a general way.

Just make a package like this:

{ "name": "express3",
  "version": "1.0.0",
  "description":"Express version 3",
  "dependencies": { "express":"3" } }
// index.js
module.exports = require('express')
@vorillaz

This comment has been minimized.

Show comment Hide comment
@vorillaz

vorillaz Jul 4, 2017

This is a common issue for my team as well. We are currently migrating a huge web app (~150 LOC) built with Backbone Marionette. Since the major releases bring lots of breaking changes we want to break down our app and create independent bundles with different Marionette versions in order to progressively refactor the whole project. Thus, we are stuck, since there is no chance to use NPM as a package manager. We finally used NPM and a local repository in order to manage our dependencies.

vorillaz commented Jul 4, 2017

This is a common issue for my team as well. We are currently migrating a huge web app (~150 LOC) built with Backbone Marionette. Since the major releases bring lots of breaking changes we want to break down our app and create independent bundles with different Marionette versions in order to progressively refactor the whole project. Thus, we are stuck, since there is no chance to use NPM as a package manager. We finally used NPM and a local repository in order to manage our dependencies.

@galuszkak galuszkak referenced this issue in DefinitelyTyped/DefinitelyTyped Jul 11, 2017

Merged

[stripe] fix definitions files and tests #17902

8 of 8 tasks complete
@adamlubek

This comment has been minimized.

Show comment Hide comment
@adamlubek

adamlubek Aug 3, 2017

another use case is that I have angular app which is composed of smaller feature npm packages. I want to be able to load specific version of package depending on client e.g. all clients would be presented with package version 1.0.33 but one of the clients would be presented with 1.1.0. This way I could verify new features only on one client before rolling out to all clients.

another use case is that I have angular app which is composed of smaller feature npm packages. I want to be able to load specific version of package depending on client e.g. all clients would be presented with package version 1.0.33 but one of the clients would be presented with 1.1.0. This way I could verify new features only on one client before rolling out to all clients.

@hinell

This comment has been minimized.

Show comment Hide comment
@hinell

hinell Aug 13, 2017

I agree that the best way to manage multiple modules is aliasing. Installation path could be changed by just specifying new folder name on the left-side of its dependency field as following:

  • package.json#dependecies
{
  "foo"     : ">=2.0.0" ,
  "foo-old" : "foo@1.9.0"
}

Where:

  • foo is installed as usually into folder named as foo: node_modules/foo/;
    equivalent to "foo":"foo@>=2.0.0"
  • foo-old is installed into node_modules/foo-old/
    The loading of a modules could be as following:
var foo    = require('foo') // getting  2.0.0 version
var fooold = require('foo-old') // 1.9.0

I think it can be implemented pretty easily.

hinell commented Aug 13, 2017

I agree that the best way to manage multiple modules is aliasing. Installation path could be changed by just specifying new folder name on the left-side of its dependency field as following:

  • package.json#dependecies
{
  "foo"     : ">=2.0.0" ,
  "foo-old" : "foo@1.9.0"
}

Where:

  • foo is installed as usually into folder named as foo: node_modules/foo/;
    equivalent to "foo":"foo@>=2.0.0"
  • foo-old is installed into node_modules/foo-old/
    The loading of a modules could be as following:
var foo    = require('foo') // getting  2.0.0 version
var fooold = require('foo-old') // 1.9.0

I think it can be implemented pretty easily.

@victorherraiz

This comment has been minimized.

Show comment Hide comment
@victorherraiz

victorherraiz Aug 16, 2017

I really like the aliasing idea. Another implementation option that could be simpler (not better) to build:

{
  "aliases": {
    "xreq-old": "xreq"
  },
  "dependencies": {
    "xreq": "^2.0.0",
    "xreq-old": "^1.0.0",
    }
  }
}

aliases section could create local alias.

I really like the aliasing idea. Another implementation option that could be simpler (not better) to build:

{
  "aliases": {
    "xreq-old": "xreq"
  },
  "dependencies": {
    "xreq": "^2.0.0",
    "xreq-old": "^1.0.0",
    }
  }
}

aliases section could create local alias.

@TomMahle

This comment has been minimized.

Show comment Hide comment
@TomMahle

TomMahle Sep 19, 2017

I wanted to post here for anyone like me that is using Yarn and landed here. It is a more or less drop-in replacement for NPM that supports aliasing out of the box:

yarn add material-ui@latest
yarn add material-ui-next@npm:material-ui@next
then

import FlatButton from 'material-ui/FlatButton'; // v0.x
import Button from 'material-ui-next/Button'; // v1.x

(credit for example goes to callemall/material-ui#7195 (comment) )

I wanted to post here for anyone like me that is using Yarn and landed here. It is a more or less drop-in replacement for NPM that supports aliasing out of the box:

yarn add material-ui@latest
yarn add material-ui-next@npm:material-ui@next
then

import FlatButton from 'material-ui/FlatButton'; // v0.x
import Button from 'material-ui-next/Button'; // v1.x

(credit for example goes to callemall/material-ui#7195 (comment) )

@Restuta Restuta referenced this issue in Restuta/rcn.io Oct 18, 2017

Open

Show "show past" in a friendlier way #299

@chandlervdw

This comment has been minimized.

Show comment Hide comment
@chandlervdw

chandlervdw Oct 19, 2017

And for those that want to mostly use material-ui-next:

yarn add material-ui-old@npm:material-ui@latest
yarn add material-ui@next

then

import Button from 'material-ui-old/DatePicker'; // v0.x
import { pink } from 'material-ui/colors'; // v1.x

And for those that want to mostly use material-ui-next:

yarn add material-ui-old@npm:material-ui@latest
yarn add material-ui@next

then

import Button from 'material-ui-old/DatePicker'; // v0.x
import { pink } from 'material-ui/colors'; // v1.x
@nyurik

This comment has been minimized.

Show comment Hide comment
@nyurik

nyurik Oct 19, 2017

Running yarn add material-ui-old@npm:material-ui@latest adds "material-ui-old": "npm:material-ui@latest" line to package.json's dependencies section, but at least npm 5.5.1 throws an error for npm install. So while amazing, using this feature means npm can no longer be used for the project.

nyurik commented Oct 19, 2017

Running yarn add material-ui-old@npm:material-ui@latest adds "material-ui-old": "npm:material-ui@latest" line to package.json's dependencies section, but at least npm 5.5.1 throws an error for npm install. So while amazing, using this feature means npm can no longer be used for the project.

@matthew-dean

This comment has been minimized.

Show comment Hide comment
@matthew-dean

matthew-dean Oct 19, 2017

@nyurik I think the point is to not use NPM at that point, if you're going to have aliased dependencies. Yarn is becoming fairly popular for NPM management these days.

@nyurik I think the point is to not use NPM at that point, if you're going to have aliased dependencies. Yarn is becoming fairly popular for NPM management these days.

@nyurik

This comment has been minimized.

Show comment Hide comment
@nyurik

nyurik Oct 19, 2017

@matthew-dean of course, but many projects explicitly allow users to use both packaging systems interchangeably, and this split won't be very healthy for the community. Especially in cases where there is a large number of different projects but a common build system, and some projects require a different manager. I sincerely hope NPM team would reconsider their decision.

nyurik commented Oct 19, 2017

@matthew-dean of course, but many projects explicitly allow users to use both packaging systems interchangeably, and this split won't be very healthy for the community. Especially in cases where there is a large number of different projects but a common build system, and some projects require a different manager. I sincerely hope NPM team would reconsider their decision.

@nemanjacosovic

This comment has been minimized.

Show comment Hide comment
@nemanjacosovic

nemanjacosovic Nov 30, 2017

Why is this still even a thing? Its very clear that we need multiple versions. I don't see any valid reasons against it.

Why is this still even a thing? Its very clear that we need multiple versions. I don't see any valid reasons against it.

@skylize

This comment has been minimized.

Show comment Hide comment
@skylize

skylize Dec 7, 2017

@nemanjacosovic This issue has only been racking up comments with pleas to implement and ideas on how to do it since June 2014? Why should we have expected any movement on this yet? Rofl

Actually you will find it's been closed since January 2015. So I guess that's when the maintainers just quit listening to us.

skylize commented Dec 7, 2017

@nemanjacosovic This issue has only been racking up comments with pleas to implement and ideas on how to do it since June 2014? Why should we have expected any movement on this yet? Rofl

Actually you will find it's been closed since January 2015. So I guess that's when the maintainers just quit listening to us.

@silkentrance

This comment has been minimized.

Show comment Hide comment
@silkentrance

silkentrance Dec 7, 2017

@skylize if so, they could have shut down comments on this thread a while ago, but they did not.

@skylize if so, they could have shut down comments on this thread a while ago, but they did not.

@scott113341

This comment has been minimized.

Show comment Hide comment
@scott113341

scott113341 Dec 7, 2017

@skylize your assertion that the maintainers of npm don't listen to its community of users is, frankly, disrespectful. There are dozens of comments from maintainers in this issue alone explaining very well why this functionality may be very difficult to implement properly.

If you think that there is a particular solution (either discussed above or not yet explored) that is robust enough to overcome these well-explained technical barriers, then I would kindly ask that you contribute to the technical discussion by explaining why the solution is adequate.

@skylize your assertion that the maintainers of npm don't listen to its community of users is, frankly, disrespectful. There are dozens of comments from maintainers in this issue alone explaining very well why this functionality may be very difficult to implement properly.

If you think that there is a particular solution (either discussed above or not yet explored) that is robust enough to overcome these well-explained technical barriers, then I would kindly ask that you contribute to the technical discussion by explaining why the solution is adequate.

@skylize

This comment has been minimized.

Show comment Hide comment
@skylize

skylize Dec 7, 2017

@scott113341

your assertion that the maintainers of npm don't listen to its community of users is, frankly, disrespectful.

I'm greatly appreciative of all the work that's gone into npm, so I apologize to anyone who might feel disrespected by my comments.

Unfortunately, I guess I let my real feelings spill out about this particular issue. The claim that you should only ever need one version of a dependency seems absurdly near-sighted to me in today's world of deeply nested graphs of rapidly updating dependencies with breaking changes.

I remember reading this post way back when from @isaacs on Jan 22, 2015, which permanently closed the issue:

I don't think that we need new fanciness for this. It's a rare edge case, and a confusing thing to implement in a general way.

This post did not raise any real technical concerns or explain what is so difficult. It was just a raw, unfiltered opinion from one person that shut everything down for everybody. From what I can tell, this seems to be not-even-on-the-radar for the people actually writing code for the project, because it is a "closed" issue. Put this on a roadmap and we might see some real progress and some practical solutions.

In a later comment @isaacs adds

If someone has a dozen or a hundred actual use cases today for this, then let's investigate further. But what I'm hearing so far is a lot of engineering solutions for a very small one-off problem that only a few people have.

The community has filled this thread to the brim with numerous use-cases, but the issue remains closed and seemingly ignored.


If you think that there is a particular solution (either discussed above or not yet explored) that is robust enough to overcome these well-explained technical barriers, then I would kindly ask that you contribute to the technical discussion by explaining why the solution is adequate.

I added a proposal in June 2015 on how to deal with the overall technical problems, which nobody ever raised any concerns against.

I propose something like npm install --save-common lodash@1 or npm install --save-common-dev lodash@1.
Npm would at that point:

  1. Install the module into a folder with the version number appended to the name
  2. Replace all matching modules in the dependency tree with symlinks to the versioned module.
  3. Mark it in as a common dependency in package.json using token characters, so npm install would be able to replicate the process.

Looking back at that I see some flaws in my idea, namely the reliance on symlinks which are not easily dealt with cross-platform. But platform-specific symlinks are not impossible. And regardless, the basic premise of writing packages to version-numbered folders is still a good starting point, if someone was actually trying to build this.

skylize commented Dec 7, 2017

@scott113341

your assertion that the maintainers of npm don't listen to its community of users is, frankly, disrespectful.

I'm greatly appreciative of all the work that's gone into npm, so I apologize to anyone who might feel disrespected by my comments.

Unfortunately, I guess I let my real feelings spill out about this particular issue. The claim that you should only ever need one version of a dependency seems absurdly near-sighted to me in today's world of deeply nested graphs of rapidly updating dependencies with breaking changes.

I remember reading this post way back when from @isaacs on Jan 22, 2015, which permanently closed the issue:

I don't think that we need new fanciness for this. It's a rare edge case, and a confusing thing to implement in a general way.

This post did not raise any real technical concerns or explain what is so difficult. It was just a raw, unfiltered opinion from one person that shut everything down for everybody. From what I can tell, this seems to be not-even-on-the-radar for the people actually writing code for the project, because it is a "closed" issue. Put this on a roadmap and we might see some real progress and some practical solutions.

In a later comment @isaacs adds

If someone has a dozen or a hundred actual use cases today for this, then let's investigate further. But what I'm hearing so far is a lot of engineering solutions for a very small one-off problem that only a few people have.

The community has filled this thread to the brim with numerous use-cases, but the issue remains closed and seemingly ignored.


If you think that there is a particular solution (either discussed above or not yet explored) that is robust enough to overcome these well-explained technical barriers, then I would kindly ask that you contribute to the technical discussion by explaining why the solution is adequate.

I added a proposal in June 2015 on how to deal with the overall technical problems, which nobody ever raised any concerns against.

I propose something like npm install --save-common lodash@1 or npm install --save-common-dev lodash@1.
Npm would at that point:

  1. Install the module into a folder with the version number appended to the name
  2. Replace all matching modules in the dependency tree with symlinks to the versioned module.
  3. Mark it in as a common dependency in package.json using token characters, so npm install would be able to replicate the process.

Looking back at that I see some flaws in my idea, namely the reliance on symlinks which are not easily dealt with cross-platform. But platform-specific symlinks are not impossible. And regardless, the basic premise of writing packages to version-numbered folders is still a good starting point, if someone was actually trying to build this.

@mnpenner

This comment has been minimized.

Show comment Hide comment
@mnpenner

mnpenner Dec 7, 2017

Just wanted to remind you guys that yarn add lodash2@npm:lodash@2.x already works so we know this is possible, and there's already a precedent for the syntax for it. It looks like this in package.json:

  "dependencies": {
    "lodash2": "npm:lodash@2.x"
  },

I think this is a better solution than the one proposed by @skylize too because it lets you choose a name for the additional packages, opposed to just appending a number to the name which may or may not conflict with another package. Also, I don't think there's a need for the special cli-args, --save-common.

mnpenner commented Dec 7, 2017

Just wanted to remind you guys that yarn add lodash2@npm:lodash@2.x already works so we know this is possible, and there's already a precedent for the syntax for it. It looks like this in package.json:

  "dependencies": {
    "lodash2": "npm:lodash@2.x"
  },

I think this is a better solution than the one proposed by @skylize too because it lets you choose a name for the additional packages, opposed to just appending a number to the name which may or may not conflict with another package. Also, I don't think there's a need for the special cli-args, --save-common.

@skylize

This comment has been minimized.

Show comment Hide comment
@skylize

skylize Dec 7, 2017

@mnpenner

I think this is a better solution than the one proposed by @skylize too because it lets you choose a name for the additional packages

In this comment to #2943, @isaacs made it pretty clear that blanket aliasing will never be considered. If we want a solution that will actually get built, we need to be thinking of ways to give the user only the bare minimum amount of control needed to reach the target, not allowing them to just name anything whatever they want.

skylize commented Dec 7, 2017

@mnpenner

I think this is a better solution than the one proposed by @skylize too because it lets you choose a name for the additional packages

In this comment to #2943, @isaacs made it pretty clear that blanket aliasing will never be considered. If we want a solution that will actually get built, we need to be thinking of ways to give the user only the bare minimum amount of control needed to reach the target, not allowing them to just name anything whatever they want.

@mnpenner

This comment has been minimized.

Show comment Hide comment
@mnpenner

mnpenner Dec 8, 2017

@skylize I think what isaacs was getting at is that is if you require one module, it shouldn't load the module from an unrelated directory (I think). With yarn's solution, lodash2 is actually installed into node_modules/lodash2. So node's module resolution algorithm remains completely unchanged.

That said, yes, you could use this deceive the reader by aliasing one package to an unrelated package's name, but I don't understand why you would want to go to such great lengths to prevent developers from writing stupid code. I could just as easily clone jquery and publish to npm as lodash2 and then what? A few people get confused and the world chugs on.

mnpenner commented Dec 8, 2017

@skylize I think what isaacs was getting at is that is if you require one module, it shouldn't load the module from an unrelated directory (I think). With yarn's solution, lodash2 is actually installed into node_modules/lodash2. So node's module resolution algorithm remains completely unchanged.

That said, yes, you could use this deceive the reader by aliasing one package to an unrelated package's name, but I don't understand why you would want to go to such great lengths to prevent developers from writing stupid code. I could just as easily clone jquery and publish to npm as lodash2 and then what? A few people get confused and the world chugs on.

@nyurik

This comment has been minimized.

Show comment Hide comment
@nyurik

nyurik Dec 8, 2017

@skylize I don't think "never consider" is ever a good approach when working with a community. Opinions change, new arguments and usecases come forth, etc. The #2943 comment was made over 5 years ago - yarn didn't even exist back then. In just a year, yarn is a major player in this field - clearly showing that NPM has become the IE6 of the package management, and could use some love.

yarn clearly broke compatibility on this one. Yet, the community is clearly in favor of yarn's approach, so I think NPM team should reconsider. Otherwise it hurts all of us - we all would like both, the compatibility AND the version aliasing. If NPM introduces a new incompatible syntax just for version aliasing without any justification, the issue will get even worse.

nyurik commented Dec 8, 2017

@skylize I don't think "never consider" is ever a good approach when working with a community. Opinions change, new arguments and usecases come forth, etc. The #2943 comment was made over 5 years ago - yarn didn't even exist back then. In just a year, yarn is a major player in this field - clearly showing that NPM has become the IE6 of the package management, and could use some love.

yarn clearly broke compatibility on this one. Yet, the community is clearly in favor of yarn's approach, so I think NPM team should reconsider. Otherwise it hurts all of us - we all would like both, the compatibility AND the version aliasing. If NPM introduces a new incompatible syntax just for version aliasing without any justification, the issue will get even worse.

@isiahmeadows

This comment has been minimized.

Show comment Hide comment
@isiahmeadows

isiahmeadows Dec 8, 2017

Could we start trying sending support emails or something, rather than blowing this issue up with borderline off-topic stuff? It kind of gets old getting an email + a notification each time one of you all comment here.

Could we start trying sending support emails or something, rather than blowing this issue up with borderline off-topic stuff? It kind of gets old getting an email + a notification each time one of you all comment here.

@DuBistKomisch

This comment has been minimized.

Show comment Hide comment
@DuBistKomisch

DuBistKomisch Dec 15, 2017

In response to #5499 (comment):

No one yet has provided a real-world example of (2) in this thread, so I am somewhat suspicious that it's only hypothetical anyway.

We want to use socket.io-client to connect to separate v1 and v2 servers, and the protocols are mutually incompatible, so we'd need both clients installed simultaneously.

Eventually I'd like to switch to yarn for this project of course (sick of npm's shit, and yarn's only burned me once so far), but I don't have time to clean up all the tech debt required right now, so this is really annoying... guess I'll try out npm-install-version/node-multidep.

Edit: npm-install-version works I guess, can't actually include it in the package.json though so just need to install it manually everywhere...

DuBistKomisch commented Dec 15, 2017

In response to #5499 (comment):

No one yet has provided a real-world example of (2) in this thread, so I am somewhat suspicious that it's only hypothetical anyway.

We want to use socket.io-client to connect to separate v1 and v2 servers, and the protocols are mutually incompatible, so we'd need both clients installed simultaneously.

Eventually I'd like to switch to yarn for this project of course (sick of npm's shit, and yarn's only burned me once so far), but I don't have time to clean up all the tech debt required right now, so this is really annoying... guess I'll try out npm-install-version/node-multidep.

Edit: npm-install-version works I guess, can't actually include it in the package.json though so just need to install it manually everywhere...

@palmerj3

This comment has been minimized.

Show comment Hide comment
@palmerj3

palmerj3 Dec 22, 2017

Contributor

I have a real-world scenario for this.. I maintain jest-junit and I would like to setup travis ci to test it against multiple versions of jest. Doing that is fine but I would also like to be able to run my unit tests with whatever version of jest I choose.

Contributor

palmerj3 commented Dec 22, 2017

I have a real-world scenario for this.. I maintain jest-junit and I would like to setup travis ci to test it against multiple versions of jest. Doing that is fine but I would also like to be able to run my unit tests with whatever version of jest I choose.

@hinell

This comment has been minimized.

Show comment Hide comment
@hinell

hinell Dec 24, 2017

@palmerj3 Well, there are a lot of real-world scenarios especially when you writing cross-platform software but looks like npm is unlikely to implement anything cause the issue is opened almost 3 years ago and nothing has changed since then. That's why it makes me sad. 😞

hinell commented Dec 24, 2017

@palmerj3 Well, there are a lot of real-world scenarios especially when you writing cross-platform software but looks like npm is unlikely to implement anything cause the issue is opened almost 3 years ago and nothing has changed since then. That's why it makes me sad. 😞

@silkentrance

This comment has been minimized.

Show comment Hide comment
@silkentrance

silkentrance Dec 26, 2017

While it is fun seeing that this is not going to be resolved, whereas for example yarn provides a very good alternative, I am now signing off.

While it is fun seeing that this is not going to be resolved, whereas for example yarn provides a very good alternative, I am now signing off.

@trevorwhealy

This comment has been minimized.

Show comment Hide comment
@trevorwhealy

trevorwhealy Jan 10, 2018

👋 We have a lot of legacy code written in the v1 release of React-Transition-Group (https://github.com/reactjs/react-transition-group), and it is working great.

As React evolved and the maintainers changed, the codebase also changed dramatically, causing them to release a v2 that had breaking changes. It would be a lot of work to retool legacy code that is actually working well and won't be changed for the foreseeable future.

We locked down to v1 so that our app would still work, but we want to use v2 for all future development. Allowing aliases would be pretty useful in this case.

This comment from earlier in the thread seems to be a simple solution to this common problem: #5499 (comment)

Ideally, we would really enjoy being able to alias like so:

"react-transition-group@v1": "^1.1.3",
"react-transition-group@v2": "https://github.com/reactjs/react-transition-group.git#master",
"react-transition-group@v3: "^3.0.0",

trevorwhealy commented Jan 10, 2018

👋 We have a lot of legacy code written in the v1 release of React-Transition-Group (https://github.com/reactjs/react-transition-group), and it is working great.

As React evolved and the maintainers changed, the codebase also changed dramatically, causing them to release a v2 that had breaking changes. It would be a lot of work to retool legacy code that is actually working well and won't be changed for the foreseeable future.

We locked down to v1 so that our app would still work, but we want to use v2 for all future development. Allowing aliases would be pretty useful in this case.

This comment from earlier in the thread seems to be a simple solution to this common problem: #5499 (comment)

Ideally, we would really enjoy being able to alias like so:

"react-transition-group@v1": "^1.1.3",
"react-transition-group@v2": "https://github.com/reactjs/react-transition-group.git#master",
"react-transition-group@v3: "^3.0.0",
@jlpospisil

This comment has been minimized.

Show comment Hide comment
@jlpospisil

jlpospisil Feb 21, 2018

I am working on migrating a large project from bootstrap 3 to 4. This feature would be nice. I would like to import both, and apply bootstrap 4 to specific pages/areas as the migration progresses.

I am working on migrating a large project from bootstrap 3 to 4. This feature would be nice. I would like to import both, and apply bootstrap 4 to specific pages/areas as the migration progresses.

@pauldraper

This comment has been minimized.

Show comment Hide comment
@pauldraper

pauldraper Mar 17, 2018

Yarn supports this case via general-purpose aliasing. ("This isn't going to be reconsidered" #2943)`

"react-transition-group-v1": "npm:react-transition-group@^1.1.3",
"react-transition-group-v2": "https://github.com/reactjs/react-transition-group.git#master",
"react-transition-group-v3: "npm:react-transition-group@^3.0.0",

Yarn supports this case via general-purpose aliasing. ("This isn't going to be reconsidered" #2943)`

"react-transition-group-v1": "npm:react-transition-group@^1.1.3",
"react-transition-group-v2": "https://github.com/reactjs/react-transition-group.git#master",
"react-transition-group-v3: "npm:react-transition-group@^3.0.0",
@VincentCharpentier

This comment has been minimized.

Show comment Hide comment
@VincentCharpentier

VincentCharpentier Mar 21, 2018

So basically is this gonna be a feature ?
With the constant (breaking) changes we have to face in javascript projects this seems like an obviously needed feature.
Will it be possible soon ?
If not, that's not a big issue I could switch to yarn, but honestly I wish I could stay with npm
Thanks

So basically is this gonna be a feature ?
With the constant (breaking) changes we have to face in javascript projects this seems like an obviously needed feature.
Will it be possible soon ?
If not, that's not a big issue I could switch to yarn, but honestly I wish I could stay with npm
Thanks

@jamesmfriedman

This comment has been minimized.

Show comment Hide comment
@jamesmfriedman

jamesmfriedman Apr 7, 2018

Same issue. I run a UI library for React and I need to test across 6 different versions since the react api is subtlety different between them.

Same issue. I run a UI library for React and I need to test across 6 different versions since the react api is subtlety different between them.

@armanriazi

This comment has been minimized.

Show comment Hide comment
@armanriazi

armanriazi May 16, 2018

According to the following links how match package.json for angular 5 and 6

In my use case I need to have both of them on "Dependency" section.It's not important how handle with every form.

key : "npm-install-version"
{ "name": "app-angular", "version": "1.0.0", "scripts": { "npm-install-version": "npm-install-version", "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "private": true, "dependencies": { "core-js": "^2.5.4", "zone.js": "^0.8.26" }, "devDependencies": { "@angular-devkit/build-angular": "~0.6.1", "@angular/cli": "~6.0.1", "@angular/compiler-cli": "^6.0.0", "@angular/language-service": "^6.0.0", "@types/jasmine": "~2.8.6", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "~4.2.1", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~1.7.1", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~1.4.2", "karma-jasmine": "~1.1.1", "karma-jasmine-html-reporter": "^0.2.2", "npm-install-version": "^6.0.2", "protractor": "~5.3.0", "ts-node": "~5.0.1", "tslint": "~5.9.1", "typescript": "~2.7.2" }, "npm-install-version": { "@angular/animations": [ "^6.0.0", "^5.1.0" ], "@angular/common": [ "^6.0.0", "^5.1.0" ], "@angular/compiler": [ "^6.0.0", "^5.1.0" ], "@angular/core": [ "^6.0.0", "^5.1.0" ], "@angular/forms": [ "^6.0.0", "^5.1.0" ], "@angular/http": [ "^6.0.0", "^5.1.0" ], "@angular/platform-browser": [ "^6.0.0", "^5.1.0" ], "@angular/platform-browser-dynamic": [ "^6.0.0", "^5.1.0" ], "@angular/router": [ "^6.0.0", "^5.1.0" ], "rxjs": [ "^6.0.0", "^5.5.2" ] } }

According to the following links how match package.json for angular 5 and 6

In my use case I need to have both of them on "Dependency" section.It's not important how handle with every form.

key : "npm-install-version"
{ "name": "app-angular", "version": "1.0.0", "scripts": { "npm-install-version": "npm-install-version", "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "private": true, "dependencies": { "core-js": "^2.5.4", "zone.js": "^0.8.26" }, "devDependencies": { "@angular-devkit/build-angular": "~0.6.1", "@angular/cli": "~6.0.1", "@angular/compiler-cli": "^6.0.0", "@angular/language-service": "^6.0.0", "@types/jasmine": "~2.8.6", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "~4.2.1", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~1.7.1", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~1.4.2", "karma-jasmine": "~1.1.1", "karma-jasmine-html-reporter": "^0.2.2", "npm-install-version": "^6.0.2", "protractor": "~5.3.0", "ts-node": "~5.0.1", "tslint": "~5.9.1", "typescript": "~2.7.2" }, "npm-install-version": { "@angular/animations": [ "^6.0.0", "^5.1.0" ], "@angular/common": [ "^6.0.0", "^5.1.0" ], "@angular/compiler": [ "^6.0.0", "^5.1.0" ], "@angular/core": [ "^6.0.0", "^5.1.0" ], "@angular/forms": [ "^6.0.0", "^5.1.0" ], "@angular/http": [ "^6.0.0", "^5.1.0" ], "@angular/platform-browser": [ "^6.0.0", "^5.1.0" ], "@angular/platform-browser-dynamic": [ "^6.0.0", "^5.1.0" ], "@angular/router": [ "^6.0.0", "^5.1.0" ], "rxjs": [ "^6.0.0", "^5.5.2" ] } }

@armanriazi

This comment has been minimized.

Show comment Hide comment
@armanriazi

armanriazi May 16, 2018

Because i need Angular 5 for GraphQl and Angular 6 for stable material UI !!?

Because i need Angular 5 for GraphQl and Angular 6 for stable material UI !!?

@Mani-RRI

This comment has been minimized.

Show comment Hide comment
@Mani-RRI

Mani-RRI May 22, 2018

hello every one,
I need both rxjs@^5.5.0 and rxjs@^6.0.0-beta.4 have to be installed. But if I try to install one of these, the other gets vanish. Do I have a solution?

hello every one,
I need both rxjs@^5.5.0 and rxjs@^6.0.0-beta.4 have to be installed. But if I try to install one of these, the other gets vanish. Do I have a solution?

@nyurik

This comment has been minimized.

Show comment Hide comment
@nyurik

nyurik May 22, 2018

@Mani-RRI yes, we switched to yarn, and used their aliasing system. Works well.

nyurik commented May 22, 2018

@Mani-RRI yes, we switched to yarn, and used their aliasing system. Works well.

@Mani-RRI

This comment has been minimized.

Show comment Hide comment
@Mani-RRI

Mani-RRI May 23, 2018

@nyurik , thank you : )

@nyurik , thank you : )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment