Reputation: 1756
reHi!
Here's the deal, we have a monorepo. We're using Lerna & Yarn with a bunch of Angular Libraries.
In every package.json for the packages/libraries, we have something like:
"prepublishOnly": "yarn build <library name goes here>"
The way Yarn works for workspaces is yarn install
, does what it does. Because we use workspaces, it creates symlinks to the packages. For example, if we have a package called @foo/bar
, in the top-level node_modules
, we would have node_modules/@foo/bar
be a symlink to libs/foo-bar
.
Yarn Workspaces is all fine and dandy, except the stuff in node_modules/@foo/bar
isn't ready to be published. First, we need to build the package using Angular CLI's compiler.
We accomplish that with the already mentioned prepublishOnly
script in package.json
.
What works is when all the packages need are to be built. The flow goes:
yarn install
- Does the symlink/workspace magic.lerna publish --contents dist
- Does the monorepo magic. Lerna will see that all the packages have had modifications, and run the prepublishOnly
across all the packages. This way, what's in node_modules/@foo
will be "legit" NPM packages (the output of Angular CLI building the libraries)The problem is when a single library has a modification.
yarn install
- Does the symlink/workspace magic. All the things in node_modules/@foo
will be symlinks to libs/<package-name>
which, at this point, are source files. Not NPM packageslerna publish --contents dist
- Starts... and goes "Oh, only Package A has changed. So let me run against it." Lerna will fail due to the other packages inside node_modules
NOT being legit NPM packages.I need to figure out how to either:
I feel like I'm missing something simple somewhere.
If there are examples I can give to help explain, please ask.
Upvotes: 1
Views: 1044
Reputation: 843
in your root package.json (considering you've lerna as a dev dependency)
{
"scripts": {
"publish-ci": "lerna run build && lerna publish --content dist"
}
}
in your library1 packages
"scripts": {
"build": "yarn build library1"
}
now you can run yarn publish-ci
on your root folder and everything will be built and published.
you could also use lerna publish --from-package
flag to publish only changed package.
Here, you need lerna to only changed packages, not for publishing, a hacky way to get this is
in your root package.json
{
"scripts": {
"publish-ci": "node custom.publish.js"
}
}
in custom.publish.js
var { execSync } = require("child_process");
let packagesChangedString = execSync("yarn lerna changed --toposort --json --loglevel silent").toString();
let packageChanged = JSON.parse(packagesChangedString.substring(packagesChangedString.indexOf("["), packagesChangedString.lastIndexOf("]") + 1));
console.log(packageChanged);
packageChanged.forEach(changed => {
// exec npm publish manually without using lerna for publishing.
execSync("cd " + changed.location + " && npm publish" );
});
Upvotes: 3