39

I have a lerna repo for a project under development. It has several packages that depend on each other. To make development easier, none of the packages are published and they depend on the latest version of each other.

Directory tree

foo/
  packages/
    core/
      package.json
    errors/
      package.json

foo/packages/core/package.json

{
  ...
  dependencies: {
    "@foo/errors": "*"
  }
}

I have another project, bar, that I'm using to test the lerna project. Currently I'm linking to its dependencies using a local file: dependency:

bar/package.json

{
  ...
  dependencies: {
    "@foo/core": "../foo/packages/core"
  }
}

This approach has given me a world of trouble.

  • Using npm, I'm constantly hit with ENOENT .DELETE errors. Removing my package-lock.json and reinstalling has taken years off my life.
  • Using yarn, I've been unable to yarn install in bar. Yarn follows the file: dependency to @foo/core, sees that it depends on @foo/errors and doesn't know about lerna's symlink. This causes it to fail, telling me it can't find @foo/errors.

This has made writing actual code for this project secondary to this mess of dependency management.

How can I make this (I feel fairly simple?) project structure work? Open to lerna/yarn/npm/pnpm/shell scripts/MS DOS at this point.

tk421
  • 5,775
  • 6
  • 23
  • 34
Jack Guy
  • 8,346
  • 8
  • 55
  • 86

4 Answers4

8

You should be able to accomplish this with npm link. Although I have not tried this using a local dependency that is not published on npm.

Directory tree

foo/
  packages/
    core/
      package.json
    errors/
      package.json
bar/
    package.json

foo/packages/core/package.json

{
  ...
  dependencies: {
    "@foo/errors": "*"
  }
}

bar/package.json

{
  ...
  dependencies: {
    "@foo/core": "../foo/packages/core"
  }
}

Run the following commands

cd foo
npx lerna clean
npx lerna bootstrap --hoist
npm run build # command to build your projects
cd packages/core
npm link
cd ../../../bar
npm i
npm link @foo/core

Removing package-lock.json files usually does more harm then good! And about not being able to find @foo/errors, if you ran npm bootstrap, @foo/core should be symlinked to @foo/errors. One possibility could be that your lerna scripts are using npm while you where running install/link with yarn.

jjbskir
  • 8,474
  • 9
  • 40
  • 53
7

Can you move your lerna up to a directory which hold both 'foo' and 'bar'? Is that possible?

root/
  foo/
    packages/
      core/
        package.json
      errors/
        package.json
  bar/
    package.json
  lerna.json

And in your lerna file, you can add your repos to packages

{
  "lerna": "2.9.0",
  "packages": [
     "foo/packages/*",
     "bar/",
  ],
}
Doppio
  • 2,018
  • 12
  • 11
  • 2
    While I've used this option in the past, it's not ideal because I'd like to manage the git repos separately and publish `/foo` to npm eventually. – Jack Guy Mar 21 '18 at 17:56
  • 6
    Awarding bounty because this is the closest to a viable solution I've seen, but not marking as an answer in hopes of something a little better. :) – Jack Guy Mar 22 '18 at 20:05
  • 1
    @JackGuy Did you find a way to do this? I'm in the exact pickle as you. – Michael Wolthers Dec 01 '18 at 20:39
  • 1
    @MichaelWolthers I stuck with Yarn and primarily relied on `yarn link` to put packages in the non-lerna project. Kind of a pain, but the only robust solution I found. Things get a lot easier after an initial version release to npm. – Jack Guy Dec 02 '18 at 01:42
  • 1
    ```yarn lerna exec yarn link``` - is pretty handy if you need to create links in one go – Jaberino Jun 04 '20 at 16:35
  • To add to @Jaberino answer, you then need to run `yarn link ` (`npm link ` won't work). You need to do this package per package. – Eric Burel Sep 11 '20 at 07:50
1

Under slightly different conditions where one of the npm modules you are working is not part of your lerna repo, you can use lerna to exec the npm link command.

npx lerna exec -- npm link <npm_package_name>

This will npm link the external package in all of your lerna modules.

This should not be confused with lerna link which will do something similar for all submodules in your your lerna repo and is the current solution to the question.

ThisCompSciGuy
  • 176
  • 2
  • 11
0

Use can try like that:

foo/packages/core/package.json

{
   ...
  dependencies: {
    "@foo/errors": "file:../errors"
   }
}

bar/package.json

{
  ...
  dependencies: {
    "@foo/core": "file:../foo/packages/core"
  }
}
Rosco Kalis
  • 567
  • 3
  • 13
Suhosauge
  • 44
  • 2
  • This doesn't match the directory structure I specified in the question and also wouldn't work with lerna. :( – Jack Guy Mar 13 '18 at 22:32
  • Hi: you can try to change abtribute "name":"@foo/core" of core/package.json , and "name": "@foo/errors" of errors/package.json, Good luck! – Suhosauge Mar 15 '18 at 04:58
  • { "name": "bar", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@foo/core": "file:../foo/packages/core", "@foo/errors": "file:../foo/packages/errors" } } ,{ "name": "@foo/core", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@foo/errors": "file:../errors" } } ,{ "name": "@foo/errors", "version": "1.0.0", "main": "index.js", "license": "MIT" } – Suhosauge Mar 15 '18 at 04:59
  • But what happens when you publish your project? Using a local folder as a dependency won't work? In a normal workflow you probably want to temporarily override the package path, like `npm link` would do usually. So the dependency "foobar@0.0.1" is fetched from NPM as usual, OR from your local development version using npm link. I can't find a similar pattern with Lerna. – Eric Burel Sep 11 '20 at 07:48