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

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.

Related

How to build an exe for Electron + React

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.

Deploying React, Express project to Heroku

I have created a small React Express app and am struggling with deploying it to Heroku.
So far I have organised the client and server into separate folders.
Previously I had the contents of server in the projects root and client as its own folder accessed with a path.join however this didn't serve any of the build files so I opted to separate the folders.
Now with two folders I use a root package.json to install all dependencies and get both sides running.
{
"name": "project",
"version": "1.0.0",
"main": "",
"scripts": {
"start": "npm start --prefix server",
"install-client": "cd client && npm install && npm run build && cd ..",
"install-server": "cd server && npm install && cd .. ",
"heroku-postbuild": "npm run install-client && npm run install-server"
}
}
This works with my other folders in serving the back-end however there is no front-end at all. I'm wondering if there is a solution to this problem specifically or even a better way to deploy a full stack project in the same dyno.
This is my currently result on my Heroku app:
Heroku app result
And here any additional relevant files:
Main server file
const express = require('express');
const path = require('path');
const cors = require('cors');
const db = require('./config/db');
const app = express();
const PORT = process.env.PORT || 8080;
//Dependencies
app.use(express.json());
app.use(cors());
//Select all rows from table
app.get('/api/get', (req, res) => {
const selectAll = 'SELECT * FROM plant_data';
db.query(selectAll, (err, rows) => {
if (err) throw err;
res.send(rows);
});
});
//Insert into database
app.post('/api/insert', (req, res) => {
const row = req.body.row;
const insert = "INSERT INTO plant_data (test) VALUES (?)";
db.query(insert, [row], (err, rows) => {
if (err) throw err;
console.log("inserted: " + row);
});
});
//Server port
app.listen(process.env.PORT || PORT, () => {
console.log('Server started on port ' + PORT);
});
Main client file
import React, {useState, useEffect} from "react";
import axios from "axios";
export default function Index() {
const [data, setData] = useState('');
const [rows, setRows] = useState([]);
useEffect(() => {
axios.get('/api/get')
.then(res => {
setRows(res.data);
}).catch(err => {
console.log(err);
});
});
//Connects front-end submit to backend db
const insertRow = () => {
axios.post('/api/insert', {
row: data
});
};
return (
<>
<h1>Body</h1>
<input type="text" onChange={(e) => {
setData(e.target.value);
}} />
<button onClick={insertRow}>Submit</button>
{rows.map((row) => {
return <p>{row.test}</p>
})}
</>
);
};
Server package file:
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"heroku-postbuild": "npm install --prefix client && npm run build --prefix client"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.0",
"cors": "^2.8.5",
"express": "^4.18.1",
"mysql": "^2.18.1",
"nodemon": "^2.0.19"
}
}
Client package file:
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"#emotion/react": "^11.8.2",
"#material-ui/core": "^4.12.3",
"#mui/material": "^5.5.3",
"#testing-library/jest-dom": "^5.16.2",
"#testing-library/react": "^12.1.4",
"#testing-library/user-event": "^13.5.0",
"axios": "^0.27.2",
"hamburger-react": "^2.4.1",
"node-sass": "^7.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-router-dom": "^6.2.2",
"react-scripts": "5.0.0",
"styled-components": "^5.3.5",
"web-vitals": "^2.1.4"
},
"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"
]
}
}

how to use nodejs modules in nw/react app

I'm trying to build an app with NW ans react and i'm having trouble calling node js modules fron react like the "fs" module i got the following error: TypeError: fs.readdir is not a function
this is my folders structure:
public
-----files generated by CRA
src
-----main.js
-----handlers.js
-----files generated by CRA
package.json
{
"name": "nw-react",
"version": "0.1.0",
"private": true,
"main": "./public/main.js",
"dependencies": {
"#testing-library/jest-dom": "^5.11.4",
"#testing-library/react": "^11.1.0",
"#testing-library/user-event": "^12.1.10",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"nw" : "nw ."
},
"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": {
"cross-env": "^7.0.3",
"nw": "^0.64.1"
}
}
main.js
nw.Window.open("http://localhost:3000", {}, function (win) {});
handlers.js
const fs = require("fs");
exports.getFiles = cb => {
const dir = "C:\\Users\\pc\\Documents";
fs.readdir(dir, (err, files) => {
cb(files);
});
};
App.js
import { useState, useEffect } from "react";
import logo from "./logo.svg";
import "./App.css";
const handlers = require("./handler");
function App() {
const [files, setFiles] = useState([]);
useEffect(() => {
handlers.getFiles(files => {
setFiles(files);
});
}, []);
return (
<div className='App'>
{files.map(file => (
<h1 key={file}>{file}</h1>
))}
</div>
);
}
export default App;
Add this to your package.json:
"node-remote": [
"http://localhost:3000",
"file://*"
]
You may also need this:
"eslintConfig": {
"extends": "react-app",
"globals": {
"nw": true
}
}
You cannot use fs module in browser.. it is node core module.

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)

Import methods without using relative path syntax

I want to know more about monorepo projects. I have a repository named dnd which is using Yarn workspaces with Lerna. The repository contains two main directories.
packages/core
packages/app
The core directory contains utility methods and the app directory is using create-react-app boilerplate. Now here is the thing I want to use my utility methods in the main app components something like this.
import { concat } from '#dnd/core';
Currently, I am importing something like this
import { concat } from '../../../core/lib/utils';
I have to traverse the relative path with this ugly syntax. Now the path is correct but create-react-app throwing an error.
Module not found: You attempted to import ../../../core/lib/utils which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
Is there a way we can simply import our core directory methods inside our app components with something like this.
import { concat } from '#dnd/core';
Repositry: Link
dnd/package.json:
{
"name": "root",
"private": true,
"scripts": {
"bootstrap": "lerna bootstrap --use-workspaces"
},
"devDependencies": {
"lerna": "^3.21.0"
},
"workspaces": [
"packages/*"
]
}
dnd/lerna.json:
{
"useWorkspaces": true,
"packages": [
"packages/*"
],
"version": "0.0.0"
}
dnd/packages/core/package.json:
{
"name": "#dnd/core",
"version": "0.0.0",
"description": "> TODO: description",
"homepage": "",
"license": "ISC",
"main": "lib/core.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
}
}
dnd/packages/core/lib/utils.js:
export const concat = (...args) => {
return ''.concat(...args);
};
dnd/packages/app/package.json:
{
"name": "#dnd/rain",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^4.2.4",
"#testing-library/react": "^9.3.2",
"#testing-library/user-event": "^7.1.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
dnd/packages/app/src/components/App.js:
import React from 'react';
import { concat } from '../../../core/lib/utils';
const App = () => {
return (
<div className="App">
{ concat('Hello', 'World', 'Culture') }
</div>
);
};
export default App;
Yes you can.
Disclaimer: I am typing this on the fly (without testing) based on my limited experience on my own monorepo project.
It should give you a great starting point nontheless.
Idea
You would need to compile packages/core using microbundle or rollup into a bundle.
Then you want to include that bundled packages/core as a dependency in packages/app
Setup
packages/core/package.json
microbundle is a devDependency as we only require it during development.
{
"name": "#dnd/core",
"scripts": {
"dev": "microbundle watch lib/*.js --target node"
},
"source": "lib/index.js", // entry point into #dnd/core
"main": "dist/index.js", // the compiled file/bundle that #dnd/app will reference
"devDependencies": [
"microbundle": "^0.13.0"
]
}
packages/app/package.json
We add our compiled core package into package/app
{
"name": "#dnd/app"
"dependencies": [
"#dnd/core": 0.0.0
]
packages/core/lib/index.js
Create an index.js file that will be an export of all your lib functions
This will be your entry point for #dnd/core
export * from './utils.js'
export * from './other-utils.js'
Before Development
Before we start development, we will need to "install" the new depedencies.
lerna bootstrap
Then run the npm dev script
# this will run the npm dev script only for packages/core
cd packages/core
npm run dev
or
# from the root of your project (inside /dnd folder)
# this will do a `npm run dev` equivalent inside all your packages
lerna run dev
This will tell microbundle to watch for changes inside packages/core/lib/index.js
Whenever you change code inside packages/core/lib/utils.js, it will recompile the code into packages/core/dist/index.js
Usages of #dnd/core inside #dnd/app
Now we can import our functions from core in our app source code.
import React from 'react';
import { concat } from '#dnd/core';
const App = () => {
return (
<div className="App">
{ concat('Hello', 'World', 'Culture') }
</div>
);
};
export default App;

Resources