yarnpkg / berry

πŸ“¦πŸˆ Active development trunk for Yarn βš’
https://yarnpkg.com
BSD 2-Clause "Simplified" License
7.43k stars 1.11k forks source link

[Feature] prepack publishing and a root private workspace works unintuitively #4733

Open xenoterracide opened 2 years ago

xenoterracide commented 2 years ago

Describe the user story

As a developer I want to compile my packages before packing but the root prepack script doesn't run when doing yarn workspaces foreach --no-private npm publish --tolerate-republish

Describe the solution you'd like

Perhaps the best option I can think of is a --tolerate-private which would run the prepack step, and pack the private modules but not actually push it.

Describe the drawbacks of your solution

still requires developer knowledge to work

Describe alternatives you've considered

The workaround is to call prepack directly in my prepublish step for my custom yarn script. note: "publish:yarn" naming is due to some company internal CI stuff. The root package here is private and thus skipped, there's only one root typescript build that builds all workspaces using composite.

    "publish:yarn": "yarn workspaces foreach --no-private npm publish --tolerate-republish",
    "postinstall": "husky install",
    "prepack": "yarn install --immutable && tsc --build --verbose",
    "prepublish:yarn": "yarn prepack && ./yarn-login.sh",
noahnu commented 2 years ago

If you're not publishing the root workspace, I don't think it makes sense to run prepack on the root. The root workspace is not "special" in any way.

I'm not a yarn maintainer but my recommendation would be to add a "prepack" entry to each child workspace that calls out to the root (to deduplicate the code). The yarn berry project actually does this. Here's an example on a 3rd party project (one I maintain): https://github.com/tophat/monodeploy/blob/00cd6c10dab0343dfdc6bfbd095b1c7f66a8d213/packages/logging/package.json#L27

There's an additional advantage to having a prepack script defined per workspace, you can support the git protocol with a workspace selector to install a specific workspace from git directly (yarn runs prepack on the target workspace automatically).

xenoterracide commented 2 years ago

Yeah but that's a lot of duplicate code, which is why I'm saying that it would be better to do the tolerate private approach. Also if I did it in every single one, they would all be running typescript build again and again and again and there's only one typescript built at the root because it's a typescript composite repo.

I'm of course not saying that it should necessarily be run automatically, simply that if I say tolerate private, then it runs for that workspace but doesn't actually try to push it. All the advantages, none of the disadvantages in my opinion.

noahnu commented 2 years ago

"--tolerate-private" sounds like it'd run all private workspaces, not just the top level workspace. It also seems contradictory to the "no-private" flag.

For your use case, isn't it simpler to just run the following?

yarn prepack && yarn workspaces foreach --no-private npm publish --tolerate-republish 
xenoterracide commented 2 years ago

for mine, that's more or less what I'm doing now. The new command would be

yarn workspaces foreach npm publish --tolerate-private --tolerate-republish

which also has the benefit of documenting this as it's not really documented that you have to do any workarounds to publish all the modules in a repo.

there is another use case, what if I have modules that I don't want to publish but I need to run prepack for them in order to build other modules. For example, as you suggest, instead of one single compile I had one per module. For example a types module where I'm not publishing the types, instead I'm publishing other modules that are (esbuild) flattened programs. I still have to build the types to build the programs. That is actually a potential problem down the pipeline for us.

noahnu commented 2 years ago

it's not really documented that you have to do any workarounds to publish all the modules in a repo

You don't have to do any workarounds to publish all the modules in a repo. What you're trying to do is run a lifecycle script for a package that you're not publishing.

It's worth noting that there's no connection between yarn workspaces foreach and yarn npm publish. You're running yarn npm publish via yarn workspaces foreach.

what if I have modules that I don't want to publish but I need to run prepack for them in order to build other modules

Prepack is a lifecycle hook that is meant to be run prior to packing. We only pack prior to publishing. It sounds like you want to prepack even packages that won't be published. It's an interesting problem, one I hadn't considered for my own publishing toolchain (should be easy to support this in monodeploy πŸ˜„ ).

Either way, I'll let a yarn maintainer chime in here, but I suspect what you're trying to do is best handled by a build plugin/tool.