ThorstenHans / ngx-electron

A simple Angular wrapper for electron's Renderer API
MIT License
429 stars 86 forks source link

ipcRenderer always null #30

Closed michaelfoidl closed 5 years ago

michaelfoidl commented 5 years ago

Hi!

I created a new Angular 7 app with angular-cli and added your package, as well as the necessary electron packages. I also wired everything up. However, I was not able to communicate between ipcMain and ipcRenderer. In fact, Electron service always returns null when requesting an instance of ipcRenderer. Is this supposed to work with Angular 7?

bampakoa commented 5 years ago

@michaelfoidl I can confirm that this package works with Angular 7. It would be great if you could share some of your code to help you.

michaelfoidl commented 5 years ago

Since the project I am working on unforntunately is not public, I cannot just share the whole repository. But I'll try my best to sketch the structure.

This is my package.json-File:

{
    "name": "norris",
    "version": "1.0.0",
    "private": true,
    "scripts": {
        "angular:build": "ng build",
        "angular:serve": "ng serve",
        "electron:build": "tsc -p ./src/tsconfig.electron.json",
        "electron:serve": "wait-on http-get://localhost:4200/ && npm run electron:build && electron ./dist/electron/main.js --serve",
        "start": "npm run angular:build && npm run electron:build && electron ./dist/electron/main.js",
        "watch": "npm-run-all --parallel angular:serve electron:serve"
    },
    "dependencies": {
        "@angular/animations": "~7.2.0",
        "@angular/cdk": "^7.3.1",
        "@angular/common": "~7.2.0",
        "@angular/compiler": "~7.2.0",
        "@angular/core": "~7.2.0",
        "@angular/forms": "~7.2.0",
        "@angular/material": "^7.3.1",
        "@angular/platform-browser": "~7.2.0",
        "@angular/platform-browser-dynamic": "~7.2.0",
        "@angular/router": "~7.2.0",
        "core-js": "^2.5.4",
        "guid-typescript": "^1.0.9",
        "jquery": "^3.3.1",
        "material-design-icons": "^3.0.1",
        "ngx-electron": "^2.1.1",
        "rxjs": "~6.3.3",
        "tslib": "^1.9.0",
        "ytdl-core": "=0.29.0",
        "zone.js": "~0.8.26"
    },
    "devDependencies": {
        "@angular-devkit/build-angular": "~0.13.0",
        "@angular/cli": "~7.3.1",
        "@angular/compiler-cli": "~7.2.0",
        "@angular/language-service": "~7.2.0",
        "@types/electron": "^1.6.10",
        "@types/jquery": "^3.3.29",
        "@types/node": "~8.9.4",
        "@types/promise.prototype.finally": "^2.0.3",
        "codelyzer": "~4.5.0",
        "electron": "^4.0.4",
        "electron-builder": "^20.38.5",
        "npm-run-all": "4.1.5",
        "ts-node": "~7.0.0",
        "tslint": "~5.11.0",
        "typescript": "~3.2.2",
        "wait-on": "3.2.0"
    }
}

I have not modified the angular.json file generated by angular-cli.

This is my tsconfig.json-File:

{
    "compileOnSave": false,
    "compilerOptions": {
        "baseUrl": "./",
        "outDir": "./dist",
        "sourceMap": true,
        "declaration": false,
        "module": "commonjs",
        "moduleResolution": "node",
        "noImplicitAny": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "importHelpers": true,
        "target": "es2018",
        "paths": {
            "*": [
                "node_modules/*",
                "src/app/modules/*"
            ]
        },
        "typeRoots": [
            "node_modules/@types"
        ],
        "lib": [
            "es2018",
            "dom"
        ]
    }
}

There are two other tsconfig.json-Files extending this one: One for the electron-Part and one for the angular-Part.

This is the angular-Part:

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
        "outDir": "../dist/app",
        "types": [
            "node"
        ]
    }
}

This is the electron-Part:

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
        "outDir": "../dist/electron",
        "types": []
    },
    "include": [
        "electron/main.ts"
    ]
}

All the angular-specific code is in src\app and all the electron-specific code is in src\electron. I have imported the NgxElectronModule in my AppModule and I am getting an instance of Electron-Service via DI in one of my services that is resolved via DI as well. However, for resolving my internal services I use InjectionTokens in order to be more flexible. In the constructor of the service, I try to access ipcRenderer (isElectronApp is true), but I always get null:

constructor(
        @Inject(ElectronService)
        electronService: ElectronService
    ) {
        this.electronService = electronService;
        if (this.electronService.isElectronApp) {
            console.log(this.electronService.ipcRenderer.sendSync("ping"));   // cannot resolve sendSync of null
        }
    }

I understand that this only works when serving the app inside electron, which I do via npm run watch - still null.

niuwenbo commented 5 years ago

i have some error but also shell is null i used angular 7.2.2 ionic 4.1.1 capacitor beta-19 image

bampakoa commented 5 years ago

@niuwenbo in the attached screenshot I noticed that isElectronApp variable is false.

akjhacse commented 5 years ago

@bampakoa In electron side if we are using webview then we have to enable the nodeintegration and due to that jquery does not work. But if we disable nodeintegration then we are not able to access any electron service in angular.

Below is the code for Electron without nodeintegration:

main.js

`const { app, BrowserWindow, globalShortcut } = require('electron');

let mainWindow;

app.on('ready', () => { mainWindow = new BrowserWindow({ width: 1920, height: 1200, frame: true });

app.on('window-all-closed', function () { app.quit(); })

mainWindow.loadURL('file://' + __dirname + '/index.html'); mainWindow.maximize();

globalShortcut.register('f5', function () { mainWindow.reload(); });

});`

index.html

`

tes app

`

in Angular side everything is null:

`if(this._electronService.isElectronApp){

        alert('ipc ren '+ this._electronService.ipcRenderer);
        alert('webFrame '+ this._electronService.webFrame);
        alert('remote '+ this._electronService.remote);

        if(this._electronService.remote)
        {
            alert('ipcMain '+ this._electronService.remote.ipcMain);

        }
    }`
bampakoa commented 5 years ago

@akjhacse you do not need to disable nodeIntegration for jquery to work, if you import it like below:

<!-- Insert this line above script imports  -->
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>

<!-- normal script imports etc  -->
<script src="scripts/jquery.min.js"></script>       

<!-- Insert this line after script imports -->
<script>if (window.module) module = window.module;</script>

This maybe the case also for @michaelfoidl

michaelfoidl commented 5 years ago

@bampakoa This would not work for me since I do not import third party scripts like JQuery using AngularCLI's the scripts-section, but directly through TypeScript as modules. This means that I cannot influence the order in which the scripts are loaded.

abalad commented 5 years ago

Same issue here

amanitequeen commented 5 years ago

Hello,

I have same issue with a Ionic 4 application, code below

if(this.electron.isElectronApp) {
      console.log("im in electron !");
      let pong: string = this.electron.ipcRenderer.sendSync('store-data');
      console.log(pong);
}

displays "I'm in electron" but then it shows an error "TypeError: Cannot read property 'sendSync' of null"

ohager commented 5 years ago

A question: I had the null problem, too. Enabling nodeIntegration makes it work. But I got a security warning in Developer Tools: Electron Security Warning (Insecure Content-Security-Policy)

Is there a way to make ngx-electron work with nodeIntegration:false?

michaelfoidl commented 5 years ago

I thought the whole point of using ngx-electron was not to enable nodeIntegration...

ohager commented 5 years ago

I thought the whole point of using ngx-electron was not to enable nodeIntegration...

me too, and it's not even documented (at least haven't seen it). But I prefer event-driven over polling (in case of remote) - but maybe I'm doing something wrong, that's why I'm asking

Rekoc commented 5 years ago

Hi everyone,

I got the same error then you guys: image (the 'true' value is from console.log(this._electronService.isElectronApp);) I'm working on Angular 7 and Electron 5. image

EDIT: enabling nodeIntegration fix the issue for me as well.

bampakoa commented 5 years ago

As of Electron version 5.0.0, nodeIntegration is set to false by default. I came across the same error when using Angular 7+ and Electron 5. When I set nodeIntegration: true everything works correctly.

image

VinayJeurkar commented 5 years ago

I faced similar issue, but I fixed it by changing the code from :

win = new BrowserWindow({ 
    width: 1200, height: 800,
});

To:

win = new BrowserWindow({ 
    width: 1200, height: 800,
    webPreferences: {
        nodeIntegration: true,
        backgroundThrottling: false
    }
});
ctchisholm commented 5 years ago

I've noticed that ipcRenderer is always null when I use any version of electron above 4. No matter what I set nodeIntegration to, ipcRenderer is always null. I suspect that this projects needs to be updated to support electron version 5+.

ThorstenHans commented 5 years ago

I've bumped ngx-electron today and compiled it against Electon@6.0.10 in combination with Angular@8.2.x .

Of course works ngx-electon only with nodeIntegration:true. This is due to the age of ngx-electron.

Back in the days when writing ngx-electron, nodeIntegration was true by default. Today, I consult you to dive deeper into Electron and use a custom preload script with tailored API being exposed to the Renderer. However, I fixed and tested the issues reported here. If you enable nodeIntegration, ipcRenderer and others are available as expected @ctchisholm

image

charlesr1971 commented 4 years ago
Angular CLI: 8.3.25
Node: 12.14.0
OS: win32 x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.803.25
@angular-devkit/build-angular     0.803.25
@angular-devkit/build-optimizer   0.803.25
@angular-devkit/build-webpack     0.803.25
@angular-devkit/core              8.3.25
@angular-devkit/schematics        8.3.25
@angular/cli                      8.3.25
@ngtools/webpack                  8.3.25
@schematics/angular               8.3.25
@schematics/update                0.803.25
rxjs                              6.4.0
typescript                        3.5.3
webpack                           4.39.2

Main elements of my directory structure:

electron/main.ts
electron/tsconfig.json
src/app/app.module.ts
src/app/app.component.ts
src/app/app.component.html
src/app/app.component.scss
angular.json
package.json
tsconfig.json

I have added to electron/main.ts:

function createWindow() {
    win = new BrowserWindow({ 
      width: 800, 
      height: 600,
      icon: `file://${__dirname}/dist/assets/images/logo.png`,
      webPreferences: {
        nodeIntegration: true,
      } 
    });
...

But, I still get the error:

TypeError: Cannot read property 'sendSync' of null

I am using the latest version of:

ngx-electron

My package.json:

{
  "name": "color-palette",
  "version": "0.0.0",
  "main": "./electron/dist/main.js",
  "build": {
    "directories": {
      "output": "./dist/"
    },
    "appId": "colorpalette1",
    "category": "colorpalette1.app.color.histogarm",
    "win": {
      "target": "NSIS",
      "icon": "build/icon.ico"
    }
  },
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e",
    "start:electron": "ng build --base-href ./ && electron .",
    "electron-build": "ng build --prod && electron .",
    "dist": "ng build"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~8.2.14",
    "@angular/common": "~8.2.14",
    "@angular/compiler": "~8.2.14",
    "@angular/core": "~8.2.14",
    "@angular/forms": "~8.2.14",
    "@angular/platform-browser": "~8.2.14",
    "@angular/platform-browser-dynamic": "~8.2.14",
    "@angular/router": "~8.2.14",
    "angular-svg-round-progressbar": "^3.0.1",
    "gm": "^1.23.1",
    "got": "^10.6.0",
    "ngx-electron": "^2.2.0",
    "rxjs": "~6.4.0",
    "tslib": "^1.10.0",
    "zone.js": "~0.9.1"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.803.21",
    "@angular/cli": "~8.3.21",
    "@angular/compiler-cli": "~8.2.14",
    "@angular/language-service": "~8.2.14",
    "@types/electron": "^1.6.10",
    "@types/jasmine": "~3.3.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "~8.9.4",
    "codelyzer": "^5.0.0",
    "electron": "^8.1.1",
    "electron-builder": "^22.4.1",
    "electron-packager": "^14.2.1",
    "jasmine-core": "~3.4.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~4.1.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~2.0.1",
    "karma-jasmine-html-reporter": "^1.4.0",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.15.0",
    "typescript": "~3.5.3"
  }
}

electron/tsconfig.json:

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist",
    "sourceMap": true,
    "declaration": false,
    "module": "commonjs",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": ["node_modules/@types"],
    "lib": ["es2018", "dom"]
  }
}

In VSCode, I am then adding the following into the terminal:

npm run start:electron

This works as expected, and opens up a new Chromium window.

I was then told to add:

npm start

Into the Chromium window's DevTool's console

But, I am a little bit confused by the last step?

Much of the code I wrote for this, was taken from the following tutorial:

https://dev.to/michaeljota/integrating-an-angular-cli-application-with-electron---the-ipc-4m18

Here is an image of what happens, when the Chromium window opens:

image

KiamboJyms commented 4 years ago

Hey was getting the same when nodeIntegration was false and set it to true and now after that correction everything is returning undefined.

KiamboJyms commented 4 years ago

Angular version 10 electron version 10 and ngx-electron version 2.2.0

tiapko commented 3 years ago

In my case only isElectronApp is true all other properties are null or ReferenceError

npm 6.14.11 Angular CLI: 11.2.2 Node: 14.15.5 OS: win32 x64 Angular: 11.2.3

function createWindow() {
  mainWindow = new electron.BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true,
      backgroundThrottling: false,
      preload: path.join(
        electron.app.getAppPath(),
        "dist/assets",
        "preload.js"
      ),
    },
  });

  mainWindow.loadURL(
    url.format({
      pathname: path.join(__dirname, `/dist/index.html`),
      protocol: "file:",
      slashes: true,
    })
  );

image

artur-kulik commented 3 years ago

The same issue with angular 11 and ngx-electron 2.2.0

lerchenreich commented 3 years ago

angular11, electron 12.0.7 and ngx-electron 2.2.0

I read the electron documentation and have found out, that the contextIsolation is by default true for securityreasons. contextIsolation must be false and nodeIntegration as already described must be true.

good luck

function createWindow () { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation : false } })

SSYEIP commented 3 years ago

This was the answer I needed. Thank you!

farhadpti commented 3 years ago

angular11, electron 12.0.7 and ngx-electron 2.2.0

I read the electron documentation and have found out, that the contextIsolation is by default true for securityreasons. contextIsolation must be false and nodeIntegration as already described must be true.

good luck

function createWindow () { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation : false } })

the only correct answer for latest versions of electron and angular.

if somone need "electronService.remote" not to be null, also add "enableRemoteModule: true" to "webPreferences"

Arjun021 commented 2 years ago

angular11, electron 12.0.7 and ngx-electron 2.2.0

I read the electron documentation and have found out, that the contextIsolation is by default true for securityreasons. contextIsolation must be false and nodeIntegration as already described must be true.

good luck

function createWindow () { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, contextIsolation : false } })

@lerchenreich I followed this solution but issue is not resolved in Angular version 13.3.3, electron version 19.0.4

I am trying to use desktopCaptures API in app.component.ts

if (this.electronService.isElectronApp) { this.electronService.desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => { // Other logic }); }

The desktopCapture function is coming undefined