Devoev
Devoev

Reputation: 574

Can't npm link multiple packages

I'm getting a weird error while linking local packages:

I have 2 packages (let's call them A and B). When I link either one of those to my project using npm link A it works as intended. But then I try to link the other one as well using npm link B and it gets linked, but the link of A is gone. I get no error message, just the following:

added 5 packages, removed 5 packages, changed 2 packages, and audited 121 packages in 5s

3 packages are looking for funding run npm fund for details

Previously this worked without any problem, but today I updated some dependencies with npm update. When I tried to relink my packages the problem occured.

Maybe it's worth mentioning that package B also links package A.

Edit: Solved it using npm link A B

Upvotes: 18

Views: 2418

Answers (2)

Martijn Scheffer
Martijn Scheffer

Reputation: 691

i have a similar problem, with a dozen modules, i ended up using mock-require

i made a little module that traverses the directory containing all my modules, and mocks all of them

this is the module, lets call it "@my-scope/mockModules"

const fs = require("fs-extra")
const path = require("path")
const mockRequire = require("mock-require")

// traverse directories,skipping "node_modules"
function traverseDir(directory, options, callback) {
  const files = fs.readdirSync(directory)
  
  for(const file of files) {
    const filepath = path.join(directory, file)
    const stat = fs.statSync(filepath)

    if (stat.isDirectory()) {
      if (options.exclude_folders === undefined || options.exclude_folders.indexOf(file) === -1) {
        traverseDir(filepath, options, callback)
      }
    } else {
      callback(file, filepath, directory)
    }
  }
}

// read all packages, to check if the module is in my scope
function getPackages(root) {
  const packages = []

  traverseDir(root, {
    exclude_folders: ["node_modules"]
  }, (name, path, directory) => {
    if(name === "package.json") {
      try {
        const content = require(path)

        packages.push({
          path,
          directory,
          content
        })
      } catch(error) {
        console.error(`could not open ${path}`)
      }
    }
  })

  return packages
}

// get an array of all packages, and paths for the modules in my scope, mock them using mock-require

function mockModules(rootFolder, scope) {
  let packages = getPackages(`${__dirname.split(rootFolder)[0]}${rootFolder}`)
  packages = packages.filter(pack => pack.content.name.indexOf(`${scope}/`) == 0)

  console.log("mocking")

  for(const pack of packages) {
    const path = `${pack.directory}/${pack.content.main}`
    console.log(`    ${pack.content.name} ${path}`)
    mockRequire(pack.content.name, path)
  }
}

module.exports = mockModules

and this is how to use it:

const mockModules = require("@my-scope/mockModules")
mockModules("my-scope", "name of root folder")

Upvotes: 0

Devoev
Devoev

Reputation: 574

Solved my issue using npm link A B.

Upvotes: 24

Related Questions