1

My goal is to open puppeteer-chromium instance as a child process in nodejs environment and listen to all clicks that user will make in a way that these events are accessible from parent process. So I think stream of events is needed but I have no idea how to send them from evaluate method (process object is not accessible in that context - 'process is undefined' in logs of chromium).

Currently I'm trying to add click listener inside page's context but is there any way to obtain those events outside of evaluate method?

I know evaluate method can return promise but it's only one value so it's not enough. I'd like to gather all clicks until I close chromium window.

Thanks in advance for all kind of advices.

My sample code:

  // parent.js
  const child = require('child_process');
  const childprocess = child.fork('./childprocess.js');
  childprocess.on('message', (msg) => {
      console.log('Message from child', msg);
      // here I'd like to get click events from childprocess
      // eg. saving them in database
  });

  // childprocess.js
  const puppeteer = require('puppeteer');
  (async () => {
      await process.on('message', (m) => {
        process.send(m)
      })
      const browser = await puppeteer.launch(options);
      const page = await browser.newPage();
      await page.goto('http://someurl.com');
      await page.evaluate( (processHandle) => {
        document.addEventListener('click', (event) => {
          console.log(event);  // event is logged in chromium dev console
          processHandle.send({msg: event}); // nothing happens
        })
      }, process);
  })()
Hagalaz
  • 109
  • 3
  • 14
  • 1
    *I'd like to gather all clicks* - how many are there, where are they and how is the script supposed to know that that there will be no more? That's the problem here. A promise is supposed to be finished with time. A stream of DOM events isn't. You probably have XY problem. Consider explaining your case in details instead of investigating potentially wrong solution. – Estus Flask Jul 04 '18 at 22:42
  • `You probably have XY problem. Consider explaining your case in details instead of investigating potentially wrong solution` — Can't agree more. Please add details of what you want to accomplish – Vaviloff Jul 05 '18 at 10:02
  • @estus I've tried to explain it more, tell me if this is clear to understand. – Hagalaz Jul 05 '18 at 13:28
  • So clicks are supposed to be done by a user. What do you intend to use them for in parent process? Please, post the entire (pseudo)code that is related to clicks, this may help to understand your case. – Estus Flask Jul 05 '18 at 13:32
  • @estus Now you should have some bigger picture I think. – Hagalaz Jul 05 '18 at 21:05

1 Answers1

1

The issue with the sample code is that processHandle won’t be serialized in such a way that JavaScript in the context of the document can use it. You can instead expose a function on window that will do what you want:

await page.exposeFunction("sendEventToProcessHandle", (event) => {
    processHandle.send({ msg: JSON.parse(event) });
})

await page.evaluate((processHandle) => {
    document.addEventListener('click', function (e) {
        window.sendEventToProcessHandle(JSON.stringify(e));
    });
}, process)

Here, window.sendEventToProcessHandle is a function that will run in the context of the Node.JS process, where you can access processHandle, but can be called by the document.

Aankhen
  • 2,198
  • 11
  • 19
  • Not exactly worked but I've managed to pass process object by using it in 'exposeFunction'. There is one problem left. In chromium I logged out whole event eg. MouseEvent {isTrusted: true, screenX: 152, screenY: 266, clientX: 130, clientY: 107, …} but after sending to parent there is only {isTrusted:true} – Hagalaz Jul 06 '18 at 22:20
  • Odd. If it were mangling native objects I could understand that but numbers are serializable. If you log `event` inside `sendEventToProcessHandle`, is it still missing those fields? – Aankhen Jul 07 '18 at 10:05
  • No @Aankhen, after sending event to puppeteer's context it gets smaller. All fields of event are accessible only from evaluate context. – Hagalaz Jul 07 '18 at 13:35
  • I’ve updated the answer to include JSON-ification. Could you see if that works? – Aankhen Jul 07 '18 at 16:20
  • Yes, I've tried that and does not work, it's related with serialization problem regarding events. I will just choose needed properties and send them as separate object. – Hagalaz Jul 07 '18 at 22:15
  • I see. That solution makes sense. – Aankhen Jul 08 '18 at 11:50