Nextjs + Expo in Monorepo "Invalid Hooks Call" - reactjs

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

I had some issues with this, I had a project with Next 13.1 and another project with Expo 47, and it was only solved through unifying their React and React DOM versions (It was 18.2 in one, and 18.1.0 on another).

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

Styled-jsx typescript error after migrating to monorepo structure. Property 'jsx' does not exist on type 'DetailedHTMLProps'

I am using styled-jsx in my project and I just migrated it to a monorepo structure, and since then I have been having the following problem:
Type '{ children: string; jsx: true; }' is not assignable to type
'DetailedHTMLProps<StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>'.
Property 'jsx' does not exist on type
'DetailedHTMLProps<StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>'.ts(2322)
This appears under the jsx attribute every time I use the default tag for style-jsx:
<style jsx>
{`...`}
</style>
I found a closed issue about this subject, and according to this link, this issue can be solved if I manually add the following two lines to interface HTMLAttributes in react/index.d.ts:
jsx?: boolean;
global?: boolean;
This actually solved the problem, but I don't want to manually modify a file from node_modules.
According to this closed issue in vercel, I should be able to fix this by simply running yarn add -D #types/styled-jsx, but this didn't work.
Installing the packages using using npm instead of yarn fixed the problem too, but I don't want to change the package manager I am using. Furthermore, installing this one package with npm and the others with yarn crashed the application.
I thought this could be a hoisting problem related to styled-jsx and yarn workspaces, but adding
"private": true,
"nohoist":["**/styled-jsx","**/styled-jsx/**"]
to my root package.json and to the package.json of the project that uses styled-jsx didn't fix the problem either.
Does any one have a solution to this problem that does not involve manually modifying react/index.d.ts, changing my package manager or abandoning the monorepo structure?
The package.json of the project that uses styled-jsx:
{
"name": "with-typescript",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"type-check": "tsc",
"lint": "eslint **/**",
"lint:fix": "eslint **/** --fix",
"test": "NODE_ENV=test jest --passWithNoTests --watch",
"test:ci": "NODE_ENV=test jest --passWithNoTests"
},
"dependencies": {
"#fortawesome/fontawesome-svg-core": "^1.2.34",
"#fortawesome/free-solid-svg-icons": "^5.15.2",
"#fortawesome/react-fontawesome": "^0.1.14",
"#types/styled-jsx": "^2.2.8",
"axios": "^0.21.1",
"dotenv": "^8.2.0",
"firebase": "^8.2.4",
"firebase-admin": "^9.4.2",
"formidable": "^1.2.2",
"global": "^4.4.0",
"isomorphic-unfetch": "3.0.0",
"jest": "^25.2.1",
"js-cookie": "^2.2.1",
"next": "^10.0.5",
"path": "^0.12.7",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-router-dom": "^5.2.0",
"styled-components": "^5.2.1",
"styled-jsx": "^3.4.1"
},
"devDependencies": {
"#types/formidable": "^1.0.32",
"#types/js-cookie": "^2.2.6",
"#types/node": "^12.12.21",
"#types/react": "^16.9.16",
"#types/react-dom": "^16.9.4",
"#types/react-router-dom": "^5.1.7",
"#types/styled-components": "^5.1.7",
"#types/styled-jsx": "^2.2.8",
"#typescript-eslint/eslint-plugin": "^4.14.0",
"#typescript-eslint/parser": "^4.14.0",
"eslint": "^7.18.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-import-resolver-typescript": "^2.3.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"prettier": "^1.18.2",
"typescript": "3.7.3"
},
"license": "ISC"
}
The package.json of my root folder:
{
"name": "next_shsc",
"version": "1.0.0",
"main": "index.js",
"private":true,
"repository": "https://github.com/agaragon/next_shsc.git",
"author": "aragon <andregaragon#gmail.com>",
"license": "MIT",
"workspaces":{
"packages": [
"packages/*"
]
}
}
This solution fixed the issue for me (after #smeijer at GitHub):
Create a TypeScript Declaration File, named e.g. custom.d.ts:
import 'react';
declare module 'react' {
interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
jsx?: boolean;
global?: boolean;
}
}
Place it somewhere in the project, for example in the /src/typings folder. It should be picked up by the compiler automatically, but it may possibly depend on the config (?).
If you get eslint error complaining about the import 'react' line, put the following comment above it:
// eslint-disable-next-line react/no-typos`
Installing the #types/styled-jsx package didn't work for me - it's a stub for the types, as styled-jsx includes their own now.
Reading the docs on the styled-jsx github, there's a specific solution for this: https://github.com/vercel/styled-jsx#typescript
Adding a file at the root of my next app named styled-jsx.d.ts and putting this in it worked for me:
/// <reference types="styled-jsx" />
I am using Next 12.1.6 and I had this problem until I installed #types/styled-jsx 3.4.4.
I think it is a better approach.
Using pnpm 7 in a monorepo and Next 12.2.0 I had to install styled-jsx in my app with pnpm add styled-jsx

Parcel + Babel not transpiling ES6 from node_modules?

I can't seem to get Babel to work with Parcel, although the presets are being installed automatically. It works locally and in Chrome, but it's not transpiling node_modules es6 files, so the output still has const/let/... and it cannot run in Safari.
.babelrc
{
"presets": ["#babel/preset-env","#babel/preset-react"]
}
(I've also tried the env and react ones).
package.json scripts
"scripts": {
"start": "parcel index.html",
"build": "parcel build index.html",
Why would this be?
Full package.json (note this is after messing around in order to try to get it working)
{
"name": "my-react-app",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"start": "parcel index.html",
"build": "parcel build index.html"
},
"author": "",
"license": "ISC",
"dependencies": {
"#babel/core": "^7.1.5",
"#babel/preset-env": "^7.1.5",
"#babel/preset-react": "^7.0.0",
"axios": "^0.18.0",
"babel-polyfill": "^6.26.0",
"browserslist": "^4.3.4",
"lodash": "^4.17.11",
"node-sass": "^4.10.0",
"pinyin": "^2.8.3",
"prop-types": "^15.6.2",
"react": "^16.6.1",
"react-dom": "^16.6.1",
"react-notifications": "^1.4.3",
"react-router-dom": "^4.3.1"
},
"devDependencies": {
"cssnano": "^4.1.7",
"sass": "^1.14.3"
}
}
Still getting .js files with const, let. Any ideas what I am missing?
I've found a solution to it from https://github.com/parcel-bundler/parcel/issues/1655#issuecomment-425593377
// .browserslistrc.packages
node 10.11
// package.json
{
"scripts": {
"postinstall": "npm-run-all -p \"postinstall:*\"",
"postinstall:p-retry": "cpy --rename=.browserslistrc .browserslistrc.packages node_modules/p-retry",
"postinstall:query-string": "cpy --rename=.browserslistrc .browserslistrc.packages node_modules/query-string"
}
}
Add a postinstall:package-name for every npm package that you need to add transpilation (in my case, pinyin) and run npm run postinstall after every npm install. Babel should now also transpile that npm package!

Babel version error when react-native bundle

When i try to run:
react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
I receive this error:
Requires Babel "^7.0.0-0", but was loaded with "6.26.3". If you are sure you have a compatible version of #babel/core, it is likely that something in your build process is loading the wrong version. Inspect the stack trace of this error to look for the first entry that doesn't mention "#babel/core" or "babel-core" to see what is calling Babel. (While processing preset: "C:\\..\\AppDirectory\\node_modules\\#babel\\preset-env\\lib\\index.js")
I've tried removing node-modules directory, cleaning cache, npm install, etc, etc, etc. I've also tried installing Babel manually but the same issue persists.
I had the same error before when generating the .apk, but could solve it installing babel dependencies, now this doesn't work neither.
This is my package.json
{
"name": "Appname",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-test-renderer": "16.3.1",
"babel-preset-react-native-stage-0": "^1.0.1"
},
"scripts": {
"start": "react-native start",
"android": "react-native run-android",
"ios": "react-native run-ios",
"test": "jest"
},
"dependencies": {
"#babel/core": "^7.0.0-beta.54",
"#babel/preset-env": "^7.0.0-beta.54",
"#babel/preset-react": "^7.0.0-beta.54",
"babel-core": "^6.26.3",
"babel-preset-react-native": "^2.1.0",
"babel-upgrade": "0.0.20",
"react": "16.3.1",
"react-native": "^0.55",
"react-native-circle-checkbox": "^0.1.6",
"react-native-modal": "^6.4.0",
"react-native-phone-call": "^1.0.7",
"react-navigation": "^2.6.2",
"react-redux": "^5.0.7",
"react-router-native": "^4.3.0",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0"
}
}
And this is my .babelrc file:
{
"presets": ["#babel/react"],
"env": {
"development": {
"plugins": [
"transform-react-jsx-source"
]
}
}
}

Size of bundled ReactJS app

I am trying to reduce the size of my reactjs application bundle.js file. For a relatively simple app i have its browserified js file size - 452Kb.
To build it, i use NPM with respective package.json file:
{
"name": "MyApp-React",
"version": "0.0.1",
"description": "My App Description",
"main": "app.js",
"scripts": {
"watch": "watchify app.js -o public/js/bundle.js -v",
"browserify": "browserify app.js | uglifyjs > public/js/bundle.js",
"build": "npm run browserify",
"start": "npm install"
},
"author": "",
"dependencies": {
"axios": "^0.14.0",
"body-parser": "^1.15.2",
"clipboard": "^1.5.12",
"express": "~4.9.7",
"express-handlebars": "~1.1.0",
"express-session": "^1.14.1",
"highlight.js": "^9.7.0",
"node-jsx": "~0.12.4",
"react": "~15.3.1",
"react-dom": "^15.3.1",
"react-maskedinput": "^3.2.4",
"react-modal": "^1.4.0",
"react-router": "^2.8.1"
},
"devDependencies": {
"browserify": "~6.0.3",
"nodemon": "^1.2.1",
"reactify": "~1.1.1",
"uglify-js": "~2.4.15",
"watchify": "^3.1.1"
},
"browserify": {
"debug": false,
"transform": [
"reactify"
]
}
}
Not being an expert in Node JS/ ReactJS development i hope i do somethin wrong, but i cant find what.
For the time being i tried few things: app.js file has a line of code setting NODE_ENV variable to 'production'
process.env.NODE_ENV = 'production';
A second thing i have tried is to use npm prune command with --production parameter. Having this run, i see it removes a lot from node_modules folder, but then npm run build is failing to run as it misses devDependencies. What can i do?
One thing that you could do to lighten the download burden for your users is get react and react-dom from a CDN instead of putting them in your bundle.
Move them from the dependencies section of your package.json to a new section peerDependencies (see npm docs).
Then add tags to your HTML code for loading React and ReactDOM like so:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js"></script>
→ See React on cdnjs.com
Then you need to change your Browserify config to recognize react and react-dom as external modules.
→ See related question on StackOverflow

Why npm tries to find package.json in the wrong directory?

I'm having a web app with TypeScript, Angular and several dependencies.
npm of course is here also.
package.json was introduced to the project from the begging by npm init and right now it looks like that:
{
"name": "myApp",
"version": "0.0.8-d",
"description": "Web App",
"author": "Author",
"license": "ISC",
"repository": {
"type": "git",
"url": "MYURL"
},
"bugs": {
"url": "MYURL"
},
"homepage": "MYURL",
"browserify": {
"transform": [
"debowerify"
]
},
"dependencies": {
"malihu-custom-scrollbar-plugin": "^3.1.3"
},
"devDependencies": {
"browserify": "~13.0.0",
"connect-history-api-fallback": "^1.2.0",
"connect-modrewrite": "^0.8.2",
"debowerify": "~1.2.0",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"gulp-clean-css": "^2.0.4",
"gulp-concat": "^2.6.0",
"gulp-connect": "^3.2.2",
"gulp-less": "^3.0.5",
"gulp-ng-annotate": "^2.0.0",
"gulp-sass": "^2.2.0",
"gulp-sourcemaps": "^1.6.0",
"gulp-typescript": "^2.12.2",
"gulp-uglify": "^1.5.3",
"jasmine": "^2.4.1",
"run-sequence": "^1.1.5",
"typescript": "^1.8.9",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}
Also my file structure is like this:
Root
|-- tscode
|-- compiled
|-- html_files
|-- node_modules
|-- libs
| package.json
This think is that npm seems to work fine, everything is installed correctly I can add/remove dependencies BUT always I'm getting this working:
npm WARN enoent ENOENT: no such file or directory, open '/Projects/MyApp/tscode/package.json'
package.json is on the root folder as it should but still I'm getting this warning which is very annoying. As you can see npm searching for the json file in a folder one level inside instead on the root.
Also if I do:
npm list --depth=0
Then I'm getting a correct list of my dependencies BUT also: -> /Projects/MyApp/innerfolder extraneous error: ENOENT: no such file or directory, open '/Projects/MyApp/tscode/package.json
Any ideas?
Node version: v5.10.1
npm version: 3.8.5
Note: This is happening to everyone in my team regardless OS.
UPDATE: It seems that there is a bug with npm. There are some open issues at npm repository such as:
https://github.com/npm/npm/issues/9633
https://github.com/npm/npm/issues/10004
If something change I'll update the question with an answer (if provided)
Try this :
Delete node_modules folder
Then run :
$ npm cache clean
$ npm install

Resources