-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Workspaces: lock file per workspace #5428
Comments
based on yarn blog:
it doesn't seem necessary to bundle yarn.lock when publishing the individual package... it is more a development artifact for the whole repo, therefore, no need to put it in each package. |
@connectdotz it may not be needed for a library or published package but for building a docker container you're going to want to deploy somewhere it definitely would be. |
sure... but wouldn't the development docker container just have the whole repo and therefore the yarn.lock anyway? I can see we use docker containers to test our monorepo project for different OS or platforms, in which case we just deploy the whole repo and its yarn.lock. Can you give me an example use case that you need to deploy individual packages from the monorepo project into docker containers during the development cycle, so I can get a more concrete understanding... |
So for us, we don't want to package the whole monorepo into the resulting docker container. We are using docker in production and those images should be as light as possible. Our mono repo is quite big and contains multiple microservices that share code between them using library packages (and some of the libraries are relevant for some of the microservices, but not all). So when we package a microservice, we want the image to contain the files of that microservice and any other dependencies as proper dependencies - downloaded from our private registry, and built for the arch of the docker image. So I think the main consideration here is to keep our docker images as light as possible, and packaging the whole monorepo doesn't fit our needs. Also, when we run "yarn" inside the image of the microservice, we don't want to have symlinks there, just a normal dependency. The solution here doesn't have to be creating a yarn.lock file per workspace, it could also be a yarn command, that helps in the process of packaging a given workspace, generating a yarn.lock file for a workspace on demand, etc.. Hope it helped clearify the use case.. 🍻 |
@netanelgilad thanks for details, it does help to clarify that your use case is more about publishing individual packages, for production or development, to docker containers. Please join the discussion in #4521 so we can start to consolidate them. |
While I can se the use of individual lock files, they are not necessary. If you run docker from the root of the repo with the You only need the package.json for the packages you will build in the image and yarn will only install packages for those package.json files you have copied in even thou the yarn.lock includes much more. EDIT: With that said. it causes docker cache to not be used for package changes in any package even though it is not included in the build |
#4206 is related/duplicate, and the use-case described there is exactly the problem we're facing:
|
I have similar issues with workspaces. My project is a
Workspace packages There are 2 possible solutions:
|
Also struggling with this. We've got an Angular CLI project alongside our API so they're in the same repository and trying to push the frontend to Heroku. We're using a buildpack which tells Heroku to jump up to the frontend repository first: https://github.com/lstoll/heroku-buildpack-monorepo Problem is, there's no |
You can just use the global yarn.lock file with the individual packages. I've recently approached my Dockerfile like this:
This will install only dependencies that are actually in use by the two packages I copied and not by anyone else. I have a build process where first I'd like to create a release artifact from one package and then not have any of its dependencies installed. This is fairly easy with Docker's multistage build
And you'll end up with a small container that only contains the dependencies specified in your yarn.lock file and needed in production. |
@johannes-scharlach @connectdotz I think that from my end, this issue could be closed and we can keep working on issue #4521. Since the main yarn.lock file could work with a subset of the packages, it seems like a yarn.lock per workspace is not necessary (even though I still think this could be a better dev workflow 😉 ). But the issue in #4521 is still important, because in the solution we got to here, we need to mention every dependency workspace in the Dockerfile even though yarn should know the interdependencies and how "vendor" a given workspace. |
I spent the last couple of days trying to convert our monorepo to first Lerna and then Yarn workspaces. Yarn worked generally more reliably and it's really close to what we need, especially with the recent introduction of However, the single
What would you think about Yarn workspaces being just a tiny core – a declaration of packages without any specific functionality. For example:
Etc. These are just examples and in practice, some features would probably be opt-out instead of opt-in (for example, people expect a single What do you think? |
I believe the problem this feature request is addressing is the same as in #4521 . A command to do essentially what @johannes-scharlach describes would certainly be more feasible than a lockfile per workspace. There is also an RFC open right now for nested workspaces, which sounds similar to this feature request though I believe it's solving a different problem. |
Workspaces won't drastically change, I think we're satisfied with their current interface.
That's already possible (v1.10, #6244).
Since we won't change the workspace interface it would be the opposite ( What I don't like about this is that it takes a technical behavior (hoisting) and tries to turn it into a semantical behavior. You should focus on the user story and then figure out the implementation rather than the opposite. In this case, I think your use case ("Installing dependencies in specific package only") would be better solved by extending |
I guess the core question is whether hoisting and a single For example, in our use case, the best hypothetical behavior of workspaces would be:
Hoisting can be disabled with |
I think the best way to solve this would be to have That way, you could simply copy the workspace lockfiles when publishing your app at a certain version, and install in Yarn doesn't have to install the entire lockfile; it should easily be able to extract only the part of the dependency graph relevant to that package. |
In fact this might be fairly easy to do manually even now:
edit: unfortunately this is all wrong, as the workspace lockfile does not include the versions of packages within the workspace, which might be dependencies of the app package. There would need to be something more involved than copying when creating app lockfiles from workspace lockfiles. |
I'm not exactly sure if separate lockfiles is the answer, but I have a similar problem. I have a monorepo set up with a CLI and a backend. The CLI requires a few packages that are platform-specific and only work on desktop machines with a particular setup. On the other hand I need to be able to build my api into a docker image, which is fundamentally impossible in the current implementation of workspaces. |
Very similar use case than @samuela here! This one would be massively helpful! |
My use-case might seem laughable compared to the other, "real" ones. But I have a monorepo for some utils - in ths case react hooks - inside I have a second workspace next to Now, although the What I would wish for is a way to specify that some workspaces shall use some specific lockfiles, e.g. some mapping like so:
Or even a way to specify "do not put anything from this workspace into the lockfile at all". But yeah, mine is not a serious use-case in the first place :) |
You nailed it – as I see it, one of the very core benefits of yarn.lock file is for creating frozen-dep production builds! Did the creators of Yarn forget that? |
Maybe it's also worth moving this discussion to npm itself, which supports workspaces too starting with v7.0.. |
I've been researching related topics and would like to add some clarification to my comment above (mostly aimed at less experienced developers I suppose, since the issues I was facing were to some extent due to my failure in understanding the importance of "locking all dependencies to specific version" is called pinning; unfortunately, it will not prevent things from potentially breaking if sub-dependency updates (final paragraphs of the article here), which I haven't considered. That is exactly what lockfile meant to prevent from happening. I've wasted more than enough hours on breaking updates in the past on multiple occasions; I will experiment with using Above said, I'm very much looking forward to any progress on this issue |
@migueloller Individual lock-files mean individual Yarn Monorepos. You can't have a lock-file for a Workspace because it breaks deps uniformity in the Monorepo. If you want to do so, you're going away from the original idea of Yarn Monorepo: it's about unifying, hoisting, and reducing deps into a flat list in the root instead of having different versions (and even whole subtrees) in different workspaces. |
@the-spyke but the original issue is about exactly the opposite. A lock file per workspace. I fail to understand how you cant have a lockfile per workspace. It breaks deps uniformity in the Monorepo? Sure for development. But the whole purpose of shared dependencies goes out the window when you must deploy lightweight micro services from each of your workspaces Shared, hoisted deps only makes sense in development. For a workspace to live in Docker, it requires a lockfile. |
@dan-cooke As you can see, I had this issue in 2018 too, but now I have different opinion. You're saying Docker and Microservices. But what if I develop a regular Same time, if you're developing microservices (MSs) there 2 possible situations:
So, what I was saying it that maybe the issue doesn't look like what it is. |
@the-spyke Its definetly not a "one size fits all" solution anyway |
@the-spyke, your bring up good points. Perhaps more thought needs to be put into what problems Yarn workspaces was designed to solve and if using it to manage large monorepos is aligned with that design. I'm curious as to how you would solve a scenario like this:
The next question to ask would be "How does one get the benefits of hoisting with this method?" For example, if I'm going to give this a shot and will report back. If this ends up working, then perhaps we've just been using Yarn workspaces wrong all along... EDIT: I tried it out, and it does work. |
I've changed my stance now and realize that while having an individual lockfile per workspace might be the first thing that comes to mind when managing an entire monorepo with Yarn workspaces, it might not be the right question. A better question might be "Is Yarn workspaces designed to manage a monorepo?". The answer, as usual, is "it depends". If you're Babel and you have a single team working on the monorepo and everything is meant to change in lockstep, then yes, this is what Yarn workspaces was designed for. But if you're an organization with multiple teams and you're using a monorepo, you likely don't want to manage the entire monorepo with a single Yarn workspace root. You probably just want to use Yarn's default behavior or multiple Yarn workspace roots within the monorepo. This will be determined by what apps you're building, how many teams there are, etc. For us, it became clear that for each deployable entity (in our case there's a Dockerfile), we want to have a separate
There's a whole other host of problems that come with running a monorepo. For example, what about tracking dependencies and only rebuilding things that changed to save time in CI? Yarn workspaces could help there by letting you query the dependency graph. Lerna does this, for example, to allow topological sorting of commands being run. Yarn v2 actually lets you query the dependency graph as well. The package manager PNPM also does that. But I would argue that depending on the complexity of the monorepo one might want to try tools built for that (not package managers) like Bazel, Pants, Buck, etc. |
@migueloller From your requirements I see that you don't need a strictly independent packages or other exotic things, you also do want slimmer developer installs. In such case you should start with regular Yarn Monorepo: single root and all packages as workspaces. You'll have faster installation times, lower disk usage, and
There're also situations where independent teams develop independent projects. In this case Building a minimal possible Docker image for production use is completely unrelated to the Yarn, but you may force Yarn to reuse a development artifact called |
@the-spyke, in this example I only used 3 workspaces but in our actual repo we have over 20 workspaces with a combination of libraries and deployed workloads for both the front-end and back-end. The way I see it now is that we have a monorepo (or what you call multirepo) where it will probably make sense to have multiple Yarn workspace roots with independent lockfiles. We're thinking of using a deployable unit as the unit of separation, it aligns nicely with lockfiles. I think for me, what makes this work very nicely is the fact that Yarn workspaces supports paths outside the workspace root, even though the initial blog post says otherwise. For example, you can have this: {
"workspaces": [
"../lib1",
"../lib3"
]
} |
We have the same use case as @migueloller and one possible idea is for Yarn to support multiple sets of workspaces, like this:
Yarn would maintain two additional lock files (I imagine the main
When building a Docker image e.g. for frontend, we'd create a context (e.g., via tar) that includes this:
What I didn't think about deeply is whether it's possible to install (link in (Something similar was also posted here.) |
@gfortaine, if you read the discussion you will realize that that's actually not the case. The reason for having a separate lockfile has nothing to do with installation, but instead having a lockfile that only changes when a specific package changes. A top-level lockfile will change with every workspace dependency change, but a lockfile scoped to a single package will only change when that package's dependencies change. It might be worth mentioning that that this can be done in user-land. Using the I might take a stab at building this and report back with my findings. |
It looks like that I’ve just found this implementation albeit for pnpm : @pnpm/make-dedicated-lockfile Hope this helps 👍 |
My need for this behavior (versioning per workspace, but still have lockfiles in each package) is that I have a nested monorepo, where a subtree is exported to another repo entirely, so must remain independent. Right now I'm stuck with lerna/npm and some custom logic to attempt to even out versions. Would be nice if yarn (I guess v2, given that's where nested support lies?) could manage all of them at once, but leave the correct subset of the global pinning in each. A postinstall script could attempt to manage the lock files directly, I suppose. Sounds complicated, but would be nice either way. |
For anyone looking to generate a lock file from the workspaces lockfile, I have created a CLI that extracts your dependencies from a passed in package.json and spits out a lockfile using only the contents of the workspace lockfile. You can check it out on npm and GitHub |
Wasn't able to get this working. Shows help |
@heri16 You need to pass in the lockfile and package.json like below: generate-lockfile --lockfile yarn.lock --package package.json I have updated the help output to make this more clear |
If you're using yarn workspaces like I am, I used this and managed to generate a lockfile using the following command (run from within the package itself):
|
Since the goal here was to create docker deployments i'll close this as fixed in v2 where you can use the plugin https://yarn.build/ or https://gitlab.com/Larry1123/yarn-contrib/-/tree/master/packages/plugin-production-install to handle that |
@merceyz i think that for many of us following this discussion, migrating to yarn v2 is not a viable option, as it's still incompatible with a lot of dependencies. Migrating to yarn v2 would require far more work than following some of the workarounds posted earlier. |
@franzmoro I believe you're mistaken - Yarn's current majors support both PnP and node_modules installs, as our Migration Guide makes abundantly clear. If you hit compatibility issues, you have more than enough options to unblock yourself in a few minutes top. If that isn't the case, feel free to open an issue to let us know in more details what blockers you hit exactly. In any cases, we don't intend to spend resources developing features on an outdated codebase when we believe a clearly superior option is freely available, so I'll lock this issue for now. Please direct follow ups if any to our new discussion tab. |
Do you want to request a feature or report a bug?
feature
What is the current behavior?
Using yarn workspaces for a monorepo which includes a top level node module creates only a single
yarn.lock
at the root of the monorepo, with noyarn.lock
that is specific for the top level node module.What is the expected behavior?
I want to use yarn workspaces to manage a monorepo that includes both apps (top level node modules) and libraries. But having only a single
yarn.lock
file at the root of the monorepo prevents me from packaging my app into a docker image for example. I would love a way to get ayarn.lock
file for chosen workspaces that need to have one of their own, because that workspace may later be used outside of the monorepo.An example:
If I have a monorepo with 2 workspaces:
workspace-a
andworkspace-b
.workspace-a
uses some of the exported modules fromworkspace-b
. If I want to packageworkspace-a
into a docker image (or any other way of packaging that workspace by itself, without the whole monorepo), I don't have ayarn.lock
for it. That means that when I'll move the files ofworkspace-a
into a different environment apart from the monorepo, I'll be missing ayarn.lock
file and when installing dependencies, I'll lose all the advantages of a lock file (knowing I'm installing the same dependencies used in development).I'm quite surprised I couldn't find an issue about this. Am I the only one who wants to work with monorepos that way? Maybe I'm missing something? My current workaround is using
lerna
without hoisting at all, so I'll have a lock file per package.The recently released
nohoist
feature also doesn't seem to help (though I hoped), as it doesn't create a differentyarn.lock
per workspace.This issue is somewhat related to this comment on another issue. Thought that it may deserve an issue of its own.
Please mention your node.js, yarn and operating system version.
node 8.9.3, yarn 1.5.1, OSX 10.13.3
The text was updated successfully, but these errors were encountered: