Access Electron API from a completely different system process - node.js

I am looking for a way to capture a screenshot of a VS Code extension host window. This window is opened when my extension's tests are being run (this is coming from the default Yeoman template for VS Code extensions).
I cannot use my extension's context as the extension only has access to the VS Code API and VS Code runs extensions in a different Node process from the Electron one (main or renderer). IPC is used through the API instead of running extensions in-process.
I can run this code in an Electron renderer process (using DevTools or as a part of the Electron application's script) to capture the Electron window:
const electron = require('electron');
electron.remote.getCurrentWindow().capturePage(image => {
//electron.clipboard.writeImage(image);
electron.clipboard.writeText(image.toDataURL());
console.log('Data URL is in clipboard.');
});
I have verified that placing this in VS Code window DevTools will produce the correct Data URI.
In order to be able to do this from a different Node process, knowing only the Code window PID, I figured I would attach a debugger to the VS Code extension host Electron window and using CDP I would issue a Runtime.evaluate call to run the above code as if it was entered into the DevTools.
However, I am struggling with attaching the debugger. There are generally two ways to do it:
kill -s SIGUSR1 <node-pid> for Unix/macOS
process._debugProcess(proc.pid); for Windows
I am interested in Windows right now, so I issue the Windows line from a new Node process. What should happen upon successful debugger attachment is the target process should print out something like this:
Debugger listening on ws://127.0.0.1:9229/cf49bcfe-d922-4f89-b438-57755d254198
For help see https://nodejs.org/en/docs/inspector
However in my case, this only works if I start the barebones Electron app with --inspect and then issue process._debugProcess(proc.pid);, without --inspect it doesn't throw an error, but doesn't attach the debugger either.

process._debugProcess now works for me with Electron 5.

Related

Invalid Hook Call error when running Next app from PM2

We have an install of Node.js running on a Windows Server 2012R2 web server. A developer created an application for us using Next/React/Node (I'm not a web developer so I'm unsure of the specifics of the various development tools used). This app works fine when manually started on the command line like this:
C:\NodeApps\pacifield>"C:\PROGRAM FILES\NODEJS\NODE.EXE" C:\NodeApps\pacifield\node_modules\next\dist\bin\next start
However this requires someone to manually login and restart the app whenever the server is rebooted or the app stops for whatever reason. I am trying to setup PM2 to run the app. I have it up and running fine until you browse to the app - at which point you get the following error:
next-server.ts:306 Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
at resolveDispatcher (c:\NodeApps\pacifield\node_modules\react\cjs\react.development.js:1476:13)
at useContext (c:\NodeApps\pacifield\node_modules\react\cjs\react.development.js:1484:20)
at useSession (c:\NodeApps\pacifield\node_modules\next-auth\dist\client\index.js:75:39)
at Provider (c:\NodeApps\pacifield\node_modules\next-auth\dist\client\index.js:588:12)
at processChild (C:\NodeApps\pacifield\node_modules\react-dom\cjs\react-dom-server.node.development.js:3353:14)
at resolve (C:\NodeApps\pacifield\node_modules\react-dom\cjs\react-dom-server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (C:\NodeApps\pacifield\node_modules\react-dom\cjs\react-dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (C:\NodeApps\pacifield\node_modules\react-dom\cjs\react-dom-server.node.development.js:3690:29)
at Object.renderToString (C:\NodeApps\pacifield\node_modules\react-dom\cjs\react-dom-server.node.development.js:4298:27)
at Object.renderPage (C:\NodeApps\pacifield\node_modules\next\dist\server\render.js:596:45)
I have checked and there is only the one installation of React in C:\NodeApps\pacifield\node_modules\react and the other suggestions don't seem to make sense when it runs fine outside of PM2. I have checked with ProcessExplorer that all the environment variables are the same (except for the additional ones PM2 adds) when the app is run from the command line vs. PM2.
Anyone have any suggestions?
Hooks can only be call inside of functional component or inside another hook.
take note: Invalid Hook Call Warning
Notify your frontend developer it.

Using command line arguments with ReactJS

I'm wondering if it's possible to use command line arguments with ReactJS (not react-native). For example, is it possible to input a simple string and have it be saved as a variable so it can be displayed? The npm yargs module is the kind of thing I'm looking for, but I couldn't get that to work because the child process it spawns apparently doesn't work in a browser.
Edit: I've also tried something like including {process.argv[0]} in say an h1 tag, but nothing shows up.
React doesn't have anything special for command line arguments. In fact, it is primarily designed as a DOM library. You could use yargs and then pass the values to a React component.
For example you run this command in terminal or cmd
npm start -- foo
foo is your argument.
You can print your like this
// print process.argv
process.argv.forEach(function (val, index, array) {
console.log(index + ': ' + val);
});
in your script.
React runs is client-side
React is a client-side library. It runs in a web page, on a browser. The end-user doesn't use the command-line to "run" React, therefore command-line arguments are not available to the end-user.
For developers
As a developer, you do use tools to start a development server and launch a browser that is running React. Most likely, you're using Create React App. You can use environment variables to pass variables/arguments to React. Specifically, the documentation offers these examples:
# on Linux and macOS
REACT_APP_NOT_SECRET_CODE=abcdef npm start
# on Windows (cmd.exe)
set "REACT_APP_NOT_SECRET_CODE=abcdef" && npm start
Note that these variables are embedded into React at build time, when Create React App bundles and builds your app (kind of like compiling). This means that if you build your React project and then transfer the output files to another server and try to pass new variables, nothing will change.
For servers
If your React build files are on a server and you want to be able to pass command-line arguments to the server and have React change, this is also possible, but largely depends on what software you are using to serve. Broadly, the server would take the runtime argument and pass it into the template which renders your React app. Then any Javascript that runs on that page can access the arguments.

How to inject script using node.js code?

You all know open npm package: https://www.npmjs.com/package/open
Using this package, one can write the following code:
var open = require('./node_modules/open/lib/open.js')
open('http://www.cnn.com')
and activating it by:
$ node app.js
will open a browser window of cnn.com.
I want my script to open this site and inject some code to the console. I mean that the browser will behave like I clicked F12, went to 'console' tab and typed in console the code:
alert('Hello World')
Do you know how to do it?
The open module is used to "Open a file or url in the user's preferred application."
It can open the preferred application (a browser in this case) but it cannot control it. In fact, it doesn't even know what browser will that be (or even if that will be a browser).
What you are asking for can be achieved with tools like PhantomJS ("PhantomJS is a headless WebKit scriptable with a JavaScript API."), Nightmare.js ("A high-level browser automation library.") or CasperJS ("Navigation scripting & testing for PhantomJS and SlimerJS"), see:
http://phantomjs.org/
http://www.nightmarejs.org/
http://casperjs.org/

How to disable the debug remote port in node-webkit desktop app

I wan't to protect the code of my node-webkit desktop application packaged in an exe file.
The problem is not on the file directly but with the dedicated port for remote debugging.
Perhaps I haven't understood something but, on Windows, if I execute a "netstat -a -o" command, I see an open port associated to the application and if I open this port on my browser, I have a page with "Inspectable WebContents" and a link to the webkit application.
With this debug window, it's possible to access to all the sources of the app and I don't know how to disable this feature.
For now, I think there is no actual way to disable remote debugging in nw.js.
Even so, according to the wiki, remote debugging seems to only be executed through the command line switches. Therefore you can block the chromium command line switches (or only --remote-debugging-port) to prevent arbitrary remote debugging by user until nw.js supports disabling functionality of remote debugging.
For instance:
const gui = require('nw.gui');
const app = gui.App;
for (let element of app.fullArgv) {
// app.argv has only user's switches except for the chromium args
if (app.argv.indexOf(element) < 0) {
app.quit(1); // invalid args!
}
}
However, I am not quite sure the above code could protect your application code, because the nw.js is using Chromium internally. So that, the application code would be extracted in temporary folder on initialization. Whereas above solution isn't really protect your nw.js application. See more details: https://github.com/nwjs/nw.js/issues/269
Note: node-webkit has changed name to nw.js

Output to Chrome console from Node.js

I'm looking for a way to output Node variables directly into the google chrome browser console. The same way a console.log() works on the client side. Something like this for php. This would greatly speed up development.
NOTE:
Since the old answer (written in september 2014) refers to an older version of node-inspector, my instructions are not relevant anymore in 2017. Also, the documentation has gotten a lot better, so I have updated my original answer:
node-inspector is what you need.
It opens up an instance of Chrome with its developer tools for debugging.
It's also easy to use:
1. Install
$ npm install -g node-inspector
2. Start
$ node-debug app.js
Source: https://github.com/node-inspector/node-inspector
You might want to try NodeMonkey - https://github.com/jwarkentin/node-monkey
I know it's an old question but came on top of my Google search so maybe somebody will find my answer useful.
So you can use node --inspect-brk index.js
Now, all you have to do is basically just type chrome://inspect in your Chrome address bar and click Open dedicated DevTools for Node
In DevTools, now connected to Node, you’ll have all the Chrome DevTools features you’re used to:
Complete breakpoint debugging, stepping w/ blackboxing
Source maps for transpiled code
LiveEdit: JavaScript hot-swap evaluation w/ V8
Console evaluation with ES6 feature/object support and custom object formatting
Sampling JavaScript profiler w/ flamechart
Heap snapshot inspection, heap allocation timeline, allocation profiling
Asynchronous stacks for native promises
Hope that helped.
The closest thing to this I've seen is Node JS console object debug inspector
See this post for usage and potential issues: http://thomashunter.name/blog/nodejs-console-object-debug-inspector/
For users with nodejs on linux via ssh-shell (putty):
Problem with nodejs on linux-ssh-shell is, that you have no browser connected.
I tried all this solutions, but didnt get it to work.
So i worked out a solution with firebase (https://firebase.google.com), because my project uses firebase.
If you are familiar with firebase, than this is a great way. If not, firebase is worth using in combination with nodejs - and its free!
In the server-side-script (started with node) use a own function log():
// server-side:
// using new firebase v3 !
var fbRootRef = firebase.database();
var fbConsoleRef = fbRootRef.ref("/console");
var log = function(args) {
fbConsoleRef.set({'obj': args});
}
// inside your server-code:
log({'key':'value'});
On client-side you create a firebase-reference on this console-object:
// client side:
fbRootRef.child('/console').on('value', function(d) {
var v = d.val();
console.log(v);
});
Now everything logged on server-side with the log() - function is transferred in realtime to the firebase-database and from there triggering the client-console-reference and logged into the browsers console.
If anyone needs help, i will explain in more detail and could give a more extended version of this logging with types (console./log/warn/info), grouping with title-info (i.e. server says: (filename + line).
Setting up firebase for your project is done in max 30 minutes, inserting the console-function in 30 minutes. I think its worth the time!
You can use bonsole, a simple way to log something in browser. Even in Linux, you can go to the LAN's ip to check it.
The most simple way with least dependencies is using a WebSocket connection to send the messages to the browser. Any WebSocket example you can find on the internet will suffice to accomplish this. Everything else requires to be heavily integrated into the host system and wouldn't work if you want to actually run this on a remote server. You can also send commands to the server directly from the browser console this way.
Links:
https://www.npmjs.com/package/websocket
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications

Resources