javascriptnode.jstypescriptpuppeteeres6-modules

'this' is Undefined in Instance Methods when Importing Puppeteer Inside a Module


I am running into an issue with Puppeteer where 'this' is undefined within the Puppeteer class instance methods when Puppeteer is imported into a module.

When I import Puppeteer directly in my main script, everything works as expected. However, as soon as I try to import and use Puppeteer within a separate module, I get the following error:

TypeError: Cannot read properties of undefined (reading '#defaultContext')
    at newPage (/node_modules/puppeteer-core/lib/esm/puppeteer/cdp/Browser.js:173:27)

Upon closer inspection, it appears that this is undefined inside of the browser.newPage() instance method whenever Puppeteer is imported within a module.

I have tried tweaking the allowSyntheticDefaultImports, esModuleInterop, module and moduleResolution compiler options in my tsconfig.json to no avail. I also tried importing Puppeteer using the import puppeteer from "puppeteer", import * as puppeteer from "puppeteer", and import puppeteer = require("puppeteer") syntaxes and am running into the same problem in all three situations.

While manually binding this when invoking the instance method appears to be a workaround (e.g., browser.newPage.bind(browser)), you seemingly have to do so every time you call any instance methods of Puppeteer's classes.


Solution

  • When trying to create a minimal reproducible example as suggested by trincot and ggorlen, I took another look at my original code and realized that the cause of the issue was having a helper function invoke the Puppeteer instance methods without binding this when calling them. Whether or not I was using Puppeteer within a module turned out to be irrelevant.

    E.g.,

    // I was doing this
    function callMethod (func, ...args) {
       func(...args);
    }
    callMethod(browser.newPage);
    
    // And what I really needed to do was something like this
    function callMethod (obj, method, ...args) {
       obj[method].call(obj, ...args);
    }
    callMethod(browser, 'newPage');
    

    During my original troubleshooting, I replaced the first couple calls to callMethod() with a direct call to the respective Puppeteer instance method but left all of the other calls to callMethod() intact, obscuring the fact that callMethod() was the true culprit all along.

    Lesson learned: Always make a minimum reproducible example, no matter how "simple" you believe your existing code is.