How to build an exe for Electron + React - reactjs

I have been reading documentation and trying so many different things for days now. My electron app works just fine in dev mode, but both electron-forge and electron-builder do not work. My project is currently using electron-forge.
They both are able to create an installer. Electron forge doesn't install after running. electron-builder installs, but the app doesn't do anything when you click on it.
I really do not know what I'm doing wrong and I feel like I'm losing my mind.
I tried following the Squirrel.windows documentation for debugging, but when in the correct directory the commands don't even work.
Here is my package.json:
{
"name": "ptax-automation-desktop-app",
"author": "Redacted",
"version": "0.2.2",
"description": "In the property tax industry there is alot of monotonous work that involves visiting County's websites to retrieve Tax Bills, Assessment Notices, and other documents and subsequently upload this information to their system. However, with such monotony data entry errors are bound to be made. Also, a person's labor could be much better used towards something that requires more complex decision making while the automation runs in the background. Simply install the app, select an automation you want to run, upload a spreadsheet with the list of data points needed and relax.",
"main": "public/electron.js",
"homepage": "./",
"dependencies": {
"#formkit/auto-animate": "^1.0.0-beta.3",
"#fortawesome/fontawesome-svg-core": "^1.3.0",
"#fortawesome/free-solid-svg-icons": "^6.0.0",
"#fortawesome/react-fontawesome": "^0.1.17",
"#testing-library/jest-dom": "^5.16.2",
"#testing-library/react": "^12.1.3",
"#testing-library/user-event": "^13.5.0",
"bootstrap": "^5.1.3",
"browserify": "^17.0.0",
"capture-website": "^2.4.0",
"colors": "^1.4.0",
"concurrently": "^7.0.0",
"cross-env": "^7.0.3",
"dotenv": "^16.0.3",
"electron-common-ipc": "^15.1.0",
"electron-is-dev": "^2.0.0",
"electron-squirrel-startup": "^1.0.0",
"electron-store": "^8.0.1",
"electron-updater": "^5.3.0",
"find-object-paths": "^1.0.2",
"html-pdf-chrome": "^0.8.1",
"nanoid": "^4.0.0",
"path": "^0.12.7",
"prompt-sync": "^4.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "^6.2.2",
"react-scripts": "5.0.0",
"reactstrap": "^9.0.1",
"redux": "^4.1.2",
"redux-thunk": "^2.4.1",
"request": "^2.88.2",
"selenium-webdriver": "^4.2.0",
"socket-port-helpers": "^2.1.0",
"url": "^0.11.0",
"wait-on": "^6.0.1",
"web-vitals": "^2.1.4",
"xlsx": "^0.18.5"
},
"devDependencies": {
"#electron-forge/cli": "^6.0.0",
"#electron-forge/maker-deb": "^6.0.0",
"#electron-forge/maker-rpm": "^6.0.0",
"#electron-forge/maker-squirrel": "^6.0.0",
"#electron-forge/maker-zip": "^6.0.0",
"electron": "^21.2.2",
"electron-devtools-installer": "^3.2.0",
"node-sass": "^7.0.1",
"nodemon": "^2.0.15"
},
"scripts": {
"app": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron-forge start\"",
"prestart": "browserify -o ./public/preload.bundle.js -x electron ./preload.js",
"start": "cross-env GENERATE_SOURCEMAP=false",
"poststart": "react-scripts start",
"build": "react-scripts build && electron-builder -p always",
"electron:package:win": "npm run build && electron-builder -w -c.extraMetadata.main=build/electron.js",
"test": "react-scripts test",
"build-css": "node-sass ./src/css/sass_css/ -o ./src/css/vanilla_css/",
"watch-css": "nodemon -e scss -x \"npm run build-css\"",
"eject": "react-scripts eject",
"package": "react-scripts build && electron-forge package",
"make": "react-scripts build && electron-forge make"
},
"config": {
"forge": {
"packagerConfig": {
"icon": "src/images/icon.ico",
"name": "Ptax Automation App",
"asar": true
},
"makers": [
{
"name": "#electron-forge/maker-squirrel",
"config": {
"name": "cra_electron_forge_demo"
}
},
{
"name": "#electron-forge/maker-zip",
"platforms": [
"darwin"
]
},
{
"name": "#electron-forge/maker-deb",
"config": {}
},
{
"name": "#electron-forge/maker-rpm",
"config": {}
}
]
}
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
"last 1 electron version",
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 electron version",
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Here is my folder structure:
Here is my preload file:
const electronCommonIPC = require("electron-common-ipc/lib/electron-common-ipc-preload");
electronCommonIPC.PreloadElectronCommonIpc();
window.electronCommonIPC = electronCommonIPC;
window.require = require;
Here is my electron main file:
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require("electron");
// Library Imports
const { isDev } = require("electron-is-dev");
const Store = require("electron-store");
//Functions
const {
createIpcBusBridge,
} = require("./electron/functions/ipc/createIpcBusBridge");
const { createWindow } = require("./electron/functions/window/createWindow");
const { createTray } = require("./electron/functions/tray/createTray");
// Listeners
require("./electron/ipc-main-listeners/allListeners");
/*
---------------------------START OF BASE TEMPLATE---------------------------
*/
let store = new Store();
let tray;
/*
The whenReady method will be called when Electron has finished
initialization and is ready to create browser windows.
Some APIs can only be used after this event occurs.
*/
const reactDevToolsId = "fmkadmapgofadopljbjfkapdkoienihi";
app.whenReady().then(() => {
console.log("isDev: ", isDev);
if (isDev === undefined) {
const {
default: installExtension,
REDUX_DEVTOOLS,
} = require("electron-devtools-installer");
installExtension([REDUX_DEVTOOLS, reactDevToolsId])
.then((name) => console.log(`Added Extension: ${name}`))
.catch((err) => console.log("An error occurred: ", err));
}
const window = createWindow(__dirname, process, store);
if (tray !== undefined) {
tray.destroy();
}
tray = createTray(window, __dirname, process);
createIpcBusBridge();
app.on("activate", function () {
/*
On macOS it's common to re-create a window in the app when the
dock icon is clicked and there are no other windows open.
*/
if (BrowserWindow.getAllWindows().length === 0)
createWindow(window, tray, __dirname, process, store);
});
});
/*
Prevent Tray Icon Duplication
*/
app.on("before-quit", function () {
tray.destroy();
});
/*
Quit when all windows are closed, except on macOS. There, it's common
for applications and their menu bar to stay active until the user quits
explicitly with Cmd + Q.
*/
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
/*
---------------------------END OF BASE TEMPLATE---------------------------
*/
console.log("Settings path: ", app.getPath("userData"));
Here is the function I imported for creating the window from public/electron directory:
// Library Imports
const { BrowserWindow, ipcMain } = require("electron");
const { autoUpdater } = require("electron-updater");
const isDev = require("electron-is-dev");
const path = require("path");
const url = require("url");
// Functions
const { handleResolutionPref } = require("./handleResolutionPref");
const { handlePositionPref } = require("./handlePositionPref");
const { maximizeWindow } = require("./maximizeWindow");
const { minimizeWindow } = require("./minimizeWindow");
const { closeWindow } = require("./closeWindow");
// Listeners
require("../updater/listeners/updateAvailable");
require("../updater/listeners/updateDownloaded");
const createWindow = (directoryName, process, store) => {
const [screenWidth, screenHeight] = handleResolutionPref(store);
const [screenXCoordinate, screenYCoordinate, isScreenPositionCustom] =
handlePositionPref(store);
console.log(
"preload directory",
path.join(directoryName, "preload.bundle.js")
);
let window = null;
// Create the browser window.
if (isScreenPositionCustom === true) {
window = new BrowserWindow({
width: screenWidth,
height: screenHeight,
frame: false,
fullscreenable: true,
resizable: true,
transparent: false,
x: screenXCoordinate,
y: screenYCoordinate,
webPreferences: {
preload: path.join(directoryName, "preload.bundle.js"),
contextIsolation: false,
nodeIntegration: true,
sandbox: false,
webSecurity: false,
},
icon: path.join(directoryName, "icon.ico"),
});
} else {
window = new BrowserWindow({
width: screenWidth,
height: screenHeight,
frame: false,
fullscreenable: true,
resizable: true,
transparent: false,
webPreferences: {
preload: path.join(directoryName, "preload.bundle.js"),
contextIsolation: false,
nodeIntegration: true,
sandbox: false,
webSecurity: false,
},
icon: path.join(directoryName, "icon.ico"),
});
}
window.on("closed", () => (window = null));
if (isDev === true) {
window.loadURL("http://localhost:3000");
} else {
window.loadURL(
url.format({
pathname: path.join(__dirname, "index.html"),
protocol: "file:",
slashes: true,
})
);
}
// Handle window toggling for custom titlebar
ipcMain.on("windowMinimize", () => minimizeWindow(window));
ipcMain.on("windowMaximize", () => maximizeWindow(window));
ipcMain.on("windowClose", () => closeWindow(window));
// Open the DevTools.
// window.webContents.openDevTools()
if (isDev === false) {
autoUpdater.checkForUpdates();
}
return window;
};
module.exports = { createWindow };
What am I doing wrong here guys?

So after losing my sanity for about 4 days I found out the cause of this.
For one reason or another, electron-is-dev is not working properly, and is just returning undefined. My window was never created because it was trying to install Redux dev tools when it shouldn't.
My solution was to replace the electron-is-dev with just checking the value of app.isPackaged instead.
I feel infuriated that I spent so long on such a stupid bug, but it's my fault for depending on the library I guess.

Related

Electron app not running after building with electron-forge [duplicate]

Here is my package.js file
{
"name": "cabed",
"version": "0.1.0",
"private": false,
"dependencies": {
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#testing-library/user-event": "^13.5.0",
"axios": "^0.27.2",
"electron-forge": "^5.2.4",
"electron-is-dev": "^2.0.0",
"electron-packager": "^17.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"main": "public/electron.js",
"homepage": "./",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"dev": "concurrently -k \"cross-env BROWSER=none npm start\" \"npm:electron\"",
"electron": "wait-on tcp:3000 && electron .",
"eb": "electron-packager C:/Users/user/cabed cddf --platform=win32 --arch=x64"
},
"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"
]
},
"devDependencies": {
"concurrently": "^7.6.0",
"cross-env": "^7.0.3",
"electron": "^22.1.0",
"wait-on": "^7.0.1"
},
"config": {
"forge": {
"packagerConfig": {},
"makers": [
{
"name": "#electron-forge/maker-squirrel",
"config": {
"name": "stock_trading_app"
}
},
{
"name": "#electron-forge/maker-zip",
"platforms": [
"darwin",
"linux",
"win32"
]
},
{
"name": "#electron-forge/maker-deb",
"config": {}
},
{
"name": "#electron-forge/maker-rpm",
"config": {}
}
]
}
}
}
The generated exe with electron builder which i ran with
npm run eb
the exe generated by code above
does not render the react app inside the opened windows app.
Here is my app js
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div style={{justifyContent:'center',alignContent:'center',alignItems:'center'}}>
<div className="App">
<img src={logo} className="App-logo" alt="logo" />
<p>
Sasdsad
</p>
<p>
Sasdsad
</p>
</div></div>
);
}
export default App;
my electron.js looks like this under public directory.
const path = require('path');
const { app, BrowserWindow } = require('electron');
const isDev = require('electron-is-dev');
function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
});
// and load the index.html of the app.
// win.loadFile("index.html");
win.loadURL(
isDev
? 'http://localhost:3000'
: `file://${path.join(__dirname, "./index.html")}`
);
// Open the DevTools.
if (isDev) {
win.webContents.openDevTools({ mode: 'detach' });
}
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
When running npm start first, then the exe renders react page inside window.
I need some configuration probably but i could not found it yet.
Since you said it works when you start your server first, I assume you're using the localhost URL both in dev and in prod. When your app is packaged, you should load the file in your window and not the local URL:
const { app } = require("electron");
const windowURL = app.isPackaged
? `file://${path.join(__dirname, "./index.html")}`
: "http://localhost:3000/";
mainWindow.loadURL(windowURL);
The path when your app is packaged might be different depending on your file structure and your build/package configurations. Also, don't forget to add "homepage": "./" on your package.json or you may get a blank page.

Electron Packager - when I copy app-win32-x64 dir to another path, executable stops working

I've packaged an electron-react app with:
electron-packager . app --platform=win32 --arch=x64 --overwrite
Then a app-win32-x64 folder is created containing the executable and some other files:
app-win32-x64 folder
When I run the executable everything works fine.
Then, I copy the app-win32-x64 folder to another path (where my colleges can access the executable). When I double-click on the exe now, the electron app starts, but with a blank screen and after a few seconds it closes again.
Do you have any idea why this happens?
I haven't used any absolute paths in my code.
here is my main.js:
const { BrowserWindow, app, ipcMain, Notification } = require('electron');
const path = require('path');
var fs = require('fs')
const isDev = !app.isPackaged;
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
backgroundColor: "white",
webPreferences: {
nodeIntegration: false,
worldSafeExecuteJavaScript: true,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html');
}
if (isDev) {
require('electron-reload')(__dirname, {
electron: path.join(__dirname, 'node_modules', '.bin', 'electron')
})
}
ipcMain.on('notify', (_, message) => {
new Notification({title: 'Notifiation', body: message}).show();
})
ipcMain.on('makeDir', (event, path) => {
fs.mkdir(path, (err) => {
if (err) {
return console.log(err);
}
console.log(`Created directory in ${path} successfully`);
})
})
app.whenReady().then(createWindow)
here is my package.json:
{
"name": "electron-react-app",
"productName": "App",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --config webpack.common.js --watch",
"start": "electron ."
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"#babel/core": "^7.20.2",
"#babel/preset-env": "^7.20.2",
"#babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.0",
"css-loader": "^6.7.2",
"electron": "^21.3.1",
"electron-packager": "^17.1.1",
"electron-reload": "^2.0.0-alpha.1",
"sass": "^1.56.1",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0"
}
}
If you need any other scripts, let me know.
I also tried copying the entire source code folder, not just the app-win32-x64 folder, it still didn't work. Is it maybe because of some security measures in this other directory? Usually executables run there, that's what the directory is for.
Thank you so much in advance!
Leon

How to resolve: Failed to load resource: the server responded with a status of 404 (Not Found) in Reactjs

I am working on a social interface project with MERN Stack technology on windows 10. I am running my frontend on port 3000 and my backend on port 5000 of my localhost. When I perform an operation that requires my frontend to be connected to my backend for example the account creation operation, after submitting the account creation form and clicking on the sign up button, nothing happens and when I 'inspect my react web page at the frontend, I see the following error: Failed to load resource: the server responded with a status of 404 (Not Found). After doing research on the Internet, I understood that this was due to the fact that I passed a bad url to my frontend. However, I don't understand why I'm getting this error.
The contents of my backend .env file:
PORT=5000
MONGO_URI="mongodb://localhost:27017/server"
JWT_SECRET = "12/03/2020"
JWT_EXP = '10h'
ADMIN_EMAIL = ""
ADMIN_PASSWORD = ""
I do not put the other values ​​for security reasons. The contents of my config.js file at the backend:
module.exports = {
PORT: process.env.PORT || 4000,
MONGODB_URI: process.env.MONGODB_URI || "mongodb://localhost:27017/server",
JWT_SECRET: process.env.JWT_SECRET || "itssecret",
JWT_EXP: process.env.JWT_EXPIRE || '10h',
ADMIN_EMAIL: process.env.ADMIN_EMAIL || "admin#gmail.com",
ADMIN_PASSWORD: process.env.ADMIN_PASSWORD || "admin#123",
}
the one from my index.js file at the backend:
const express = require('express')
const cors = require('cors')
const mongoose = require('mongoose')
require("dotenv").config()
const app = express()
const http = require('http')
const socket = require("socket.io");
const server = http.createServer(app)
//The modifications are here
const io = socket(server, {
cors: {
origin: "http://localhost:3000",
credentials: true,
},
});
const UserRoutes = require('./routes/User')
const AuthRoutes = require('./routes/Auth')
const PostRoutes = require('./routes/Post')
const PORT = process.env.PORT || 5000
const {MONGODB_URI} = require("./config")
app.use(cors())
app.use(express.json())
app.use((req, res, next) => {
io.req = req
req.io = io
next()
})
app.use('/api/auth', AuthRoutes)
app.use('/api/user', UserRoutes)
app.use('/api/post', PostRoutes)
require('./socket')(io)
mongoose
.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log('database connected')
server.listen(PORT, () => console.log(`server started on port ${PORT}`))
})
.catch((err) => console.log(err))
here is the change i made to the index.js file to fix the problem, but nothing; I change the declaration line of my constante io:
const io = require('socket.io')(server)
the definition of the routes at the backend:
router.post('/signup', SignupUser)
router.post('/login', LoginUser)
router.get("/logout",authRequired,Logout)
router.put("/update_password",authRequired,ChangePassword)
module.exports = router
here is my frontend package.json file:
{
"name": "firebase",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.9.0",
"#emotion/styled": "^11.8.1",
"#fortawesome/fontawesome-svg-core": "^6.1.1",
"#fortawesome/free-brands-svg-icons": "^6.1.1",
"#fortawesome/free-regular-svg-icons": "^6.1.1",
"#fortawesome/free-solid-svg-icons": "^6.1.1",
"#fortawesome/react-fontawesome": "^0.1.18",
"#material-ui/core": "^4.12.4",
"#material-ui/icons": "^4.11.3",
"#material-ui/lab": "^4.0.0-alpha.61",
"#mui/material": "^5.8.1",
"#react-google-maps/api": "^2.11.8",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^13.2.0",
"#testing-library/user-event": "^13.5.0",
"axios": "0.27.2",
"classnames": "2.2.6",
"dotenv": "8.2.0",
"emoji-picker-react": "^3.5.1",
"firebase": "^9.8.4",
"install": "^0.13.0",
"jwt-decode": "3.1.2",
"moment": "^2.29.3",
"node-fetch": "^3.2.4",
"npm": "^8.11.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-eva-icons": "0.0.8",
"react-hook-google-maps": "^0.0.3",
"react-moment": "^1.1.2",
"react-router-dom": "5.3.3",
"react-scripts": "5.0.1",
"socket.io-client": "4.5.1",
"words-to-numbers": "1.5.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"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"
]
},
"devDependencies": {
"web-vitals": "^2.1.4"
}
}
Here is my backend socket.js file:
const User = require('./models/User')
const jwt = require('jsonwebtoken')
module.exports = (io) => {
io.on('connection', (socket) => {
if (io.req) {
socket.broadcast.emit('friend-login-status', { user_id: io.req.userId })
addSocketIdInDB(socket.id, io.req.userId)
socket.on('disconnect', () => {
socket.broadcast.emit('friend-logout-status', {
user_id: io.req.userId,
})
io.req.userId = null
})
}
})
}
async function addSocketIdInDB(socket_id, user_id) {
const user = await User.findById(user_id)
if (socket_id) {
user.socketId = socket_id
}
await user.save()
}
Here is the content of my frontend .env file:
REACT_APP_ENDPOINT = "http://localhost:5000"
Here is the content of my useSignupUser.js file where the error was thrown:
const url = process.env.REACT_APP_ENDPOINT
...
...
const { data } = await axios.post(`${url}/api/auth/signup`, initialState)
localStorage.setItem('token', JSON.stringify(data.data.token))
const me = await fetchCurrentUser()
setLoading(false)
To solve this error, I modified the data constant declaration line as well, but without success:
const { data } = await axios.post(`http://localhost:5000/api/auth/signup`, initialState)
I obtain this error to the following url:
http://localhost:3000/%22http://localhost:5000%22/api/auth/signup
I looked on this stackoverflow question but nothing. So I hope to rely on the community. Thanks.
I found the solutions to my problem.
Solution 1 :
In the frontend .env file, write without quotes:
REACT_APP_ENDPOINT = http://localhost:5000
instead of:
REACT_APP_ENDPOINT = "http://localhost:5000"
Solution 2 (only in developer mode) :
For this, I edited my package.json file of the backend:
{
"name": "backend",
"version": "1.0.0",
"license": "MIT",
"main": "index.js",
"type": "commonjs",
"scripts": {
"dev": "concurrently \"npm start\" \"npm run client\"",
"start": "node index.js",
"server": "nodemon index.js",
"client": "npm start --prefix frontend"
},
"dependencies": {
"bcrypt": "^5.0.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "4.17.1",
"jsonwebtoken": "^8.5.1",
"mongodb": "^3.7.3",
"mongoose": "^5.10.7",
"multer": "^1.4.2",
"socket.io": "^4.4.1"
},
"devDependencies": {
"concurrently": "^7.2.2",
"nodemon": "^2.0.4"
}
}
For those who don't know, I advise you to use concurrently , it allows you to run two commands at the same time from one; here i am using it to start my backend and frontend server from npm run dev command. This is very practical when working in MERN Stack.
I added this line on my frontend package.json file:
"proxy": "http://127.0.0.1:5000",
this solves the cors error which prevents a domain in my case localhost:3000 from communicating with another for example localhost:5000. This error is due to a restriction used to reduce the risk of site hacking via other.
And I modified the files of the frontend where the API was called in this way:
const { data } = await axios.post(`/api/auth/signup`, initialState)
instead of
const { data } = await axios.post(`{$url}/api/auth/signup`, initialState)
The reason is that since I added a proxy to my package.json file, I no longer need to specify my server's port number in my frontend files because the connection is automatic.

Cypress returns "browserslist" error in Create React App?

I've got a very simple Create React App that I am trying to implement Cypress with. I initially had a different but related error that I was able to overcome. I'm not entirely sure why I would be given this type of error considering I do have the default "browserslist" key in my package.json file.
package.json
{
"name": "cypress_test",
"version": "0.1.0",
"private": true,
"engines": {
"node": "16.13.1",
"npm": "8.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"cypress": "cypress open",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"dependencies": {
"#cypress/react": "^5.12.4",
"#cypress/webpack-dev-server": "^1.8.4",
"#emotion/react": "^11.9.0",
"#emotion/styled": "^11.8.1",
"#fontsource/roboto": "^4.5.5",
"#mui/icons-material": "^5.6.2",
"#mui/material": "^5.6.3",
"#mui/styled-engine-sc": "^5.6.1",
"#testing-library/jest-dom": "^5.16.4",
"#testing-library/react": "^12.1.5",
"#testing-library/user-event": "^13.5.0",
"browserslist": "^4.6.3",
"cypress": "^9.6.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.1",
"sass": "^1.51.0",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.4"
},
"devDependencies": {
"#babel/core": "^7.17.9",
"#babel/preset-env": "^7.16.11",
"#cypress/webpack-preprocessor": "^5.11.1",
"babel-loader": "^8.2.5",
"eslint-plugin-cypress": "^2.12.1",
"html-webpack-plugin": "^4.5.2",
"webpack": "^5.72.0"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"overrides": [
{
"extends": [
"plugin:cypress/recommended"
],
"files": [
"cypress/**/*.js"
]
}
],
"resolutions": {
"#mui/styled-engine": "npm:#mui/styled-engine-sc#latest"
},
"jest": {
"coveragePathIgnorePatterns": [
"<rootDir>/cypress/"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
When I initially installed CRA, it used the latest version of React 18, but apparently Cypress doesn't have support for 18 yet so I downgraded React to 17. I'm wondering if there are some sort of package mismatches that I'm unaware of and aren't receiving specific errors for. As a note though, the app runs fine in the browser. Here are the other related files:
/cypress/plugins/index.js:
const findWebpack = require('find-webpack')
const webpackPreprocessor = require('#cypress/webpack-preprocessor');
const injectDevServer = require('#cypress/react/plugins/react-scripts');
module.exports = (on, config) => {
const webpackOptions = findWebpack.getWebpackOptions();
if (!webpackOptions) {
throw new Error('Could not find Webpack in this project');
}
const cleanOptions = { reactScripts: true };
findWebpack.cleanForCypress(cleanOptions, webpackOptions);
const options = {
webpackOptions,
watchOptions: {},
};
on('file:preprocessor', webpackPreprocessor(options));
injectDevServer(on, config);
return config;
};
App.spec.js:
import React from 'react';
import data from '../fixtures/data.json';
import App from '../../src/App.jsx';
describe('Test search functionality', () => {
beforeEach(() => {
cy.mount(<App />);
});
it('renders new fact when search is performed', () => {
cy.visit('http://localhost:3001')
// Type in search input
cy.get('input').type('Test');
// Click on search button
cy.get('.submit-btn').click();
// Intercept the request and return the mock data
cy
.intercept({
method: 'GET',
url: `${process.env.REACT_APP_API_ENDPOINT}/jokes/search?query=Test`
}, {
fixture: data.result[1]
})
.as('fetchFact');
// cy.wait(['#fetchFact']);
cy.get('p.copy').should('contain', data.result[1].value);
})
});
cypress.json:
{
"baseUrl": "http://localhost:3001",
"videos": false,
"component": {
"testFiles": "**/*.cy.{js,ts,jsx,tsx}",
"componentFolder": "src"
}
}
Cypress error:
Error: No browserslist config found to handle the 'browserslist' target.
See https://github.com/browserslist/browserslist#queries for possible ways to provide a config.
The recommended way is to add a 'browserslist' key to your package.json and list supported browsers (resp. node.js versions).
You can also more options via the 'target' option: 'browserslist' / 'browserslist:env' / 'browserslist:query' / 'browserslist:path-to-config' / 'browserslist:path-to-config:env'
at TARGETS.web (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:93:11)
at getTargetProperties (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:296:19)
at /Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:342:20
at Array.map (<anonymous>)
at getTargetsProperties (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/target.js:342:11)
at applyWebpackOptionsDefaults (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/config/defaults.js:142:6)
at createCompiler (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:77:2)
at create (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:134:16)
at webpack (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/webpack.js:158:32)
at f (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/webpack/lib/index.js:63:16)
at Object.handler (/Users/jimmiejackson/Documents/repositories/cypress_test/node_modules/#cypress/webpack-preprocessor/dist/index.js:148:24)
at invoke (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:22:16)
at /Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:45:14
at tryCatcher (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/util.js:16:23)
at Function.Promise.attempt.Promise.try (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/node_modules/bluebird/js/release/method.js:39:29)
at Object.wrapChildPromise (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:44:23)
at Object.wrap (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/preprocessor.js:28:8)
at execute (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:123:27)
at EventEmitter.<anonymous> (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/child/run_plugins.js:213:5)
at EventEmitter.emit (node:events:390:28)
at process.<anonymous> (/Users/jimmiejackson/Library/Caches/Cypress/9.6.0/Cypress.app/Contents/Resources/app/packages/server/lib/plugins/util.js:19:22)
at process.emit (node:events:390:28)

Warning: Did not expect server HTML to contain the text node "Home" in <div>

We are making an npm react package (by tsdx library) which is a custom hook. Developers who install this package need to make a config.json file at the root and a Languages.json file in the public folder of their Next.js project. We need to access the information in these files that the developer wrote.
Package files:
LanguageProvider.tsx: A react context that stores the current locale state.
UseTranslation.tsx: A custom hook that gets the locale from the context and finds the key from the current locale in Languages.json.
export function useTranslation() {
const { locale } = useContext(LanguageContext);
let LanguagesFile;
if (typeof window === 'undefined') {
const fs = require('fs');
LanguagesFile = fs.readFileSync("./public/Languages.json", 'utf8');
}
function t(key: string) {
if (typeof LanguagesFile !== 'undefined') {
const Languages = JSON.parse(LanguagesFile);
if (!Languages && !Languages[locale] && !Languages[locale][key]) {
console.warn(`No string '${key}' for locale '${locale}'`);
return false;
} else {
return Languages[locale][key].toString() || '';
}
}
}
return t;
}
package.json
{
"version": "0.1.0",
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"engines": {
"node": ">=10"
},
"scripts": {
"start": "tsdx watch",
"build": "tsdx build",
"test": "tsdx test --passWithNoTests",
"lint": "tsdx lint",
"prepare": "tsdx build",
"size": "size-limit",
"analyze": "size-limit --why"
},
"browser": {
"fs": false,
"os": false,
"path": false
},
"peerDependencies": {
"react": ">=16"
},
"husky": {
"hooks": {
"pre-commit": "tsdx lint"
}
},
"prettier": {
"printWidth": 80,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
},
"name": "react-intl",
"author": "Roya Shahroudi",
"module": "dist/react-intl.esm.js",
"size-limit": [
{
"path": "dist/react-intl.cjs.production.min.js",
"limit": "10 KB"
},
{
"path": "dist/react-intl.esm.js",
"limit": "10 KB"
}
],
"devDependencies": {
"#size-limit/preset-small-lib": "^5.0.4",
"#types/react": "^17.0.22",
"#types/react-dom": "^17.0.9",
"husky": "^7.0.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"size-limit": "^5.0.4",
"tsdx": "^0.14.1",
"tslib": "^2.3.1",
"typescript": "^4.4.3"
}
}
The Next.js project that installed this package:
public/Languages.json
{
"en-us": {
"home": "Home",
"about": "About us"
},
"fa-ir": {
"home": "خانه",
"about": "درباره ما"
}
}
pages/index.js
export default function Home({Languages}) {
const { locale, setLang } = useContext(LanguageContext);
const t = useTranslation();
return (
<>
<div>{t('home')}</div>
<button onClick={() => setLang('fa-ir')}>
Change Language To Persian
</button>
<button onClick={() => setLang('en-us')}>
Change Language To English
</button>
</>
);
}
When I run the project it shows this warning in the browser console:
Warning: Did not expect server HTML to contain the text node "Home" in <div>.
at div
at Home
and the text from t function doesn’t render on the page.

Resources