Lerna bootstrap does not link local dependencies?

matsev picture matsev · Nov 18, 2019 · Viewed 9.5k times · Source

What is the proper way of working with lerna and local dependencies?


I have configured two modules in a mono repo to use lerna with a local dependency. I expected that

$ lerna bootstrap
$ lerna run test

would be sufficient to download all external dependencies, link a local dependency and execute and pass all tests in all modules.

Expected Behavior

As per the lerna bootstrap documentation:

  1. Symlink together all Lerna packages that are dependencies of each other.

Thus, I expected that lerna bootstrap would create a symlink in module-b/node_modules below that points to module-a (which then would allow the tests to be executed and pass).

Current Behavior

No linking occurs, which cause the tests to fail:

lerna ERR! yarn run test exited 1 in 'module-b' lerna ERR! yarn run test stdout: yarn run v1.19.1 $ jest info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

lerna ERR! yarn run test stderr: FAIL ./import.test.js ● Test suite failed to run

Cannot find module 'module-a' from 'import.test.js'

> 1 | const moduleA = require('module-a');
    | ^
  2 | 
  3 | test('should import module-a', () => {
  4 |   moduleA();

  at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:259:17)
  at Object.<anonymous> (import.test.js:1:1)

Steps to Reproduce

  1. Create the folder structure below
  2. Copy the files inlined to their corresponding directory
  3. Execute $ lerna bootstrap followed by $ lerna run test
project-root
   + packages
   |       + module-a
   |       |      + package.json
   |       |      + index.js
   |       |
   |       + module-b
   |       |      + package.json
   |       |      + import.test.js
   |
   +  lerna.json     

packages/module-a/package.json

{
  "name": "module-a",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "scripts": {
    "test": "echo \"Test passed in module-a\""
  }
}

packages/module-a/index.js

module.exports = () => console.log('Log in module-a');

packages/module-b/package.json

{
  "name": "module-b",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "dependencies": {
    "module-a": "file:../module-a"
  },
  "devDependencies": {
    "jest": "^24.9.0"
  }
}

packages/module-b/import.test.js

const moduleA = require('module-a');

test('should import module-a', () => {
  moduleA();
});

lerna.json

{
  "npmClient": "yarn",
  "packages": [
    "packages/*"
  ],
  "version": "independent"
}

Observation

Executing lerna link --force-local does not change status quo, the test still fails because the module-b/node_modules/ still does not contain a reference to module-a.

Remark

I cannot use yarn workspaces together with lerna because module-b is an Electron app and the electron builder expects its dependencies to be installed in the packages/module-b/node_modules/ folder.

Environment

  • lerna --version 3.18.4
  • npm --version 6.11.3
  • yarn --version 1.19.1
  • node --version v12.12.0
  • macOS Mojave 10.14.6

Answer

kitimenpolku picture kitimenpolku · Dec 30, 2019

I have tried your implementation.

Using file:../module-a in packages/module-b/package.json does not work for me.

You can go around it easily by using writing a version number for module-a (it does not matter which since we will force-local)

{
  "name": "module-b",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "dependencies": {
    "module-a": "1.0.0"
  },
  "devDependencies": {
    "jest": "^24.9.0"
  }
}

At the root of your project:

Bootstrap and link for local version:

npx lerna bootstrap --force-local

Run tests:

npx lerna run test