Unable to load react dev tools in electron - javascript

I'm trying to load React and Redux dev tools in electron, so far Redux was loaded successfully, but React was not. I didn't see the React tab in Developer Tools. Here is my code:
main.js
const electron = require("electron");
const path = require("path");
const url = require("url");
const os = require("os");
const { app, BrowserWindow } = electron;
let win;
const installExtensions = async () => {
const ses = win.webContents.session;
// react dev tools
ses.loadExtension(
path.join(
os.homedir(),
".config/google-chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/4.9.0_0"
)
);
// redux dev tools
ses.loadExtension(
path.join(
os.homedir(),
".config/google-chrome/Default/Extensions/lmhkpmbekcpmknklioeibfkpmmfibljd/2.17.0_0"
)
);
};
const createWindow = async () => {
win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
},
});
win.maximize();
await installExtensions();
win.loadURL(
url.format({
pathname: path.join(__dirname, "index.html"),
protocol: "file:",
slashes: true,
})
);
win.webContents.once("dom-ready", () => {
win.webContents.openDevTools();
});
win.on("closed", () => {
win = null;
});
};
app.on("ready", createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
if (win === null) {
createWindow();
}
});
package.json
{
"name": "electron-react-typescript",
"version": "0.0.7",
"description": "",
"main": "/main.js",
"scripts": {
"start": "electron main.js"
},
"dependencies": {
"electron": "^10.1.5",
"electron-builder": "^22.9.1"
}
}
I started the program using yarn start, here is the output:
yarn run v1.22.10
warning package.json: No license field
$ electron main.js
(node:8189) ExtensionLoadWarning: Warnings loading extension at /home/searene/.config/google-chrome/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/4.9.0_0: Unrecognized manifest key 'browser_action'. Unrecognized manifest key 'minimum_chrome_version'. Unrecognized manifest key 'update_url'. Cannot load extension with file or directory name _metadata. Filenames starting with "_" are reserved for use by the system.
(node:8189) ExtensionLoadWarning: Warnings loading extension at /home/searene/.config/google-chrome/Default/Extensions/lmhkpmbekcpmknklioeibfkpmmfibljd/2.17.0_0: Unrecognized manifest key 'commands'. Unrecognized manifest key 'homepage_url'. Unrecognized manifest key 'page_action'. Unrecognized manifest key 'short_name'. Unrecognized manifest key 'update_url'. Permission 'notifications' is unknown or URL pattern is malformed. Permission 'contextMenus' is unknown or URL pattern is malformed. Permission 'tabs' is unknown or URL pattern is malformed. Cannot load extension with file or directory name _metadata. Filenames starting with "_" are reserved for use by the system.
I saw Redux in the developer tools, but I didn't find React. According to this github issue, the above warnings shouldn't block the loading of dev tools. I also tried re-opening dev-tools, no luck. How to solve it?

under webPreferences add
contextIsolation: false
for the loadExtension function add { allowFileAccess: true } as a 2nd argument.
That should make it work, as they changed the default of contextIsolation to be true in some version (I think 9.0.0),
and added allowFileAccess as an extention loading option for security.
You can make an isDev boolean to use for setting the allowFileAccess if needs be.

Related

"Failed to parse source map" - Electron React app crashes

I am new to coding. And trying to make an electron app with react. In the app I want to save user login information in the app so that I can automatically fetch the data when the app launches. So, I am using electron-settings to save the data.
code sample:
app.jsx
...
import setting from "electron-settings";
function App() {
...
useEffect(() => {
const getUser = async () => {
return await setting.get('xpass-user')
}
console.log(getUser());
}, [])
return ...;
}
export default App;
electron.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const url = require('url')
const isDev = require('electron-is-dev')
function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 1250,
height: 900,
titleBarStyle: "hiddenInset",
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
}
})
win.loadURL(
isDev
? 'http://localhost:3000'
: url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
})
)
win.webContents.openDevTools();
}
app.on('ready',createWindow)
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
the error:
ERROR in ./node_modules/electron-settings/dist/settings.js 166:27-40
Module not found: Error: Can't resolve 'fs' in
'C:\Users\learner\app\node_modules\electron-settings\dist'
ERROR in ./node_modules/electron-settings/dist/settings.js 170:29-44
Module not found: Error: Can't resolve 'path' in
'C:\Users\learner\app\node_modules\electron-settings\dist'
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: { "path": require.resolve("path-browserify") }'
install 'path-browserify' If you don't want to include a polyfill, you can use an empty module like this: resolve.fallback: { "path":
false }
ERROR in
./node_modules/electron-settings/node_modules/mkdirp/lib/find-made.js
3:4-19
Module not found: Error: Can't resolve 'path' in
'C:\Users\app\node_modules\electron-settings\node_modules\mkdirp\lib'
If anyone can help me I'd be grateful. Thank You
Module not found: Error: Can't resolve 'fs' in...
In create-react-app, they have stubbed out 'fs'.You cannot import it. They did this because fs is a node core module.
Add the following to the root of the "package.json" file.
"browser": {
"fs": false,
"path": false,
"os": false
}
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.
to resolve this issue check this question How to Polyfill node core modules in webpack 5

Window does not render on build, works fine in development server

My app does not display a window when it's built, but works fine when I run npm run serve
There is still an process running in task manager, and the same thing happens if I use the installer. I don't get any errors warnings from electron-builder.
background.js:
import { app, protocol, dialog, BrowserWindow, ipcMain, shell } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
import path from 'path'
import fs from 'fs'
import childProcess from 'child_process'
import ncp from 'ncp'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
function createWindow () {
// Create the browser window.
win = new BrowserWindow({
width: 1200,
height: 600,
resizable: false,
maximizable: false,
frame: false,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
preload: path.join(__dirname, 'preload.js')
}
})
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL(path.join(__dirname,'index.html'))
}
win.on('closed', () => {
win = null
})
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 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 (win === null) {
createWindow()
}
})
I tried the fixes here and here to no avail.
I'm using electron-vue. You can find the full code here if you need more context
The issue ended up being code present inside of the app.on('ready') function. Any additional code needs to be written after the window is created, or the issue occurs.

Electron app does not function properly after built into an exe file

I have just finished working on a test project in electron. The problem is that when I package the app using an electron-packager into an executable, my main.html file does not load up in the window.
However, when I run with npm start it works absolutely fine. I have checked if there is any mistake in the path to my files but that's absolutely fine as well.
Here's my package.json file -
{
"name": "test",
"version": "1.0.0",
"description": "Just a test app",
"main": "src/main.js",
"scripts": {
"start": "electron ."
},
"author": "Ray",
"license": "MIT",
"devDependencies": {
"electron": "^9.0.5"
},
"dependencies": {
"electron-packager": "^15.0.0"
}
}
Here is my main.js
const { app, BrowserWindow } = require('electron')
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('./app/main.html')
}
// 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', () => {
// 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()
}
})
Any help will be appreciated. Thanks.
First of all electron-packagershould be part of devDependencies, not dependencies.
Second: How do you pack? If you use an asar File you need to look at the Paths. Those change when packing. So I'd recommend you use something like
win.loadURL(`file://${__dirname}/main.html`)
or
win.loadURL(url.format({
pathname: path.join(__dirname, 'main.html'),
protocol: 'file:',
slashes: true
}));
when loading your html.

How to properly package Electron + Angular-cli 9?

My question is because I have been seeing how to do it for a long time and the first few times it worked, but lately I have had many problems.
I have seen several Blogs on how to link Electron with Angular but it always happens to me that I have errors with the main.js in the loadURL
const { app, BrowserWindow } = require('electron');
const url = require("url");
const path = require("path");
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
title: 'frontend',
backgroundColor: '#ffffff',
webPreferences: {
nodeIntegration: true
}
});
mainWindow.maximize();
mainWindow.webContents.openDevTools();
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, `/dist/index.html`),
protocol: "file:",
slashes: true
})
);
mainWindow.on('closed', function () {
mainWindow = null
});
}
app.on('ready', createWindow);
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
})
app.on('activate', function () {
if (mainWindow === null) createWindow();
})
I have already made the changes that videos and pages usually say about this as
Editing the package.json with "main": "main.js",
Put the dot in <base href ="./">
In angular.json projects> appName> architect> build> options> outputPath change it to "outputPath":"dist", without the project title
All of the above works until the time of packaging.
For what several mention using "electron-packager":"^14.2.1",
From a simpler command like
    "packager": "electron-packager. --platform = win32 --out dist / --overwrite"
Where first of all, it generates an error with pathname: path.join (__ dirname, 'dist / index.html'), because it locates it somewhere else and I have to change dist / for src /
What the exe generates but at the moment of starting only the <app-root> </app-root> tag appears without the angular scripts, that is, an empty page
And others post to create the package.json script like:
"electron-package": "ng build --prod && electron-packager. --no-prune --ignore=/node_modules --ignore=/e2e --ignore=/src --overwrite"
or
"electron-package": "ng build --prod --base-href ./ && electron-packager. --no-prune --ignore=/e2e --ignore=/src --overwrite"
That the latter I think does not generate the index.html: c
Does anyone know a Definitive process with Anglar-cli and Electron?

preload script not loaded in packaged app

I've made a small Electron app which needs to load a preload js file.
When I start the app with electron ., it finds the file, but when the app is packaged, it doesn't.
The call is made here:
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
nativeWindowOpen: true,
webSecurity: false,
preload: path.join(__dirname, 'preload.js')
}
})
My simplified package.json:
"name": "app",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron .",
"build": "electron-packager . --platform=win32 --arch=x64 --overwrite"
}
"devDependencies": {
"electron": "^1.8.4",
"electron-packager": "^12.0.1",
}
My project structure:
- node_modules
- main.js
- preload.js
- package.json
I've checked the result of the path.join and in both cases, the path is correct, and the file is there.
For peoples using Electron Forge webpack typescript boilerplate :
Add the preload key in package.json file:
{
"config": {
"forge": {
"plugins": [
[
"#electron-forge/plugin-webpack",
{
"mainConfig": "./webpack.main.config.js",
"renderer": {
"config": "./webpack.renderer.config.js",
"entryPoints": [
{
"html": "./src/index.html",
"js": "./src/renderer.tsx",
"name": "main_window",
"preload": {
"js": "./src/preload.ts"
}
}
]
}
}
]
]
}
}
}
Preload script can be a typescript file.
Add MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY constant as value for preload:
// Tell typescript about this magic constant
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: any;
// [...]
const mainWindow = new BrowserWindow({
height: 1000,
width: 1500,
webPreferences: {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY,
}
});
In preload.ts write :
import {
contextBridge,
ipcRenderer
} from 'electron';
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
Add index.d.ts file, write :
declare global {
interface Window {
electron: {
doThing(): void;
}
}
}
Start your app, in your dev console you can type electron and view it is defined.
BONUS: getting the typing right for the contextBridge exposed API:
Why a separated fie ? Not sure if needed, but I prefer not having to import an interface from a file that contain main process code (like preload.ts) in renderer process.
// exposed-main-api.model.ts
export interface ExposedMainAPI {
doThat(data: string): Promise<number>;
}
// index.d.ts
declare global {
interface Window {
electron: ExposedMainAPI
}
}
// preload.ts
import {
contextBridge,
ipcRenderer
} from 'electron';
const exposedAPI: ExposedAPI = {
// You are free to omit parameters typing and return type if you feel so.
// TS know the function type thanks to exposedAPI typing.
doThat: (data) => ipcRenderer.invoke('do-that-and-return-promise', data)
};
// note: this assume you have a `ipcMain.handle('do-thing-and-return-promise', ...)`
// somewhere that return a number.
contextBridge.exposeInMainWorld('electron', exposedAPI);
Credits:
#deadcoder0904 that gave us the solution in an comment to a previous answer, here is the github issue he link : https://github.com/electron-userland/electron-forge/issues/1590
index.d.ts typing and small example usage of contextBridge: https://github.com/electron/electron/issues/9920#issuecomment-743803249
See also:
Explanations about security and also an example of using IPC: https://github.com/electron/electron/issues/9920#issuecomment-575839738
Preload script needs to be specified as an absolute path. Thus it will differ from the time you're running it in development versus running it packaged as an asar file.
const getSourceDirectory = () => isDev()
? path.join(process.cwd(), 'build', 'src') // or wherever your local build is compiled
: path.join(process.resourcesPath, 'app', 'src'); // asar location
const preload = path.resolve(getSourceDirectory(), 'preload.js');

Categories