Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I `npm link` a typescript dependency with peer dependencies?

I have a React/Redux typescript project A. My team decided to split out some of the React components and Redux code into an NPM module, so I created another React/Redux TS project B.

Initially, when I tried to install B from A, I got errors due to type redeclarations, since both A and B depend on the same type declarations files (react, redux, etc). So I moved all of B's @types dependencies to be peer dependencies. This allows me to properly install B from A.

However, for development purposes, I would like to npm link to B from A, so I don't constantly have to recompile and reinstall B. But because npm link creates a symlink, it points to the entire B project, including the type definitions that I need to avoid.

Does anyone know how to solve this conundrum?

like image 460
gardenhead Avatar asked May 08 '17 16:05

gardenhead


People also ask

Will npm install peer dependencies?

Unmet Dependencies When Testing When you use peer dependencies, npm will not automatically install those dependencies (see comments above in respect to npm version 7).

Should TypeScript be a peer dependency?

It is not possible to use peer dependencies in TypeScript. WebStorm does not recognize them and marks import statement as invalid. package. json is completely valid and the code can be built by any bundler.

What is npm link TypeScript?

Npm link is a command that allows you to link a specific npm project to another. That's about it! It's mainly used to be able to test a library onto a project without having to publish the library into npm.


1 Answers

This problem isn't particularly related to typescript, but is a general problem of how to link two javascript packages together and prevent libraries from loading multiple times. A big factor on how you solve this is based on what build/bundler you use. I think this stackoverflow answer is pretty good if you only care about de-duping react.

Here is an example of solving it using webpack.

The first thing is make sure any shared dependencies in your child package are devDependencies and peerDependencies and your parent package is setting them as the needed dependencies and devDependencies.

A - package.json

{
  "dependencies": {
    "B": "1.0.0",
    "react": "x.x.x",
  },
  "devDependencies": {
    "@types/react": "x.x.x"
  }
}

B - package.json

{
  "version": "1.0.0",
  "peerDependencies": {
    "@types/react": "x.x.x",
    "react": "x.x.x"
  },
  "devDependencies": {
    "@types/react": "x.x.x",
    "react": "x.x.x"
  }
}

If you are running webpack from package A, you need to make sure to resolve node_modules when applicable only from package A's node_modules.

const path = require('path')
module.exports = {
  // rest of your webpack condig...
  resolve: {
    modules: [path.resolve(__dirname, 'node_modules'), 'node_modules']
  }
}

Here is also another solution using react-app-rewired that does the same thing

const path = require('path')
module.exports = function override(config) {
  config.resolve = Object.assign({}, config.resolve, {
    modules: [path.resolve(__dirname, 'node_modules'), ...config.resolve.modules]
  })

  return config
}
like image 159
jjbskir Avatar answered Sep 19 '22 17:09

jjbskir