require("electron").app is undefined. I npm installed fresh modules. Unsure what to do - node.js

Yesterday, I was developing on Electron perfectly fine. Then I hop onto my computer to realize Electron isn't working at all now.
I removed node_modules and did a fresh npm install
package.json:
...
"devDependencies": {
"devtron": "^1.4.0",
"electron": "^1.4.7"
},
"dependencies": {
"electron-debug": "^1.1.0"
}
...
This is the error I got.
I followed the suggestions used of previous issues of this problem. Nothing is resolving it.
Electron is not installed globally. Everything should be self contained in the directory.
npm list
Most of this code was taken from electron boilerplate
Edit:
main process:
'use strict';
const path = require('path');
const electron = require('electron');
const app = electron.app;
// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')({
showDevTools: true
});
// prevent window being garbage collected
let mainWindow;
function onClosed() {
// dereference the window
// for multiple windows store them in an array
mainWindow = null;
}
function createMainWindow() {
const display = electron.screen.getPrimaryDisplay();
const win = new electron.BrowserWindow({
width: display.workArea.width,
height: display.workArea.height
});
const projectPath = path.dirname(path.dirname(__dirname));
win.loadURL(`file://${projectPath}/static/index.html`);
win.on('closed', onClosed);
return win;
}
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (!mainWindow) {
mainWindow = createMainWindow();
}
});
app.on('ready', () => {
mainWindow = createMainWindow();
});

So, in my case. Issue was resolved by using my original terminal rather than a plugin terminal for Atom.
For anyone out there. Double check with your vanilla terminal or even editor to double check.

Related

Preload script not loading in electron react

I'm building an app with React and Electron and trying to create a communication channel between the main (electron.js in my case) and renderer processes. By achieving this, I want to access the Store object created in my main process to save user preferences etc.
I have set up a preload script and provided the path in my main.js (electron.js). But when I try to access the method defined in the preload.js from the renderer like this window.electronAPI.sendData('user-data', this.state), it does not recognise the electronAPI (undefined variable electronAPI). Also the console.log in my preload.js is never shown when a window is loaded. Hence I assume the preload script never gets loaded and I don't know why. Any help is very much appreciated!
EDIT: The preload script seems to load now because the console.log gets printed. Maybe preload.js did load before too but I could not see it since I could only access the application by opening localhost:3000 in the browser. Now the app opens in a BrowserWindow. However the 'electronAPI' defined in the preload script cannot be accessed still.
Here is the code:
electron.js (main.js)
const electron = require('electron');
const path = require('path');
const {app, BrowserWindow, Menu, ipcMain} = electron;
let isDev = process.env.APP_DEV ? (process.env.APP_DEV.trim() === "true") : false;
function createWindow (){
const win = new BrowserWindow({
width: 970,
height: 600,
backgroundColor: '#0C0456',
webPreferences: {
nodeIntegration: true,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, 'preload.js')
}
});
//if in development mode, load window from localhost:3000 otherwise build from index.html
try {
win.webContents.loadURL(isDev
? 'http://localhost:3000'
: `file://${path.join(__dirname,'../build/index.html')}`
)
} catch(e){
console.error(e)
}
win.webContents.openDevTools({"mode":"detach"});
//Remove menu
Menu.setApplicationMenu(null);
win.once('ready-to-show', () => win.show());
console.log("main window is shown");
console.log(typeof path.join(__dirname, 'preload.js'));
win.on('crashed',() => {
console.error(`The renderer process has crashed.`);
})
}
app.on( 'ready', () => {
createWindow(); // open default window
} );
ipcMain.on('user-data', (event, args)=>{
console.log(args);
});
preload.js
const {contextBridge, ipcRenderer} = require("electron");
const validChannels = ['user-data'];
console.log("this is the preload script");
contextBridge.exposeInMainWorld('electronAPI', {
sendData: (channel, data) => {
if(validChannels.includes(channel)){
ipcRenderer.send(channel, data);
}
}
})

Electron App Not Working With `ffi-napi` Module

I have the following electron code,
//main.js
const e = require("electron");
const ffi = require("ffi-napi");
const user32 = new ffi.Library("user32", {
GetKeyState: ["short", ["int32"]],
});
console.log(user32.GetKeyState(0x06) < 0);
function createWindow() {
let win = new e.BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
});
win.loadFile("index.html");
}
e.app.whenReady().then(createWindow);
My main objective is to access windows.h functions inside an electron application. ffi-node seems to be working fine as a separate node application.
However, when I embed it into an electron app and run electron main.js it looks like it is running for few seconds, then it quits. No error code no nothing. When I try to remove the line const ffi = require("ffi-napi"); and corresponding method call, it seems to be working properly. I've also tried rebuilding the application via electron-builder install-app-deps and it didn't help.
I manage to fix the issue by changing code to this.
const { app, BrowserWindow } = require("electron");
const ffi = require("ffi-napi");
const user32 = new ffi.Library("user32", {
GetKeyState: ["short", ["int32"]],
});
console.log(user32.GetKeyState(0x06) < 0);
var win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
});
win.loadFile("index.html");
}
app.on("ready", createWindow);
And npm install electron -g followed by npm link electron

compile typescript in chatbot

I'm trying to create a chatbot I'm following a tutorial on youtube
https://www.youtube.com/watch?v=cYuWse7GB9E
However at the end of the tutorial you build the typescript using the command Ctrl + Shift + b
my tsconfig.json file looks like this
{
"conpileOnSave":true,
"compileOptions":{
"module":"commonjs",
"target":"es6",
"sourceMap":true,
"declaration":false,
"removeComments":true,
"outDir":"./dist",
"allowJs":true
},
"files":[
"./lib/types.ts",
"./lib/app.ts"
]
}
and my app.ts file looks like this
import { BotFrameworkAdapter, MemoryStorage,ConversationState } from "botbuilder";
import * as restify from "restify";
//import { ConfState } from "./types";
let server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`${server.name} listening on ${server.url}`);
})
const adaptor = new BotFrameworkAdapter({
appId: process.env.MICROSOFT_APP_ID,
appPassword: process.env.MICROSOFT_APP_PASSWORD
});
let conversationState;
const memoryStorage = new MemoryStorage();
conversationState = new ConversationState(memoryStorage);
//const conversationState = new ConversationState(new MemoryStorage());
adaptor.use(conversationState);
server.post("/api/messages",(req,res) => {
adaptor.processActivity(req,res,async(context) =>{
if(context.activity.type === "message") {
const state = conversationState.get(context);
await context.sendActivity(`you said ${context.activity.text}`);
} else {
await context.sendActivity(`${context.activity.type} event detected`);
}
})
});
my problem is that it builds, well doesn't have any errors but nothing is ever built into the "dist" folder so when I then run "node server.js" which contains this code
module.exports = require("./dist/app");
It throws an error
internal/modules/cjs/loader.js:638
throw err;
^
Error: Cannot find module './dist/app'
Has anyone any idea what is wrong. I have changed the permissions on the dist folder to full but still nothing.
thanks
my complete source code can be found here
https://github.com/andrewslaughter/chatbot/tree/master/video2

electron prevent multiple instance with middle click

I am tying to make single instance Electron application.
I am using app.makeSingleInstance , see my sample below.
SingleInstance issue with middle click :
Single Instance works if I click on app.exe 2nd time
It does not work if I middle click on a link inside my app
What I need:
Make electron app singleInstance and ensure it remaisn single instance even with middle click.
I dont want to compeltey disable middle click in my app as at some places, I have a use case for them on non-link items
How to reproduce:
use repo: https://github.com/electron/electron-quick-start
replace existing with my index.html and main.js , see below
npm install and then npm start
index.html:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Hello World!</title></head>
<body>
<h1>app.makeSingleInstance()</h1>
Middle Click on it
</body>
</html>
main.js
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const url = require('url')
let mainWindow
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
if (isSecondInstance) {
app.quit()
}
function createWindow () {
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, '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()
}
})
The middle click does not create a new instance of your application, but rather a new instance of a BrowserWindow. You can disable middle-clicks on a (actually all) elements using the auxclick event.
In your main window's HTML you could put the following JavaScript to disable middle-clicks on link elements if you do not want to redirect these events to your default browser:
// The following function will catch all non-left (middle and right) clicks
function handleNonLeftClick (e) {
// e.button will be 1 for the middle mouse button.
if (e.button === 1) {
// Check if it is a link (a) element; if so, prevent the execution.
if (e.target.tagName.toLowerCase() === "a") {
e.preventDefault();
}
}
}
window.onload = () => {
// Attach the listener to the whole document.
document.addEventListener("auxclick", handleNonLeftClick);
}
But you can also choose to redirect the middle-click events to your standard browser, namely via Electron's shell module:
// Require Electron's "shell" module
const { shell } = require("electron");
function handleNonLeftClick (e) {
// e.button will be 1 for the middle mouse button.
if (e.button === 1) {
// Check if it is a link (a) element; if so, prevent the execution.
if (e.target.tagName.toLowerCase() === "a") {
// Prevent the default action to fire...
e.preventDefault();
// ...and let the OS handle the URL.
shell.openExternal(e.target.href);
}
}
}
// Also attach the listener this time:
window.onload = () => { document.addEventListener("auxclick", handleNonLeftClick); }
You could remove the if (e.button === 1) if you also want to block right-clicks on a elements.

Why is my module not appearing in require.cache?

OS: Windows 10
Node version: 0.10.36
Mocha global version: 1.21.4
I'm attempting to use mocha to unit-test my code, but a local variable inside the code I'm trying to test is persisting between tests, causing problems.
When I look inside require.cache, between tests, I don't see my module in there. It is my understanding that I should be clearing the cache if I want to reset this module between tests.
I made a small node project to demonstrate this issue:
package.js:
{
"name": "cache-test",
"version": "0.0.1",
"dependencies": {
"lodash": "4.5.0"
},
"devDependencies": {
"chai": "1.9.2",
"mocha": "1.21.4",
"mockery": "1.4.0",
"sinon": "1.10.3",
"app-root-path":"*"
}
}
module.js:
var foo = "default value";
exports.init = function(){
foo = 'init';
}
exports.returnFoo = function(){
return foo;
}
test/test-module.js
var chai = require("chai"),
expect = chai.expect,
mockery = require("mockery"),
appRoot = require('app-root-path');
var module;
describe("module", function () {
before(function () {
mockery.enable({ useCleanCache: true });
});
beforeEach(function () {
mockery.registerAllowable(appRoot + "/module", true);
module = require(appRoot + "/module");
});
afterEach(function () {
console.log('deleting', require.cache[require.resolve(appRoot + "/module")]);
delete require.cache[require.resolve(appRoot + "/module")];
module = null;
mockery.deregisterAll();
});
after(function () {
mockery.disable();
});
describe("test",function(){
it("foo should be 'init' after running init()",function(){
module.init();
console.log('foo is ',module.returnFoo());
expect(module.returnFoo()).to.equal('init');
});
it("foo should be 'default value' if init() is not run",function(){
console.log('foo is ',module.returnFoo());
expect(module.returnFoo()).to.equal("default value");
});
});
});
running mocha prints
module
test
foo is init
√ foo should be 'init' after running init()
deleting undefined
foo is init
1 failing
Oh, I needed to add
mockery.resetCache() to my afterEach function. That solved it.
It seems like the useCleanCache option, and deleting the entry from require.cache aren't compatible with each-other, as the former keeps it from appearing in the latter.
So it's either:
Don't use useCleanCache
Delete it "manually" from require.cache
OR
Use useCleanCache
Use resetCache()
but don't attempt to mix and match.

Resources