Node's and Electron's modules from inside Angular2 - node.js

I am developing an Electron application using Angular2.
In the electron's main.js I am referencing/loading the NG App:
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')
let win
function createWindow () {
win = new BrowserWindow({width: 800, height: 600})
// load the index.html of the NG app:
win.loadURL(url.format({
pathname: path.join(__dirname, '/../../dist/index.html'),
protocol: 'file:',
slashes: true
}))
[...]
This works like a charm. However, I'd now like to access node's and electron's modules from inside the NG part.
When I try to import e.g.: the fs module like:
import * as fs from "fs";
It still compiles but whenever I call fs.readFile(...) it says:
__WEBPACK_IMPORTED_MODULE_2_fs__.readFile is not a function
When I think about it, this does not and can not work since the modules are not inside the node_modules folder (right?).
What do I need to do to make them available inside the NG part?

In case this is still relevant -
I don't know of an "official" way for this yet. but there are work-around solutions - mainly around requiring electron/other modules in index.html and accessing window['electron'] -
<script>
window.electron = require('electron');
</script>
or creating an angular services accessing the electron object.
declare const window: ElectronWindow;
export class ChildProcessService {...}
You can see an implementaion of this Here
ElectronWindow refers to a custom interface you can create and add a require() function to for handling typings.
use window.require(*some-node-module*) to store modules

You cannot call Electron / Node modules directly from inside Angular. Instead, check out the Electron remote API.

Related

GraphQL Tools loadFilesSync works for runtime but not jest in NodeJS - why?

I am working on setting up an Apollo GraphQL Server (Express based) and use the pattern where .graphql files are loaded and merged as demonstrated in this guide. This leads me to use loadFilesSync, path and the Node provided __dirName.
My typedefs module looks like this
const path = require('path');
const { loadFilesSync } = require('#graphql-tools/load-files');
const { mergeTypeDefs } = require('#graphql-tools/merge');
const schemaDefsArray = loadFilesSync(
path.join(__dirname, './types'),
{
recursive: true,
extensions: ['graphql'],
})
const typeDefs = mergeTypeDefs(schemaDefsArray);
module.exports = typeDefs;
My setup is a docker container built from a repo checked out to the WSL file system in Windows. Both the Apollo/Express server and Jest tests are run on Node from inside that container.
My problem is that during regular runtime (Express based Apollo GraphQL Server), __dirName is /srv/<project name>/src/schema and all .graphql-files are resolved for the schema as intended. But during test-runs (Jest running directly on Node) __dirName is a fully qualified \\wsl$\Ubuntu-20.04\home\<user name>\projects\<project name>\src\schema. The Apollo Server loads, reads, and resolves the schema fine while Jest tests attempting to load the same files through the same module cannot find the directory.
Why is the working directory resolved differently, what does it mean for the loadFiles function and how do I fix this?

TypeError: Cannot read property 'getAppPath' of undefined

We're using Electron "electron": "^5.0.2"
The code that is having the error is in the main process. It calls our backend services. I was trying to add a constant for the API path the same way we were including constants elsewhere (note: the solution here might be to use an environment variable). The issue is that electron is giving a error when it is trying to access the appPath() method. This same code works elsewhere in the app.
TypeError: Cannot read property 'getAppPath' of undefined
const {app} = require('electron');
const path = require('path');
const constants = require(path.join(app.getAppPath(), 'src/constants'));
When the browser window is created we're setting nodeIntegration to true
window = new BrowserWindow({
webPreferences: {nodeIntegration: true}
});
Try:
const app = require('electron')
app.remote.app.getPath()
If that doesn't work you should try checking if main.js is:
included in package.json
NOT being required by your frontend JS or index.html
of course, make sure electron is installed as a dev dependency
if you are running into while trying to packaging the app you should run the code that uses app in a conditional, app isn't available while packaging but will be available in the prod

How to resolve fs.existsSync is not a function

In NodeJS I have:
const fs = require('fs');
if (!fs.existsSync("some_path")) {
...
}
But I get the error:
TypeError: fs.existsSync is not a function
After doing some searching, I read that Webpack brings its own require which clobbers node.js's require, so when you require a node.js core module that webpack can't resolve to one of your files or dependencies, it throws.
(My stack trace includes __webpack_require__)
But how can I fix it?
I was facing the same Error like TypeError: fs.existsSync is not a function
So, I figured out that one extra line was added automatically which was creating this issue in import.
after removing this line from import
import { TRUE } from "node-sass";
the issue has been resolved.
I had the same error that you have. Your vscode might have added a new module to your js file. Remove that module and your app should work just fine.
You can allow webpack to use the Node's require and include fs etc. by targeting node in the config:
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
path: path.join(__dirname, 'build'),
filename: 'backend.js'
}
}
As described here: https://webpack.js.org/concepts/targets/ and https://webpack.js.org/configuration/target/
I was working on an electron application, I wanted to send a message from node and get in on the react side, but I was having that same issue when requiring ipcRenderer from electron, I tried
import { ipcRenderer } from 'electron';
and
const { ipceRenderer } = require('electron') This leads to an error due to webpack transforming node's require to its own webpack_require. See more info here
What worked for me was to use
const {ipcRenderer} = window.require('electron'); on the react side/renderer side from electron
In my case, I forgot that I'd only imported the promises API, const fs = require("fs").promises, which doesn't have exist or existsSync functions in Node 17.4.0.
To use exist or existsSync, make sure you've imported fs using the sync API (const fs = require("fs")).
Note: I'm adding this answer as a possible solution for future visitors to a canonical thread for the error, not OP who appears to have required fs correctly.
It is nothing to worry about, check your code for something like import { types } from "node-sass";, it would have mistakenly and automatically imported without you know. Remove that line, and everything should work perfectly.
Even if it is not type, it is something from node-sass in your node_modules file, and you can't edit that file.
So look for and remove import { types } from "node-sass"
In my case VSCode added a arbitrary import from electron. After removing it my application worked.
import { Menu } from 'electron';
In my case, i needed to send a message from the node to react. I tried importing ipcRenderer from 'electron'; and const ipceRenderer = require('electron') This results in an error owing to webpack changing the node's require to its own webpack require. See more info here

Requiring runtime app files from a node library with webpack

I'm working on a Node.js library that's already in production, and we are implementing Webpack to use babel-loader. I'm using webpack-node-externals to leave external requires unresolved until runtime.
The thing is, at some points the library need information about the app that is using it, and so far it's bee requiring it using the following:
const basepath = process.cwd();
const pkg = require( path.join( basepath, 'package.json' ) );
const packageVersion = pkg.version;
This has been working fine so far, since process.cwd() resolves to the working directory of the app that is running the library. But when ebpack reaches this require, it tries to resolve it and replaces it with a webpackMissingModule error.
Is there a way to leave this require as it is until runtime? I tried using the externals property with no luck.

browserify bundle electron app main process file

I am building a electron app and currently using browserify for the renderer (web page) files like any other javascript front end. I would like to also use browserify to bundle the main process files. However, browswerify is unable to find the electron built in modules like clipboard, ipc, browser-window, app, etc...
In my main.js file which serves as the entry point for the electron app. I have:
const ipc = require('ipc');
const clipboard = require('clipboard');
const BrowserWindow = require('browser-window');
const app = require('app');
const yargs = require('yargs');
the const yargs loads fine as it is in the node_modeuls folder and browserify can resolve that. However the othe four items cannot be found by browserify and therefore fail my build.
[11:49:17] Finished 'development' after 17 ms
Error: Cannot find module 'ipc' from '<path>'
Error: Cannot find module 'clipboard' from '<path>'
Error: Cannot find module 'browser-window' from '<path>'
Error: Cannot find module 'app' from '<path>'
Any suggestions?
With browserify you can set the options 'ignoreMissing' and 'detectGlobals' which allow browserify to ignore built int modules that eventually get loaded automatically in the electron app.
browserify({
entries: './src/main.js',
extensions: ['.js'],
ignoreMissing: true,
detectGlobals: false,
bare: true,
debug: false
})

Resources