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

feat: proper yarn workspace support #379

Closed
wants to merge 1 commit into from

Conversation

nlunets
Copy link

@nlunets nlunets commented Jul 26, 2019

Fixes #300

This PR changes the way yarn bundling is being done.
The main thing to consider is that yarn list is nowhere close to what npm ls does so you cannot really rely on that for bundling, especially in a workspace context.

Instead the code goes through the dependency based on the node resolution algorithm https://nodejs.org/api/modules.html#modules_all_together

At package time this means we might end up with path like "../../../node_modules" which obviously do not make sense in a packaged environment, so those path are stripped to just be node_modules ...

@msftclas
Copy link

msftclas commented Jul 26, 2019

CLA assistant check
All CLA requirements met.

@joaomoreno
Copy link
Member

I'm also not too excited to simply duplicate npm's internal behavior. Any chance we can simply depend on npm and use its API? #246

@joaomoreno joaomoreno self-assigned this Jul 26, 2019
@joaomoreno joaomoreno added this to the Backlog milestone Jul 26, 2019
@nlunets
Copy link
Author

nlunets commented Jul 26, 2019

Unfortunately not really, running npm-ls on a yarn workspace installed package just results in a lot of errors because the package are not where they are expected.

Furthermore we cannot even rely on the basic node resolution capabilities (require.resolve and require.resolve.paths).
The first one expect a resolveable package (ie: with a clear main script) which is not a guarantee (see babel/babel#5509)
The second one works based on the current file location (ie the npm.js file) which could be located anywhere in the dependency tree.

From the issue you linked it seems that even npm ls is problematic anyway...
In the end what you want to bundle is not related to who installed it or how they installed it, even npm or yarn can install packages in many different ways and your local setup might affect that.
Following the node resolve logic is (in my opinion) a safer approach as you would now depend on only one logic, which has been stable for years and which works regardless of which package manager installed the dependencies or how they did it :/

@nlunets
Copy link
Author

nlunets commented Aug 28, 2019

@joaomoreno any chance for you to have a deeper review on this ?

@brpowell
Copy link

@joaomoreno any chance for you to have a deeper review on this ?

Would love to see this reviewed! The change would unblock adoption of yarn workspaces for our project.

@joaomoreno joaomoreno removed this from the Backlog milestone Oct 11, 2019
@joaomoreno
Copy link
Member

joaomoreno commented Nov 28, 2019

@nlunets Looking into this. Can you give me a concrete example of an extension which would depend on this?

Also, would it be enough to simply detect symlinks and resolve them accordingly, instead of changing the whole algorithm?

@ullasholla
Copy link

@joaomoreno, here's a example repo you can test against: https://github.com/ullasholla/yarn-workspace-test

yarn hoists dependencies to the workspace root and hence just following symlinks will not help.

@ullasholla
Copy link

@joaomoreno, have you had a chance to look at this? Cheers.

@bestander
Copy link

Thanks @nlunets for sending the patch.
Until the PR is accepted I've published the patch to npm https://www.npmjs.com/package/vsce-yarn-patch

@bestander
Copy link

bestander commented Jan 15, 2020

And I take some(ok, all) responsibility that yarn ls command sucks in workspaces mode :(
It just slipped through the cracks.
Now it's a bit too late with Yarn V2 being imminent.

@joaomoreno, any chance this can be accepted?
The fix does work on workspaces repos.

Copy link
Member

@joaomoreno joaomoreno left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I take some(ok, all) responsibility that yarn ls command sucks in workspaces mode :(
It just slipped through the cracks.
Now it's a bit too late with Yarn V2 being imminent.

What do you mean?

const files = fileNames.map(f => {
// In case of a yarn workspace the filepath can point to node_modules at a higher level, we can just strip that within the extension
let basePathF = f;
while(basePathF.indexOf('../') === 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you test this on Windows? Also, please do not use indexOf to check for a prefix...

let dependencyPath;
let newPrefix = prefix;
// Follow the same resolve logic that is used within npm / yarn
while(newPrefix !== "/" && !dependencyPath) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works on Windows?

if(!dependencyPath) {
dependencyPath = path.join(prefix, "node_modules", name)
}
const depPackage = require(path.join(dependencyPath, "package.json"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use require to load a JSON file from disk.

const usingPackagedDependencies = Array.isArray(packagedDependencies);
const trees = JSON.parse(match[0]).data.trees as YarnTreeNode[];
const rootPackage = require(path.join(cwd, 'package.json'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use require to load a JSON file from disk.

const usingPackagedDependencies = Array.isArray(packagedDependencies);
const trees = JSON.parse(match[0]).data.trees as YarnTreeNode[];
const rootPackage = require(path.join(cwd, 'package.json'));
const trees = Object.keys(rootPackage.dependencies);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of trees, shouldn't it be packages? Or dependencies?

@@ -837,7 +837,14 @@ export function collect(manifest: Manifest, options: IPackageOptions = {}): Prom
const processors = createDefaultProcessors(manifest, options);

return collectFiles(cwd, useYarn, packagedDependencies).then(fileNames => {
const files = fileNames.map(f => ({ path: `extension/${f}`, localPath: path.join(cwd, f) }));
const files = fileNames.map(f => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather we change the return values of collectFiles to return absolute paths instead of hardcoding yarn workspaces knowledge down here.

@bestander
Copy link

And I take some(ok, all) responsibility that yarn ls command sucks in workspaces mode :(
It just slipped through the cracks.
Now it's a bit too late with Yarn V2 being imminent.

What do you mean?

Never mind, I implemented the workspaces in yarn and did not realize that list command got broken.
It's worth making a fix in Yarn V2 https://github.com/yarnpkg/berry though when it's released

@bestander
Copy link

I was a bit too eager on this PR, turns out it goes into infinite loop in some cases.
It needs to maintain a set of visited folders when looping through node_modules.

@bestander
Copy link

@nlunets, I've forked your PR and pushed this fix to the infinite loop bestander@44d3c26

Let us know if you want to proceed with the PR feedback

@nlunets
Copy link
Author

nlunets commented Jan 17, 2020

@bestander thanks for your involvement !
Since you probably have deeper knowledge of how yarn does its magic it might indeed be better if you take care of the PR feedback !
Thanks !

@bestander
Copy link

bestander commented Jan 17, 2020 via email

@bestander
Copy link

Apologies, everyone.
I was distracted by other work and did not finish cleaning up the PR.
I plan to follow up but can't commit to a specific date yet.

@alexgorbatchev
Copy link

Ping! Would love to see this merged soon! Thanks for making it happen!

@joaomoreno
Copy link
Member

Closing since the feedback wasn't addressed and it seems @bestander will simply create a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support yarn workspaces
7 participants