reactjsviteyarnpkgrolluppnpm

pnpm monorepo error with peer dependencies "Rollup failed to resolve import"


I have a monorepo project using turborepo. I was using yarn version 4 and everything was working perfectly fine but then I had the brilliant idea of changing from yarn to pnpm since it was recommended for monorepo (at least from what I've read).

I deleted all yarn references and changed it to pnpm, ran pnpm import, deleted node_modules, and ran pnpm install.

When I try to build one project that uses react and vite, I always get "Rollup failed to resolve import".

For example, I have zustand and then it says it failed to resolve import use-sync-external-store/shim/with-selector.js. tanstack/react-query asked for @tanstack/query-core and @tanstack/query-persist-client-core.

I tried adding them to the external rollup property in the vite.config file, but I have added 59 different packages so far. Whenever I run, it says it's missing a peer dependency, I add this dependency in the external, run build again, and it complains about another dependency, I add it to external, build again, and then I keep in this dependency hell. I don't know how to fix it. I have this in my .pnpm

link-workspace-packages=true

and this in my pnpm-workspace.yaml

packages:
  - 'apps/*'
  - 'shared/*'

This is my complete vite.config.mts file

export default defineConfig(({ mode }) => ({
  plugins: [
    react(),
    svgr(),
  ],
  resolve: {
    preserveSymlinks: true,
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  build: {
    rollupOptions: {
      external: [
        'clsx',
        'use-sync-external-store/with-selector.js',
        '@floating-ui/react-dom-interactions',
        'htm/react',
        '@tanstack/query-core',
        '@tanstack/query-persist-client-core',
        'react-router',
        '@remix-run/router',
        'immer',
        '@babel/runtime/helpers/esm/classCallCheck',
        '@babel/runtime/helpers/esm/createClass',
        '@babel/runtime/helpers/esm/objectWithoutPropertiesLoose',
        'reselect',
        'redux-thunk',
        'react-merge-refs',
        '@tanstack/query-devtools',
        'html-parse-stringify',
        '@progress/kendo-charts',
        '@babel/runtime/helpers/esm/extends',
        '@babel/runtime/helpers/esm/inheritsLoose',
        '@babel/runtime/helpers/esm/toConsumableArray',
        '@babel/runtime/helpers/esm/assertThisInitialized',
        'dom-helpers/addClass',
        'dom-helpers/removeClass',
        '@babel/runtime/helpers/esm/inherits',
        '@babel/runtime/helpers/esm/possibleConstructorReturn',
        '@babel/runtime/helpers/esm/getPrototypeOf',
        '@babel/runtime/helpers/esm/defineProperty',
        'invariant',
        '@babel/runtime/helpers/esm/slicedToArray',
        'substyle',
        '@progress/kendo-draggable-common',
        'pdfjs-dist',
        'make-event-props',
        'make-cancellable-promise',
        'tiny-invariant',
        'warning',
        'dequal',
        'merge-refs',
        'use-sync-external-store/shim/with-selector.js',
        'tslib',
        '@progress/pako-esm',
        'js-cookie',
        'nano-css',
        'nano-css/addon/cssom',
        'nano-css/addon/vcssom',
        'nano-css/addon/vcssom/cssToTree',
        'copy-to-clipboard',
        'screenfull',
        'set-harmonic-interval',
        'throttle-debounce',
        'react-universal-interface',
        'fast-shallow-equal',
        'ts-easing',
        '@xobotyi/scrollbar-width',
        'fast-deep-equal/react',
        '@kurkle/color',
        '@zxing/library',
        '@progress/jszip-esm',
      ],
    },
  },
  esbuild: {
    drop: ['console', 'debugger'],
  },
  define: {
    APP_VERSION: JSON.stringify(process.env.npm_package_version),
  },
}));

Taking zustand as an example it is only installed in the app/app1 folder (I'm using app1 for anonymity) This is my root package.json

{
  "name": "monorepo",
  "private": true,
  "scripts": {
    "build": "pnpm install && turbo build",
    // removed for simplicity
  },
  "devDependencies": {
    "husky": "^9.0.11",
    "prettier": "^3.3.1",
    "turbo": "^2.0.11",
    "typescript": "^5.5.2"
  },
  "packageManager": "pnpm@9.7.1",
  "engines": {
    "node": ">=20"
  }
}

and this is my app1 package.json (I kept only some relevant packages that I think makes sense)

{
  "name": "app1",
  "private": true,
  "dependencies": {
    "@tanstack/react-query": "^5.40.1",
    "@tanstack/react-query-devtools": "^5.40.1",
    "@tanstack/react-query-persist-client": "^5.49.2",
    "idb-keyval": "^6.2.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-router-dom": "^6.23.1",
    "zustand": "^4.5.4"
  },
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build --outDir build",
    "preview": "vite preview --outDir build --port=3000",
    "test": "vitest"
  },
  "devDependencies": {
    "@types/node": "^20.14.7",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@types/react-router-dom": "^5.3.3",
    "typescript": "^5.5.2",
    "vite": "^5.4.1",
    "vitest": "^1.6.0",
    "webpack": "^5.90.3"
  },
  "jest": {
    "moduleNameMapper": {
      "axios": "axios/dist/node/axios.cjs"
    }
  },
  "overrides": {
    "redux-persist": {
      "redux": "^5.0.0"
    },
    "redux-state-sync": {
      "redux": "^5.0.0"
    }
  }
}


Solution

  • Adding this to the .npmrc solved my problem:

    shamefully-hoist=true
    

    I think it is because I must use preserveSymlinks: true due to the Jenkins environment we use to build.

    I found it because in the documentation it says the node-linker should be set to hoisted when:

    If you are running Node.js with the --preserve-symlinks flag.
    node-linker