Skip to content

Workspaces phase 3: linking #66

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

Merged
merged 9 commits into from
May 30, 2017
Merged

Workspaces phase 3: linking #66

merged 9 commits into from
May 30, 2017

Conversation

bestander
Copy link
Member

@bestander bestander commented May 18, 2017

Linking between workspaces

Rendered

@bestander
Copy link
Member Author

Asking for comments from @arcanis @thejameskyle @cpojer @zertosh @Daniel15

@bestander bestander changed the title Workspaces phase 3 Workspaces phase 3: linking May 18, 2017
"dependencies": {
"chalk": "^1.1.3",
"diff": "^3.2.0",
"**jest-matcher-utils**": "^20.0.3",
Copy link

Choose a reason for hiding this comment

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

doesn't render as bold.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, apparently I can't mix markup into code blocks

@jamiebuilds
Copy link
Contributor

This is a bit separate, but one of the important things to keep in mind about the linking phase is what order you run the postinstall/prepublish scripts. It's possible for one workspace to depend on another another workspace within the same project and to use it as part of these scripts.

If you run the scripts in the wrong order on the workspaces, one might not be ready by the time another one goes to use it.

Lerna sorts them topologically based on which workspaces depend on one another. But that still has problems with circular dependencies.

I've been thinking about ways to mitigate this.

  1. Give different priorities to dependency sorting so that "devDependencies" are treated more important for build scripts than "dependencies"
  2. Add a way of resolving circular dependencies either as an additional field in workspace's package.json or in the project's package.json
  3. Allow the Project's package.json#workspaces field specify dependencies in the order they should be built in:
{
  "workspaces": [
    "packages/build-tool",
    "packages/*"
  ]
}

We could also combine some of these, they could all work together.

But the sorting process should definitely alert the user if it is unable to sort the workspaces definitively.

@bestander
Copy link
Member Author

Good points, @thejameskyle.
I'll add this to the RFC


In particular, testing packages that refer other packages from the same codebase can be difficult because Node.js and front end bundling tools would look up the referred packages in node_modules folder as it should be installed from npm registry.

Yarn Workspaces need to enable referring other local packages the same way when local packages are in development mode (source of truth is the package source code) and in production mode (source of truth is the package installed from npm).
Copy link

Choose a reason for hiding this comment

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

nit: "need to be able to refer to other local packages"

| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ packjage.json
Copy link

Choose a reason for hiding this comment

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

package.json here and below.

```
{
"name": "jest-matcher-utils",
"description": "A set of utility functions for jest-matchers and related packages",
Copy link

Choose a reason for hiding this comment

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

Can you get rid of all the non-essential stuff from this package.json and replace it with ?

| ---------------- **jest-matcher-utils**/ (symlink) -> ../jest-matcher-utils
| ------------ package.json
...
```
Copy link

Choose a reason for hiding this comment

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

nice description of the solution.


### Dependencies and version matching

Yarn would only link workspaces to each other if they match semver conditions.
Copy link

Choose a reason for hiding this comment

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

As @arcanis pointed out, we should absolutely warn in the case that it is not. In Jest, for example, this has caused issues in the past and we didn't know about it. Can you add it to the RFC?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it should always warn. This breaks Babel's use case where it is self-hoisting and wants to use an older version intentionally.

Copy link
Member Author

Choose a reason for hiding this comment

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

I suppose it could report which packages are linked after install.
I agree with @thejameskyle that it can be annoying if it is intended

Copy link
Member Author

Choose a reason for hiding this comment

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

But I think it is early to spec this detail, we'll need to see what level of reporting works here.
Definitely it should be in verbose logs

| ------------ package.json
| -------- jest-diff/
| ------------ node_modules/
| ---------------- **jest-matcher-utils**/ (symlink) -> ../jest-matcher-utils
Copy link

Choose a reason for hiding this comment

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

Can you write down in words that the symlink is relative, just to make sure we have this captured properly?


As long as **jest-matcher-utils** does not make relative requires via its parent folder, flag **--preserve-symlinks** won't be necessary.


Copy link

Choose a reason for hiding this comment

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

rm empty duplicate line.


This solution creates a symlink inside node_modules of a Workspace package and symlinks have multiple drawbacks:

* Symlinks are not supported in all tools (e.g. watchman)
Copy link

Choose a reason for hiding this comment

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

We can potentially punt on this for a while.

This solution creates a symlink inside node_modules of a Workspace package and symlinks have multiple drawbacks:

* Symlinks are not supported in all tools (e.g. watchman)
* Symlinks are not supported well in all OS and environments (Windows pre 10 Creative updated, Docker on SMB storage(?))
Copy link

Choose a reason for hiding this comment

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

Could we have an alternative mode, especially for CI, where we run "yarn build" and then "yarn pack" on every package and cp the build into node_modules instead of using symlinks? CI's don't need the symlinks because you aren't changing the code there. Symlinks are only really important during development.

Copy link
Member

Choose a reason for hiding this comment

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

Running yarn build implies that the module has its dependencies ready, which might not be the case when working with cyclic dependencies.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've seen once a cyclic dependency with post install scripts.
Not a common but possible case.
What if we just don't support cyclic workspaces?
It seems like a poor design and causes a lot of trouble.


* Symlinks are not supported in all tools (e.g. watchman)
* Symlinks are not supported well in all OS and environments (Windows pre 10 Creative updated, Docker on SMB storage(?))
* A symlink to **jest-match-utils** does not emulate actual installation of the package, it just symlinks to the package source code - no prepublish and postinstall lifecycle scripts are executed and no files are filtered (as done during publishing)
Copy link

Choose a reason for hiding this comment

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

You are using the wrong module name ;)

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it is correct.
jest-diff -> jest-match-utils

Copy link

Choose a reason for hiding this comment

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

It's jest-matcher-utils.

Copy link
Member Author

Choose a reason for hiding this comment

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

300px-paris_tuileries_garden_facepalm_statue


## Unresolved questions

* Is there still an issue with Node resolving real paths in symlinked folders (https://github.com/nodejs/node/issues/3402)? I think if all node_modules are installed in the Workspace root which is a parent to all workspaces and there are no relative (via ../../...) requires between workspaces everything should be working fine.
Copy link

Choose a reason for hiding this comment

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

I don't think RFCs should have language like "I think" :D Mind making this more objective?


* Is there still an issue with Node resolving real paths in symlinked folders (https://github.com/nodejs/node/issues/3402)? I think if all node_modules are installed in the Workspace root which is a parent to all workspaces and there are no relative (via ../../...) requires between workspaces everything should be working fine.
* Should the symlinks be created in Workspace root node_modules instead of referring Workspaces?
* Any special treatment for scoped packages?
Copy link

Choose a reason for hiding this comment

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

Can you answer this? It seems easy to solve, they just need to be supported normally, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think there's any need to treat them specially. Maybe I'm missing something though

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, just wanted to confirm it in first iteration

* Should the symlinks be created in Workspace root node_modules instead of referring Workspaces?
* Any special treatment for scoped packages?
* Does it need to work for other type of packages: git, file, etc?
* As described in Workspace phase 1 RFC (https://github.com/yarnpkg/rfcs/pull/60) there is only one lockfile per workspace. Should we have workspaces that are referred from other workspaces referred in the root lockfile?
Copy link

Choose a reason for hiding this comment

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

This is a good question. Do we only want to enable one gigantic workspace or should we enable slices of projects that compose different workspaces (this may not be possible)? For example, if you take Jest and react-native-packager, they have some overlapping modules: would you have two workspaces, one for each project where some modules are shared or would you have one workspace for both projects?

The reason I'm asking is because at FB, if we end up linking 100 packages together, that may actually be slower in the end and managing them outside a workspace may be better. Not something that blocks the current RFC and feature, but something to keep in mind.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a different question, I'll rephrase it.
I think the one that you raised is out of scope for this RFC and we'll need to get back to it later.

Copy link

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

Nice work. I requested a few clarifications here and there and a bunch of nits.

One of the larger issues I'm worried about is that we aren't discussing about build steps here. If we were to create a workspace that contains projects from two separate parent projects that have a different build pipeline, for example one of them uses TypeScript and the other one uses babel, then we don't know how to build the project. This doesn't need to be addressed now, but I believe this needs to be on our mind long term. Imagine Jest's watch mode, instead of running tests, watching for file changes and building different projects whenever something happens ;P

@cpojer
Copy link

cpojer commented May 24, 2017

Also, can you elaborate on the decision to deprecate yarn knit or do it in a separate PR? I don't think it fits into this PR.

@bestander
Copy link
Member Author

Also, can you elaborate on the decision to deprecate yarn knit or do it in a separate PR? I don't think it fits into this PR.

I am rolling this back.
I thought that yarn knit would be deprecated by workspaces and linking but probably we would want to have both anyway and some code could be shared.

@bestander
Copy link
Member Author

One of the larger issues I'm worried about is that we aren't discussing about build steps here. If we were to create a workspace that contains projects from two separate parent projects that have a different build pipeline, for example one of them uses TypeScript and the other one uses babel, then we don't know how to build the project. This doesn't need to be addressed now, but I believe this needs to be on our mind long term. Imagine Jest's watch mode, instead of running tests, watching for file changes and building different projects whenever something happens ;P

There are 2 aspects that I missed:

Copy link

@cpojer cpojer left a comment

Choose a reason for hiding this comment

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

I think this looks solid from my perspective. There is a lot more we'll probably have to do on top of this RFC, but it is a good start and will solve the basic problem for most cases.

@bestander bestander merged commit c1112fb into yarnpkg:master May 30, 2017
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.

5 participants