SoftwareBrothers / adminjs

AdminJS is an admin panel for apps written in node.js
https://adminjs.co
MIT License
8.25k stars 665 forks source link

Error on the login page using the latest version of admin-bro #669

Closed LahmerIlyas closed 2 years ago

LahmerIlyas commented 4 years ago

Describe the bug I'm having an issue when trying to load the login page. On the server side I'm getting this error: `node:9956) UnhandledPromiseRejectionWarning: 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://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem. at resolveDispatcher (/home/tim/WebstormProjects/selkni/node_modules/admin-bro/node_modules/react/cjs/react.development.js:1465:13) at Object.useState (/home/tim/WebstormProjects/selkni/node_modules/admin-bro/node_modules/react/cjs/react.development.js:1496:20) at ae (/home/tim/WebstormProjects/selkni/node_modules/admin-bro/node_modules/styled-components/dist/styled-components.cjs.js:1:13232) at processChild (/home/tim/WebstormProjects/selkni/node_modules/react-dom/cjs/react-dom-server.node.development.js:3043:14) at resolve (/home/tim/WebstormProjects/selkni/node_modules/react-dom/cjs/react-dom-server.node.development.js:2960:5) at ReactDOMServerRenderer.render (/home/tim/WebstormProjects/selkni/node_modules/react-dom/cjs/react-dom-server.node.development.js:3435:22) at ReactDOMServerRenderer.read (/home/tim/WebstormProjects/selkni/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29) at renderToString (/home/tim/WebstormProjects/selkni/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27) at html (/home/tim/WebstormProjects/selkni/node_modules/admin-bro/lib/frontend/login-template.js:71:53) at processTicksAndRejections (internal/process/task_queues.js:93:5) (Use node --trace-warnings ... to show where the warning was created) (node:9956) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) `

Installed libraries and their versions

"@admin-bro/design-system": "^1.7.0",
"@admin-bro/express": "^3.0.1",
"@admin-bro/typeorm": "^1.3.0",
"@admin-bro/upload": "^1.0.0",
"react-dom": "=16.13.1",
"admin-bro": "^3.3.1",
wojtek-krysiak commented 4 years ago

can you remove node_modules and install everything again?

LahmerIlyas commented 4 years ago

I solved the issue by adding react as a dependency.

flodev commented 3 years ago

@LahmerIlyas and everyone who has that error: for me it was the opposite. I had the invalid hook call because different versions of react seemed to be present as described in react hook issue guide. So I had to remove my react version and it works without. I'm running admin-bro, nestjs, postgres setup.

flodev commented 3 years ago

@wojtek-krysiak hi, here in the docs https://adminbro.com/tutorial-writing-react-components.html you list lots of dependencies. Is it possible that the docs are out of date and everything works with your internal dependencies?

SimonB407 commented 3 years ago

@flodev It's possible that something in tutorials is not 100% correct. We tried to update everything together with adding features, but we probably missed some things.

mathildegrimal commented 3 years ago

Hello, I have the same issue, did you find the solution ?

nathanguigui commented 2 years ago

still facing the same issue

dziraf commented 2 years ago

This error typically appears if there is more than one version of react in the app, AdminJS currently uses ^16 so if you have installed 17 or 18 in your project, this error can appear

nathanguigui commented 2 years ago

I'm using "adminjs": "^5.7.1" which use "react": "^16.13.1" and "react-dom": "^16.13.1" And in my package.json I'm using same version:

"react": "^16.13.1",
"react-dom": "^16.13.1",

The problem seems to appear when using in local then publishing to the production then login on the production. When I redeploy to the production it seems to fix the problem until I run on localhost again

dziraf commented 2 years ago

Can you check if there are separate react packages in: /node_modules/react /node_modules/adminjs/node_modules/react and check what's their exact version in their package.json?

nathanguigui commented 2 years ago

Inside /node_modules/react, I have a the react package version 16.13.1 I have no folder react inside /node_modules/adminjs/node_modules

For the version I just posted in my previous message:

I'm using "adminjs": "^5.7.1" which use "react": "^16.13.1" and "react-dom": "^16.13.1" And in my package.json I'm using same version: "react": "^16.13.1", "react-dom": "^16.13.1",

dziraf commented 2 years ago

Can you share all your dependencies?

nathanguigui commented 2 years ago

Sure


  "devDependencies": {
    "@types/multer": "^1.4.7",
    "@types/multer-s3": "^2.7.11",
    "@types/node-notifier": "^8.0.2",
    "@types/react-router": "^5.1.18",
    "env-cmd": "^10.1.0",
    "nodemon": "^2.0.15",
    "ts-node": "^10.5.0",
    "typescript": "^4.5.5"
  },
  "dependencies": {
    "@adminjs/design-system": "^2.2.4",
    "@adminjs/express": "^4.0.3",
    "@adminjs/typeorm": "^2.0.2",
    "@dnd-kit/core": "^5.0.3",
    "@dnd-kit/sortable": "^6.0.1",
    "@types/bcryptjs": "^2.4.2",
    "@types/express": "^4.17.13",
    "@types/lodash": "^4.14.178",
    "@types/luxon": "^2.3.1",
    "@types/morgan": "^1.9.3",
    "@types/node-mailjet": "^3.3.8",
    "adminjs": "^5.7.1",
    "aws-sdk": "^2.1080.0",
    "bcryptjs": "^2.4.3",
    "classnames": "^2.3.1",
    "cookie-parser": "^1.4.6",
    "cors": "^2.8.5",
    "cross-env": "^7.0.3",
    "esm": "^3.2.25",
    "express": "^4.17.3",
    "express-formidable": "^1.2.0",
    "express-session": "^1.17.2",
    "jsonwebtoken": "^8.5.1",
    "lodash": "^4.17.21",
    "luxon": "^2.3.1",
    "morgan": "^1.10.0",
    "multer": "^1.4.4",
    "multer-s3": "^2.10.0",
    "mysql": "^2.18.1",
    "nanoid": "^3.3.1",
    "node-mailjet": "^3.3.7",
    "node-notifier": "^10.0.1",
    "react": "16.13.1",
    "react-dom": "16.13.1",
    "react-select": "^5.2.2",
    "reflect-metadata": "^0.1.13",
    "swagger-express-ts": "^1.1.0",
    "swagger-ui-dist": "^4.9.0",
    "typeorm": "^0.2.43"
  }
nathanguigui commented 2 years ago

and there is the code where I inittialize adminjs:

    private initializeBackoffice() {
        const adminJs = new AdminJS({
            resources,
            assets: {
                styles: [
                    "/style.css",
                    "/dnd.css"
                ]
            },
            dashboard: {
                component: AdminJS.bundle("../../_admin/components/dashboard/Dashboard"),
                handler: DashboardActions.handler
            },
            rootPath: '/admin',
            branding: {
                companyName: "ProjectName",
                logo: "/logo_title.png",
                favicon: "/logo.png",
                softwareBrothers: false,
                theme: {
                    borders: {
                        default: ""
                    }
                }
            },
            locale: frLocale
        })
        const router = AdminJSExpress.buildAuthenticatedRouter(adminJs, {
            authenticate: async (email, password) => {
                try {
                    const user = await getRepository(BackofficeUser).findOne({
                        where: {email}, select: ["password", "firstName", "lastName", "email"]
                    })
                    if (user) {
                        const isValid = await bcrypt.compare(password, user.password)
                        if (isValid) {
                            delete user.password
                            return user
                        }
                    }
                } catch (e) {
                    console.log("authenticate failed:", e)
                }
                return false
            },
            cookiePassword: process.env.ADMIN_JS_COOKIE_SECRET, cookieName: process.env.ADMIN_JS_COOKIE_NAME
        })
        this.app.use(adminJs.options.rootPath, router)
        this.app.use('/api-docs/swagger/assets', express.static('node_modules/swagger-ui-dist'));
        this.app.use(swagger.express(
            {
                definition: {
                    info: {
                        title: "ProjectName API",
                        version: "1.0"
                    }
                    // Models can be defined here
                }
            }
        ));
        this.app.use(bodyparser.json({limit: "50mb"}));
        this.app.use(bodyparser.urlencoded({extended: false, limit: "50mb"}));
        this.app.use(morgan(":method :url :status :res[content-length] - :response-time ms"))
    }
dziraf commented 2 years ago

This is really strange, can you also check if there is a separate react in react-select's node_modules?

nathanguigui commented 2 years ago

in react-select's node_modules folder there is only @emotion but in package.json there are these lines:

  "peerDependencies": {
    "react": "^16.8.0 || ^17.0.0",
    "react-dom": "^16.8.0 || ^17.0.0"
  },
  "devDependencies": {
    "@types/jest-in-case": "^1.0.3",
    "enzyme": "^3.8.0",
    "enzyme-to-json": "^3.3.0",
    "jest-in-case": "^1.0.2",
    "react": "^16.13.0",
    "react-dom": "^16.13.0"
  },
nathanguigui commented 2 years ago

Do you think the problem can come from the auth cookies ? And is there a way to use localstorage instead of cookies for the authenticated router ?

dziraf commented 2 years ago

I don't think auth cookies are related. And currently cookie session is the only way to maintain session in AdminJS, we want to extend the support for different auth methods and providers in the future, but we don't have it planned anytime soon currently.

As for your issue, I would try to setup the simplest AdminJS project and see if your problem also appears there

nathanguigui commented 2 years ago

OK thanks for your time. I think you can re-open this issue

nathanguigui commented 2 years ago

After investigation, it's turns out that I'm using aws elastic beanstalk that auto create ec2 instance to scale the projet. And I was not using a session store.

So I think that the sessions were unsynced on the wrong ec2 instance.

I figured out the problem by providing a session store to the express session options of the adminjs authenticated router:


const mysql = require('mysql');
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);

const options = {
    host: process.env.MYSQL_HOST,
    port: 3306,
    user: process.env.MYSQL_USERNAME,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE,
    createDatabaseTable: true,
    //endConnectionOnClose: true,
};

const connection = mysql.createConnection(options); // or mysql.createPool(options);
const sessionStore = new MySQLStore({}/* session store options */, connection);

const router = AdminJSExpress.buildAuthenticatedRouter(
    adminJs, 
    {authenticate, cookiePassword: process.env.ADMIN_JS_COOKIE_SECRET, cookieName: process.env.ADMIN_JS_COOKIE_NAME},
    null,
    {store: sessionStore}
)
sir-guevara commented 2 years ago

installing react fixed it for me