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

[Feature] v2 equivalent of v1's "yarn install --production --frozen-lockfile" #2253

Closed
1 of 2 tasks
concision opened this issue Dec 19, 2020 · 9 comments
Closed
1 of 2 tasks
Labels
enhancement New feature or request waiting for feedback Will autoclose in a while unless more data are provided

Comments

@concision
Copy link

concision commented Dec 19, 2020

  • I'd be willing to implement this feature (contributing guide)
  • This feature is important to have in this repository; a contrib plugin wouldn't do

User Story

As a developer who ships several Node.js-based Docker images, Yarn v1 has historically offered me two important functionalities in my workflows:

  • yarn install --production[=true]: Optimized final runtime image sizes via installing only production dependencies (as devDependencies were simply unused/unnecessary to ship).

  • yarn install --frozen-lockfile: Determinism is required in the Docker builds - a build today should be exactly the same as a build a year from now (barring timestamp differences). The v1 --frozen-lockfile flag aided in achieving determinism when a contributing developer made a mistake by not properly checking in a yarn.lock into a SCM system. The --frozen-lockfile flag would cause a build to fail and allow a developer to investigate the CI logs to resolve the issue.

    From the v1 documentation of yarn install:

    If you need reproducible dependencies, which is usually the case with the continuous integration systems, you should pass --frozen-lockfile flag.

    Without --frozen-lockfile, the locked dependencies may not be specified in the yarn.lock in the SCM repository - Yarn will automatically attempt to install a compliant version specified in package.json. This leads to non-deterministic builds, as each time the build is fired on the CI system, the dependency is unlocked and may change (in part due to potential new dependency releases).

The full form of the Yarn v1 command for my use case was RUN yarn install --production=true --frozen-lockfile which optimizes the final runtime build and ensures a deterministic build, or it would otherwise fail when the CI/CD pipeline is fired (which is more desirable than a non-deterministicly-built production image).


As a developer migrating to Yarn v2 for its PnP innovation, the equivalent of these v1 features are necessary to ensure the same CI/CD workflow that was available in Yarn v1. From my understanding, these two functionalities are currently mutually exclusive in Yarn v2 (described in the "Considered Alternatives" section) - only one of these may be picked (and the obvious answer is --production is more important for the end user of the shipped production image). Notably, I would be much less inclined to submit this feature request if the behavior was not already thoroughly supported in v1.

Note: To be more specific, this issue applies to single module projects that are not multi-module workspaces.


Possible Solutions

As I see it, there are a couple possible solutions that would resolve this missing functionality:

  • (recommended) add a v2 equivalent of v1's yarn check command allowing Docker developers to do akin to the following: RUN yarn check && yarn workspaces focus --production which would be canonically equivalent to the behavior seen in v1's RUN yarn install --production=true --frozen-lockfile. A non-zero exit code on inconsistent lockfiles would be beneficial. This solution is, in my opinion, the most viable one - it enables developers to run validity checks on a lockfile without initiating an install.
  • add a --production flag to yarn install that works for non-workspaces (i.e. a single module), which currently only supports --immutable (the v2 equivalent of v1's --frozen-lockfile).
  • add an --immutable flag (behaving the same as yarn install --immutable) to the yarn workspaces focus command, which currently only supports --production.

Solution Drawbacks

The implementation for all of the above mentioned solutions may be far from trivial with the current architectural design of the current system (or maybe not?). A contributor/maintainer on the project would likely be able to answer that. Yarn v1's support of this combined functionality is succinct proof this functionality is possible to implement.


Considered Alternatives

The current alternative contenders are:

  • yarn check; however this command has been deprecated after Yarn v1.
  • yarn install --immutable; however, this has no support for --production for installing only production dependencies. Furthermore, this cannot be used to validate the lockfile as it has side effects - the filesystem is modified.
  • yarn workspaces focus --production --production, which is also mentioned in the seemingly duplicate issue [Feature] install --prod #1320. However, there is no support for the --immutable/--frozen-lockfile flag. Furthermore, an entire workspaces development plugin should not be the recommended option for simply installing production dependencies for a single-module non-workspace project.
  • a third party plugin; however, this has significant security implications (e.g. who is maintaining it - an arbitrary individual or an organization?). Yarn has earned its reputation, other individuals/organizations may not have or may be more susceptible to malicious contributions.
  • have other contributing developers on your project always ensure a yarn.lock file is checked into SCM that is consistent with package.json, but hahaha that's a funny one :^)

This is a core functionality that was available in Yarn v1 - it should also be a core functionality in Yarn v2, and not separated into a plugin.

@concision concision added the enhancement New feature or request label Dec 19, 2020
@arcanis
Copy link
Member

arcanis commented Dec 19, 2020

I believe you didn't consider the reason why those flags don't work together. Specifically:

  • As you mention, the --frozen-lockfile is a validation flag that you put in your CI to validate that your project is in the correct state before your merge pull requests in.

  • The --production flag, on the other hand, is a deployment flag that restricts the dependencies that the package manager even sees. You use it to optimize your production deployment (the flag name is a clue 😛).

Both flags are useful at different times, and using --production --frozen-lockfile was an antipattern because, by the time you ran --production, you already were supposed to have a lockfile that passes --frozen-lockfile, because it got enforced in your CI. Even if you deploy your app as part of your CI (for example in a temporary environment unique to each PR), then there's nothing preventing you from doing two jobs, one for validation and one for deployment, or to simply call --frozen-lockfile (or rather --immutable in this case) before --production.

Finally there are technical requirements that make the behaviour you want a non-starter. Specifically, we fixed with --immutable various bugs around --frozen-lockfile so that it detects when dependencies would be extraneous (which was a long-requested bugfix), but it means that it makes it incompatible with focus and --production (which, necessarily, are excluding dependencies from the install, causing the lockfile to shrink; the check that --frozen-install would do would thus never be the same as what you get from the general command, which is counterintuitive and not something we'll pursue).

@arcanis arcanis added the waiting for feedback Will autoclose in a while unless more data are provided label Dec 19, 2020
@concision
Copy link
Author

Thank you for lending insight on your point of view/design decisions on the matter - it is not as immediately obvious to me, as an end user (e.g. was this an accidental oversight? currently in the product backlog? a technical limitation? an intentional design decision?).

I believe I failed to clearly articulate my primary point across correctly - the feature proposal is to implement some form of validation check that has no side effects (i.e. do not touch the filesystem by installing to .yarn./cache). However, try not to latch onto "I am specifically proposing --production on yarn install --immutable" - that is certainly not my intention here, only a possible solution (of which there seems to be a perfectly acceptable counterpoint of technical issues/limitations).

To be clear, I don't really care how this is achieved - I am submitting a feature request indicating that some form of no-side-effect validation check is useful in developer workflows.


My underlying problem with the current recommendation is (unless I am missing some command/flag here) that I must install devDependencies and dependencies to validate the lockfile.

Perhaps then, a better proposal I can put forth is to implement a --validate-only/--dry-run flag for yarn install - it acts similar to --immutable, but will not actually install any dependencies. If the lockfile would need to be changed, a non-zero exit code would be produced. This functionality would provide enough to meet most, if not all, use cases for validating lockfiles (e.g. validation prior to a merge request, validation during deterministic builds, or validation at production "deployment"/dependency collection).

If this no-side-effect functionality is supported already, then I have missed it and would appreciate a pointer to the relevant documentation explaining it; in this case, this issue can also be closed.


One last thing I think is worth noting - I completely agree with your distinction between validation prior to merge, and only installation after the fact. This is an ideal seperation of roles in a workflow.

However, this makes a few assertions or assumptions about how a developer has setup and/or is_able to setup_ their system. Quite often, developers are often not given the sign off to change the system to a better topology: if it works already, why are you trying to improve it?

Consider a simple Dockerfile using Yarn v1 where only production dependencies are to be collected:

FROM node
WORKDIR /app
COPY package.json yarn.lock /app
COPY .yarn /app/.yarn

# either this
RUN yarn install --production --frozen-lockfile
# or alternatively something similar to
RUN yarn check && yarn install --production
...

In this case, no development dependencies need to be installed (might be necessary for only local development, but not for building). Further, dependencies only need to be installed once, not twice in v2 for yarn install --immutable validation and yarn workspaces focus --production "deployment".

This interesting/useful part of this example is no assertions or assumptions are made about any local development or CI/CD workflows - it indiscriminately fails the build if the lockfile is in an inconsistent state.


Thanks again for your time and feedback on both GitHub and the community Discord.

@arcanis
Copy link
Member

arcanis commented Dec 20, 2020

My underlying problem with the current recommendation is (unless I am missing some command/flag here) that I must install devDependencies and dependencies to validate the lockfile.

You must resolve both dependencies and devDependencies to validate the lockfile. If the devDependencies weren't part of the resolution, they would necessarily be found as extraneous, and thus would cause --immutable to fail. And since they have to be part of the resolution, they also have to be installed, if there's any install.

If what you want is to run a validation without touching the filesystem too much ("at all" is difficult, since we need to work with the cache for instance if a git dep is missing, etc), then you can do that by implementing a plugin that would just call the sub-step Project#resolveEverything instead of the all-encompassing Project#install. But it's a very fringe use case (even at worst, PnP installs only take a few seconds, making the benefits of skipping the linking moot), so it won't be a default (and I personnally wouldn't recommend this tradeoff).

if it works already, why are you trying to improve it?

I've been working on Yarn for years. I've learned that the best way I can maintain a project is to be clear about the patterns we want to recommend, and not bend sideways to support use cases unless we're convinced the value is clear, significant, and with little risks for the core team in terms of long term maintenance. Features always seem simple when you don't deal with the aftermath decisions three years down the road 😛

In this case, no development dependencies need to be installed (might be necessary for only local development, but not for building). Further, dependencies only need to be installed once, not twice in v2 for yarn install --immutable validation and yarn workspaces focus --production "deployment".

Refer to the technical challenges I mention in the first paragraph of this post. Because it seems to work in the v1 doesn't mean it actually has the right behavior - just that you didn't notice its shortcomings (like not being able to detect when the lockfile would actually change because of entries being removed).

@concision
Copy link
Author

I disagree that validating a package.json's and a yarn.lock's consistency without side effects is a fringe use case. The alternative recommendation presented is to unnecessarily install all dependencies onto the filesystem to validate the lockfile - a fairly inefficient operation in projects that have large quantities of dependencies (especially when the legacy node-modules linker is required).

Thank you for the pointers into looking into a plugin. Unfortunately, this now means any implementation I pursue developing will be covered by an NDA and no longer benefits the open source community. I am also unable to maintain an open source version due to conflict of interests in dependency supply chains at my organization (I do not write the security rules).


I will be closing this issue since it seems clear there is no interest in considering this in the feature backlog. I am merely suggesting a beneficial feature that I thought would add value to the Yarn v2 project. This unnecessarily hostile "you didn't consider the reason", "non-starter", "implement it yourself instead", 😛😛😛 attitude is certainly not conducive to a proper discussion.

Thanks for your time maintaining this project. Cheers.

@kemsky
Copy link

kemsky commented Dec 27, 2021

This is really confusing, as a new yarn 2 user I have to update my CI worflow, but this path is just too convoluted.

We had yarn install --production=true --frozen-lockfile --non-interactive - perfectly clear and simple. Validates lock file, installs only what is needed for build, supresses all interactions. Is that something uncommon?

Now it takes hours to google replacement for each argument:

  • --production=true now requires workspace-tools plugin even if you don't use any workspaces.
  • --non-interactive is not needed anymore, but I had to look through source code to find that.
  • --frozen-lockfile is not possible anymore, because as said above, yarn --immutable will run full install (why, why, why... why don't you put your comment into migration guide?).

@matart15
Copy link

Followed Migration guide.

❯❯❯ yarn workspaces focus --production
Unknown Syntax Error: Command not found; did you mean:

$ yarn workspaces list [--since] [-R,--recursive] [-v,--verbose] [--json]
While running workspaces focus --production
❯❯❯ yarn workspaces focus --all --production
Unknown Syntax Error: Command not found; did you mean:

$ yarn workspaces list [--since] [-R,--recursive] [-v,--verbose] [--json]
While running workspaces focus --all --production

@alokdeshwal-st
Copy link

@matart15 use .yarnrc.yml as below.
`plugins:

  • path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
    spec: "@yarnpkg/plugin-workspace-tools"`

@matart15
Copy link

matart15 commented May 6, 2022

@alokdeshwal-st

Thank you. For now, I changed to npm.
Will try it next time.

@jackykwan-eventx
Copy link

jackykwan-eventx commented Mar 30, 2023

--production / --frozen-lockfile should only depends on user use case,
User can combine the command to do whaever they want

It will be great to be a "SUGGESTION", not "FORCE"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request waiting for feedback Will autoclose in a while unless more data are provided
Projects
None yet
Development

No branches or pull requests

6 participants