0

I'm writing a Chrome Extension that downloads files from a web page. I want the extension to track which files have already been downloaded. For the purpose of reasonable code management, I would like the object to exist in its own Javascript file.

How do I make that class definition available to a request to scan the page?

The error message:

Making DL Tracker: undefined
VM1232:4 Uncaught TypeError: window.DLTracker is not a constructor
    at processThatPage (<anonymous>:4:17)
    at <anonymous>:5:3

The class file (lib/externalclass.js):

window.DLTracker = class DLTracker {
    constructor()
    {
        console.log("constructing the external class");
    }
};

The file that's trying to import the class (lib/processpage.js):

export function processThatPage() {
    let dltracker;
    console.log("Making DL Tracker: " + window.DLTracker);
    dltracker = new window.DLTracker();
}

The entry point: automata.js

import { processThatPage } from "./lib/processpage.js";

chrome.runtime.onInstalled.addListener(() => {
  chrome.tabs.onUpdated.addListener( pageLoadCheck);
});

async function pageLoadCheck(tabId, changeInfo, tab) {
    if (changeInfo.status === 'complete' && tab.url.startsWith("https://www.target.net/path"))
    {
>>>> I'm sure I have to do something here to install the object. This didn't work. What does?
        chrome.scripting.executeScript(
        {
            target: { tabId: tab.id },
            files: ["./lib/externalclass.js"]
        });
        chrome.scripting.executeScript(
        {
            target: { tabId: tab.id },
            func: processThatPage
        });
    }
}

Just for completeness, the manifest (manifest.json):

{
  "name": "My Automator",
  "description": "What I'm trying to accomplish",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "automata.js",
    "type": "module"
  },
  "permissions": ["storage", "tabs", "scripting", "downloads", "alarms"],
  "host_permissions": ["http://*.target.net/*", "https://*.target.net/*"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/get_started16.png",
      "32": "/images/get_started32.png",
      "48": "/images/get_started48.png",
      "128": "/images/get_started128.png"
    }
  },
  "icons": {
    "16": "/images/get_started16.png",
    "32": "/images/get_started32.png",
    "48": "/images/get_started48.png",
    "128": "/images/get_started128.png"
  },
  "options_page": "options.html"
}

Thank you!

Robert Rapplean
  • 672
  • 1
  • 9
  • 30
  • You need to make it global e.g. `window.DLTracker = class DLTracker { ... }` – wOxxOm Jan 31 '23 at 03:26
  • @wOxxOm, I tried that, but that didn't work, either. I updated the question with that attempt just to eliminate that possibility. It's like 'window' isn't the same variable in the two, like they're running in different sandboxes. – Robert Rapplean Jan 31 '23 at 16:16
  • Remove `world` from executeScript. Generally you should never use `MAIN` (it's highly unsafe) unless you specifically want to access JS stuff from the page, in which case you should inject only that code ([example](https://stackoverflow.com/a/46870005)), not the entire script. – wOxxOm Jan 31 '23 at 16:19
  • I removed world, but that didn't change the results. Sorry for the distraction. – Robert Rapplean Jan 31 '23 at 16:53
  • 1) Try adding await on the first executeScript. 2) Since it works in vanilla JS, the problem may be caused by your build settings, so try inspecting/debugging the final code in devtools. – wOxxOm Jan 31 '23 at 18:21
  • await did the trick. Thank you! – Robert Rapplean Jan 31 '23 at 18:35

0 Answers0