reactjsnpmnpm-workspaces

NPM 7 Workspaces installing multiple versions of react


We have a mono-repo that I'm migrating to npm 7's workspaces.

Current folder org:

\React
  - package.json (defines workspaces for \apps and \packages)
  \apps
    \someApp
      - React 17.0.1 (Dependency)
    \otherApp
  \packages
    \component-library
      - React 16.14.0 || 17.0.0 (Peer)
      - Storybook (6.1)
      - Storybook MUI Add On
    \framework
      - React 16.14.0 || 17.0.0 (Peer)

Running npm ci in the React folder installs React 16.14 in the \React\node_modules and 17.0.0 in \React\apps\someApp\node_modules. When trying to run the app we get the expected hook error due to multiple versions being installed. But I can't find anything that is explicitly requiring React 16.14?


Solution

  • The specific issue in the question looks like it may have been one of the many arborist bugs in early(ish) versions of NPM 7 - in NPM 8 and beyond, it should see that React 17 is supported by everything, and should therefore choose that.


    For anyone with similar issues with more recent versions of NPM - in NPM >=8.3.0 you can use overrides to force a particular version.

    Important notes:

    1. overrides may only be set in the repo's root package.json, not individual workspace package.json files.
    2. You might need to flush node_modules and package-lock.json after adding overrides (hopefully fixed soon by the fix to this issue)
    3. It's your responsibility to ensure that the overrides you apply don't break things: many packages with a "react": "^16.x.x" dependency are in reality compatible with React 17 and just haven't been updated, but not all; some may be legitimately not compatible with React 17. Be careful and look for issues on the repos of the packages whose "^16.x.x" dependencies you are overriding. There may even be a new version or alternative you can apply that does directly support React 17.
    4. You may also need to override react-dom as well as react to ensure the two can't get out of sync.

    Something like this should work in a root package.json:

      "overrides": {
        "react": "^17.0.1",
        "react-dom": "^17.0.1",
      }