I'm trying to set up my monorepo with Lerna. The plan is to refactor an existing project by pulling chunks of code out which should be their own packages. I've run lerna init
, and my current setup looks like this:
project/ packages/ new-refactored-package/ package.json prior-existing-project/ package.json { "dependencies" : { "new-refactored-package" : "latest" } } package.json { "devDependencies": { "lerna": "^2.0.0-rc.5" } } lerna.json { "lerna": "2.0.0-rc.5", "packages": [ "packages/*" ], "version": "0.0.0" }
My understanding was that lerna bootstrap
at this point is supposed to locate package1
in the project and symlink it to prior-existing-project
's /node_modules/new-refactored-package/
. From lerna's readme:
Bootstrap the packages in the current Lerna repo. Installs all of their dependencies and links any cross-dependencies.
When run, this command will:
- npm install all external dependencies of each package.
- Symlink together all Lerna packages that are dependencies of each other.
- npm prepublish all bootstrapped packages.
However, when I run it, lerna attempts instead to npm install new-refactored-package
:
npm ERR! 404 Registry returned 404 for GET on https://registry.npmjs.org/new-refactored-package
Am I misunderstanding? Do I first have to publish the depended-upon packages to npm
?
What is Lerna? Lerna is a popular and widely used tool written in JavaScript for setting and managing multi-package repositories for Node.
Why Should Developers Use Lerna? Lerna makes things easier for developers by managing tasks like versioning, deployment of code, dependency management between projects, and much more. It is mostly used in bigger projects, where it becomes hard to maintain all these tasks manually over time.
Publishing a package is a two-step process. First, Lerna pushes all the changes to the remote repository and creates a Git tag. Then, it deploys the update to NPM. Lerna uses Git tags to mark releases and track changes.
For lerna
to symlink a local package when running lerna bootstrap
the local package must have a name
and version
that matches. Whenever lerna
cannot match a dependency to a local package, it'll try to install it from the registry.
So ensure that the dependency package has a version that can be matched by the semver version in the dependant.
{ name: "@my-name/dependency", version: "1.2.0" }
{ name: "@my-name/dependant", dependencies: { "@my-name/dependency": "<VERSION>" } }
@my-name/dependency
will be symlinked when VERSION
is 1.2.0
, ^1.0.0
, 1.X.X
, or *
. However when using ranges that does not match the local package, like 1.0.0
or ^0.0.0
, it will try to resolve it in the npm registry and will show the error like 404 Not Found - GET https://registry.npmjs.org/@my-name%2fdependency - Not found
.
latest
In the actual scenario that is explained in the question, the actual issue is that the version is specified as latest
and while it's easy to think that latest
is a generic term for the latest version available, it's actually a npm-dist-tag
which is applied by default to all new releases.
If you look at packages like react
(click versions), you can see that other than the latest
, they also deploy releases with tags next
, canary
and unstable
.
Your unpublished package does not have any tags, as they are applied on publication, and so latest
will not match, meaning lerna
will try to resolve it remotely, failing with 404
.
This is noted as one of the gotchas in the Notes of the documentation for the bootstrap
command.
- When a dependency version in a package is not satisfied by a package of the same name in the repo, it will be
npm install
ed (oryarn
ed) like normal.- Dist-tags, like
latest
, do not satisfy semver ranges.- Circular dependencies result in circular symlinks which may impact your editor/IDE.
If you want to match whatever version that is available, the recommended path would be to set the version to "*"
. This will match any version and will thus always use the local version, given that the local package has a specified version
field.
{ "dependencies": { "new-refactored-package" : "*" } }
alpha
,rc
orbeta
Even
*
will not match versions that are marked as pre-release, so if you give your local package a version like0.0.1-alpha.0
, or1.0.0-rc.3
, it will also not be locally symlinked
private: true
While it does not affect lerna bootstrap
, it's worth mentioning that packages that you do not want to be published should always have private: true;
. This will ensure that lerna publish
does not publish it.
lerna bootstrap
will symlink packages instead of install if they are available.
In your case, I think lerna cannot find the correct version
or name
of the package.
Here is what I did in my project ...
project - packages/ - a_pkg - package.json { "name": "@scope/a_pkg", "version": "0.0.1", "private": true /// opt out } - b_pkg - package.json { "name": "@scope/b_pkg", "version": "0.0.1", "private": true, "dependencies": { "@scope/a_pkg": "^0" }, /// opt out } - package.json - lerna.json { "packages": [ "packages/*" ], /// opt out }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With