Nextjs + Expo in Monorepo "Invalid Hooks Call"

Viewed 1014

I've created a monorepo with 4 packages like so:

.
├── lerna.json
├── package.json
├── packages
│   ├── admin-> Basic CRUD for backend with Nextjs
│   ├── mobile-> Expo app
│   ├── server-> GraphQL server
│   ├── shared -> Yup Schemas, GraphQL stuff
│   └── tsconfig.json
├── README.md
├── yarn-error.log
└── yarn.lock

8 directories, 6 files

I'm still working on getting everything configured, so I haven't done much yet besides a test graphql query, but I'm having trouble with my Expo and Nextjs app. This is the error output when I start it.

Unhandled Runtime Error
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

I know there might be trouble when two versions of React are in the same repo, but I don't know which package's version I should downgrade or upgrade for them to match properly.

This is the package.json for my mobile package, which is an Expo app.

{
  "name": "@bt/mobile",
  "main": "__generated__/AppEntry.js",
  "version": "1.0.0",
  "keywords": [
    "react",
    "expo",
    "template",
    "typescript",
    "nativebase"
  ],
  "license": "MIT",
  "scripts": {
    "start": "expo start",
    "dev": "expo start --clear",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "postinstall": "expo-yarn-workspaces postinstall"
  },
  "dependencies": {
    "@bt/shared": "^1.0.0",
    "@apollo/client": "^3.4.15",
    "expo": "~42.0.0",
    "expo-status-bar": "~1.0.4",
    "graphql": "^15.6.0",
    "native-base": "3.2.0",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz",
    "react-native-safe-area-context": "3.2.0",
    "react-native-svg": "12.1.1",
    "react-native-web": "~0.13.12",
    "styled-components": "^5.3.0",
    "styled-system": "^5.1.5"
  },
  "devDependencies": {
    "@babel/core": "^7.9.0",
    "@types/react": "~16.9.35",
    "@types/react-native": "~0.63.2",
    "expo-yarn-workspaces": "^1.5.2",
    "typescript": "~4.0.0"
  },
  "bugs": {
    "url": "https://github.com/GeekyAnts/nativebase-templates/issues"
  },
  "homepage": "https://github.com/GeekyAnts/nativebase-templates#readme",
  "author": "Aditya Jamuar",
  "private": true
}

And this is the package.json for my admin package, which is a Next app.

{
  "name": "@bt/admin",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@apollo/client": "^3.4.15",
    "@bt/shared": "1.0.0",
    "@chakra-ui/icons": "^1.0.5",
    "@chakra-ui/react": "^1.4.2",
    "@chakra-ui/theme-tools": "1.1.2",
    "@emotion/react": "11.1.5",
    "@emotion/styled": "11.1.5",
    "formik": "^2.2.9",
    "framer-motion": "^4.0.3",
    "graphql": "^15.6.0",
    "next": "latest",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "yup": "^0.32.9"
  },
  "devDependencies": {
    "@types/node": "^14.6.0",
    "@types/react": "^17.0.3",
    "@types/react-dom": "^17.0.3",
    "typescript": "4.3.2"
  }
}

I also tried using nohoist in the root's package.json.

{
  "name": "BT",
  "version": "1.0.0",
  "license": "MIT",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/**"
    ],
    "nohoist": [
      "**/react",
      "**/react/**"
    ]
  },
  "devDependencies": {
    "lerna": "^4.0.0"
  },
  "scripts": {
    "dev": "lerna run dev",
    "build": "lerna run build",
    "build:shared": "lerna run build --scope=@bt/shared",
    "bootstrap:": "lerna run yarn",
    "clean": "lerna run clean"
  }
}

This is the output for yarn why react

yarn why v1.22.10
[1/4] Why do we have the module "react"...?
[2/4] Initialising dependency graph...
[3/4] Finding dependency...
[4/4] Calculating file sizes...
=> Found "@bt/mobile#react@16.13.1"
info Reasons this module exists
   - "_project_#@bt#mobile" depends on it
   - in the nohoist list ["/_project_/**/react","/_project_/**/react/**"]
info Disk size without dependencies: "244KB"
info Disk size with unique dependencies: "244KB"
info Disk size with transitive dependencies: "244KB"
info Number of shared dependencies: 5
=> Found "@bt/admin#react@17.0.2"
info Reasons this module exists
   - "_project_#@bt#admin" depends on it
   - in the nohoist list ["/_project_/**/react","/_project_/**/react/**"]
info Disk size without dependencies: "356KB"
info Disk size with unique dependencies: "356KB"
info Disk size with transitive dependencies: "356KB"
info Number of shared dependencies: 3
Done in 5.54s.

Here's a repository for reproducing this error: https://github.com/Je12emy/monorepo-error

1 Answers

Maybe it's too late, but It can help someone else :)

I issue the same problem when I start playing with monorepo.

In your root package.json, nohoist should be [**].

Without that, you'll have collisions conflicts between expo and nextjs. (and more trouble if your shared packages have common dependencies with your apps package.json).

I choose a different folder structure (/apps, /packages), but I have a working example in github ;)

In this demo you will find some customizations on metro.config.json and webpack.

Related