Is it possible to work with React, dotenv, mongoose, passport and session at the same time?

Viewed 37

Introduction

Hi, I had no problem making my React project's first designs and even using react-router-dom for the first time:

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Inscription from "./components/Inscription.jsx";
import CGU from "./components/CGU.jsx";
import Connexion from "./components/Connexion.jsx";
import { createRoot } from 'react-dom/client';

const rootElement = createRoot(document.getElementById("root"))

let isAuthenticated = false;

rootElement.render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<Inscription />} />
      <Route path="cgu" element={<CGU auth={isAuthenticated}/>} />
      <Route path="connexion" element={<Connexion />} />
    </Routes>
  </BrowserRouter>,
);

Note that having my index.js with just this use to work (so there is no problem over the React part) but if I go back to this now, it doesn't work anymore

But when i tried to merge the "dotenv, mongoose, passport and session" part from a previous project it never worked.

Errors history

Launching npm start I had errors in cmd or in browser console like those (not at the same time) :

  • BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default. This is no longer the case. Verify if you need this module and configure a polyfill for it. If you want to include a polyfill, you need to: - add a fallback 'resolve.fallback: { "zlib": require.resolve("browserify-zlib") }' - install 'browserify-zlib' If you don't want to include a polyfill, you can use an empty module like this: resolve.fallback: { "zlib": false } ...

  • WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.

  • Module parse failed: Unexpected token (102:2) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders | | rootElement.render( >

  • WARNING in ./node_modules/express/lib/view.js 81:13-25 Critical dependency: the request of a dependency is an expression @ ./node_modules/express/lib/application.js 22:11-28 @ ./node_modules/express/lib/express.js 18:12-36 @ ./node_modules/express/index.js 11:0-41 @ ./src/index.js 10:14-32

  • ReferenceError: process is not defined at ./node_modules/path/path.js (path.js:25:1)

  • ReferenceError: express is not defined at Object.express (external var "express":1:1)

The Problem

Now the project is launching without any errors in cmd but style one in console and nothing shows up on browser

Currently showing:

cmd

amaur@LAPTOP-3905F5SG MINGW64 /d/PycharmProjects/WebDev/ProgrArmor.com/prograrmo
Compiled successfully!

You can now view prograrmor in the browser.      

  Local:            http://localhost:3000        
  On Your Network:  http://172.20.10.3:3000      

Note that the development build is not optimized.
To create a production build, use npm run build. 

assets by path *.png 1.3 MiB
  asset 31eb58e7b1ea86d10b518cd39c1b5100.png 642 KiB [emitted] [immutable] [from: src/images/inscription.png] (auxiliary name: main)
  asset 230b29d99d0466f2af66ce53b7b8d3bb.png 626 KiB [emitted] [immutable] [from: src/images/connexion.png] (auxiliary name: main)
  asset cc62361b25dca55ad8244d19f65c9ca9.png 51.3 KiB [emitted] [immutable] [from: src/images/icons/logo-navbar.png] (auxiliary name: main)
  asset 1c18621d251b07370f464fda90d5511e.png 2.88 KiB [emitted] [immutable] [from: src/images/icons/home.png] (auxiliary name: main)
  asset b3c39c2071654db2fc52fcf2e24720e0.png 2.19 KiB [emitted] [immutable] [from: src/images/icons/gear.png] (auxiliary name: main)
  asset bec2337a70615e418673414cbd55a5b4.png 1.81 KiB [emitted] [immutable] [from: src/images/icons/social.png] (auxiliary name: main)
  asset 81a00babca7c36446839a8238e4305d2.png 1.28 KiB [emitted] [immutable] [from: src/images/icons/write.png] (auxiliary name: main)
  asset ad31d74884d54dc19ea0c3881544e4e7.png 752 bytes [emitted] [immutable] [from: src/images/icons/chart.png] (auxiliary name: main)
  asset 3ab6e0275a668aa6545aadcc8a02fa1e.png 686 bytes [emitted] [immutable] [from: src/images/icons/plus.png] (auxiliary name: main)
asset main.js 3.31 MiB [emitted] (name: main)
asset index.html 1.33 KiB [emitted]
runtime modules 27.6 KiB 13 modules
modules by path ./node_modules/ 2.74 MiB
  javascript modules 2.43 MiB 163 modules
  json modules 318 KiB 18 modules
modules by path ./src/ 25.3 KiB
  modules by path ./src/images/ 720 bytes 9 modules
  modules by path ./src/components/*.jsx 21.1 KiB 8 modules
  ./src/index.js 3.43 KiB [built] [code generated]
modules by path ./*./streams (ignored) 30 bytes
  ./streams (ignored) 15 bytes [built] [code generated]
  ./streams (ignored) 15 bytes [built] [code generated]
modules by path ./*./extend-node (ignored) 30 bytes
  ./extend-node (ignored) 15 bytes [built] [code generated]
  ./extend-node (ignored) 15 bytes [built] [code generated]
+ 17 modules
webpack 5.74.0 compiled successfully in 49685 ms

Console

Uncaught ReferenceError: require is not defined
    at Object.events (index_bundle.js:1975:1)
    at __webpack_require__ (index_bundle.js:2384:33)
    at fn (index_bundle.js:2596:21)
    at eval (emitter.js:1:20)
    at ./node_modules/webpack/hot/emitter.js (index_bundle.js:1911:1)
    at __webpack_require__ (index_bundle.js:2384:33)
    at fn (index_bundle.js:2596:21)
    at eval (reloadApp.js:2:80)
    at ./node_modules/webpack-dev-server/client/utils/reloadApp.js (index_bundle.js:1869:1)
    at __webpack_require__ (index_bundle.js:2384:33)
DevTools failed to load source map: Could not load content for chrome-extension://nmibbjghlmdiafjolcphdggihcbcedmg/js.3bd8b779.js.map: System error: net::ERR_BLOCKED_BY_CLIENT

What I have done

Current Project Directories

/build
/design
/node_modules
/public
   bootstrap-social.css
   index.html
   styles.css
/src
   /components
      ...
   /images
      ...
   index.js
.babelrc
.env
.gitignore
.config-overrides.js
package.json
package-lock.json
README.md

Current index.js

almost just a copy-paste of my previous project with passport,... over this new one

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Inscription from "./components/Inscription.jsx";
import CGU from "./components/CGU.jsx";
import Connexion from "./components/Connexion.jsx";
import { createRoot } from 'react-dom/client';

//jshint esversion:6
require('dotenv').config();
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const session = require('cookie-session');
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const FacebookStrategy = require('passport-facebook').Strategy;
const findOrCreate = require('mongoose-findorcreate');

const app = express();

app.use(express.static("public"));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));

app.use(session({
    secret: "Our little secret.",
    resave: false,
    saveUninitialized: false
}));

app.use(passport.initialize());
app.use(passport.session());

//mongoose.connect("mongodb://localhost:27017/blogDB");
mongoose.connect("mongodb+srv://"+process.env.REACT_APP_LOGIN_MONGODB+":"+process.env.REACT_APP_MDP_MONGODB+"@cluster0.naapg7h.mongodb.net/ProgrArmorDB");

const userSchema = new mongoose.Schema({
    email: String,
    password: String,
    googleId: String,
    facebookId: String,
    secret: String
});

userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

const User = mongoose.model("User", userSchema);

passport.use(User.createStrategy());

passport.serializeUser(function(user, cb) {
  process.nextTick(function() {
    return cb(null, {
      id: user.id,
      username: user.username,
      picture: user.picture
    });
  });
});

passport.deserializeUser(function(user, cb) {
  process.nextTick(function() {
    return cb(null, user);
  });
});

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
//    callbackURL: "https://nameless-shore-98289.herokuapp.com/auth/google/secrets",
    callbackURL: "localhost:3000/auth/google/secrets",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
    }, function(accessToken, refreshToken, profile, cb) {
        console.log(profile);
        User.findOrCreate({ googleId: profile.id }, function (err, user) {
          return cb(err, user);
        });
  }
));

passport.use(new FacebookStrategy({
    clientID: process.env.FACEBOOK_CLIENT_ID,
    clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
//    callbackURL: "https://nameless-shore-98289.herokuapp.com/auth/facebook/secrets"
    callbackURL: "localhost:3000/auth/facebook/secrets",
  },
  function(accessToken, refreshToken, profile, cb) {
    console.log(profile);
    User.findOrCreate({ facebookId: profile.id }, function (err, user) {
      return cb(err, user);
    });
  }
));

const rootElement = createRoot(document.getElementById("root"))

let isAuthenticated = false;

rootElement.render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<Inscription />} />
      <Route path="cgu" element={<CGU auth={isAuthenticated}/>} />
      <Route path="connexion" element={<Connexion />} />
    </Routes>
  </BrowserRouter>,
);

Current config-overrides.js

Watching solutions over here I have made up this config-overrides file which solves most of the errors

'use strict';
/* eslint-env node, es6 */
const path = require('path');
const webpack = require('webpack');
const process = require('process');
const dotenv = require('dotenv');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const express = require('express');
const nodeExternals = require('webpack-node-externals');

dotenv.config();

/////////////
// Utility //
/////////////

/**
 * Recursively merges two webpack configs.
 * Concatenates arrays, and throws an error for other conflicting values.
 */
function merge(x, y) {
  if (x == null) { return y; }
  if (y == null) { return x; }

  if (x instanceof Array && y instanceof Array) {
    return x.concat(y);
  } else if (Object.getPrototypeOf(x) === Object.prototype &&
             Object.getPrototypeOf(y) === Object.prototype) {
    // for safety, only plain objects are merged
    let result = {};
    (new Set(Object.keys(x).concat(Object.keys(y)))).forEach(function (key) {
      result[key] = merge(x[key], y[key]);
    });
    return result;
  } else {
    throw new Error(`cannot merge conflicting values:\n\t${x}\n\t${y}`);
  }
}


/////////////////
// Base Config //
/////////////////

const srcRoot = './src/';

const commonConfig = {
    entry: './src/index.js',
    mode: 'development',
   output: {
      path: path.join(__dirname, '/bundle'),
      filename: 'index_bundle.js'
   },
   devServer: {
      inline: true,
      port: 3000,
   },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: "babel-loader"
      }
    ]
  },
  externalsPresets: { node: true },
  externals: [nodeExternals()], // Need this to avoid error when working with Express
  plugins: [
    new webpack.ProvidePlugin({
        process: 'process/browser',
    }),
    new HtmlWebpackPlugin({
         template: './public/index.html'
      }),
  ],
  externals: {
        "react-native": true,
        express: 'express',
    },
  module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: ["babel-loader"],
            },
            // ...
        ],
    },
  resolve: {
     alias: {
         process: "process/browser"
     },
     fallback: {
        // existing configs...
        os: require.resolve("os-browserify/browser"),
        assert: require.resolve('assert'),
        crypto: require.resolve('crypto-browserify'),
        http: require.resolve('stream-http'),
        https: require.resolve('https-browserify'),
        os: require.resolve('os-browserify/browser'),
        stream: require.resolve('stream-browserify'),
        zlib: require.resolve("browserify-zlib"),
        fs: false,
        net: false,
        async_hooks: false,
        process: require.resolve("process"),
        express: require.resolve("express"),
        path: require.resolve('path'),
        },
    },
};


//////////////////////
// Dev/Prod Configs //
//////////////////////

const devConfig = {
  output: {pathinfo: true}
};

const prodConfig = {
  devtool: 'source-map', // for the curious
};

const isProduction = (process.env.NODE_ENV === 'production');

module.exports = function override (config, env) {
    console.log('override')
    config = merge(commonConfig, isProduction ? prodConfig : devConfig);
    return config;
}

Current package.json

Note the "start": "react-app-rewired start",

{
  "name": "prograrmor",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "assert": "^2.0.0",
    "bcrypt": "^5.0.1",
    "body-parser": "^1.20.0",
    "bootstrap": "^5.2.1",
    "browserify-zlib": "^0.2.0",
    "buffer": "^6.0.3",
    "cookie-session": "^2.0.0",
    "crypto": "^1.0.1",
    "crypto-browserify": "^3.12.0",
    "dotenv-webpack": "^8.0.1",
    "ejs": "^3.1.8",
    "express": "^4.18.1",
    "express-session": "^1.17.3",
    "https-browserify": "^1.0.0",
    "md5": "^2.3.0",
    "mongoose": "^6.5.3",
    "mongoose-encryption": "^2.1.2",
    "mongoose-findorcreate": "^3.0.0",
    "node-polyfill-webpack-plugin": "^2.0.1",
    "os-browserify": "^0.3.0",
    "passport": "^0.5.3",
    "passport-facebook": "^3.0.0",
    "passport-google-oauth20": "^2.0.0",
    "passport-local": "^1.0.0",
    "passport-local-mongoose": "^7.1.2",
    "path": "^0.12.7",
    "path-browserify": "^1.0.1",
    "react": "^18.2.0",
    "react-app-rewired": "^2.2.1",
    "react-bootstrap": "^2.5.0",
    "react-dom": "^18.2.0",
    "react-native-web": "^0.18.9",
    "react-router-dom": "^6.4.0",
    "react-scripts": "5.0.1",
    "stream": "^0.0.2",
    "stream-browserify": "^3.0.0",
    "stream-http": "^3.2.0",
    "url": "^0.11.0",
    "util": "^0.12.4",
    "web-vitals": "^2.1.4",
    "webpack-node-externals": "^3.0.0"
  },
  "scripts": {
    "start": "react-app-rewired start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version",
      "> 0.25%, not dead"
    ]
  },
  "devDependencies": {
    "@babel/core": "^7.19.1",
    "@babel/preset-env": "^7.19.1",
    "babel-loader": "^8.2.5",
    "dotenv": "^16.0.2",
    "process": "^0.11.10",
    "webpack": "^5.74.0"
  }
}

Conclusion

I think that you agree that this is a mess. If I'm currently near the solution, please advice me, but if not, I would rather go back to the Introduction and someone tells me how to make the passport, mongoose etc work together with React. Thanks a lot.

1 Answers

I had a lot of trouble here but I made it Basically there is 3 solutions on this problem depending on what you want to do:

1 - Abandon Node and do everything in React (only front might be a bad idea)

2 - Abandon React and stick to EJS (for example)

3 - React is your front-end, to connect it to a back-end you can create an API. You will then run simultaneously a server for your API and your React App. I have done all the hard stuff for you here: https://github.com/AmaurySimondet/MERN-auth-app

This is called a MERN app for Mongo Express React Node and you will find other ressources searching for this term.

Related