14

I'm having a problem importing the file "score.js" that is in same library of the "background.js" (scripts libary). I'm new to both js and chrome extensions. I looked into require.js and did this.

Background.html:

<!doctype html>
<html>
  <head>
    <title>Tab Manager</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  </head>
  <body>
    <h1>Tab Manager</h1>
    <script data-main="scripts/score.js" src="scripts/require.js"></script>
  </body>
</html>

background.js:

// gets a dictionary of existing windows ids as keys and tab arrays as values.
function get_windows() 
{
    var window_dict = {};
    chrome.windows.getAll({populate:true}, windowArr =>{
        var i;
        for (i = 0; i < windowArr.length; i++) {
            var window = windowArr[i];
            var window_id = window.id;
            var tabs = window.tabs;
            window_dict[window_id] = tabs;
          }
        console.log(window_dict);
        main(window_dict);
    })
    
}

function starting_scores(window_dict)
{
    var scores = [];
    var i;
    var j = 0;
    var total_tabs = [];
    for (const [window_id, tabs] of Object.entries(window_dict)) {
        for (i = 0; i < tabs.length; i++){
            scores[j] = new Score(tabs[i], window_id);
            j = j++;
        }}
    return scores;
}

function main(window_dict)
{
    var scores = starting_scores(window_dict);
    console.log(scores);
}

get_windows();

score.js:

class Score
{   
    // Constructor
    constructor(tab, window_id)
        {
        this.window_id = window_id; // The window id of the window that contains the tab.
        this.tab = tab; 
        this.url = tab.url;
        this.active = tab.active; // If the tab is currently looked at then it's active.
        this.audible = tab.audible; // If the tab is playing audio then audible will be true.
        this.discarded = tab.discarded; // If the tab is already unloaded but not closed this will be true.

        /* If the new tab is active then the timer is set to zero because 
        the user hasn't spent any time not using the tab. Otherwise a timer starts. */
        if(this.active == true){
            this.timer == 0;}
        else{
            this.timer = performance.now;}
        }
    
    // Get methods
    getWindowId() {
        return this.window_id;
    }
    getTab() {
        return this.tab;
    }
    getUrl() {
        return this.url;
    }
    getActive() {
        return this.active;
    }
    getAudible() {
        return this.audible;
    }
    getDiscarded() {
        return this.discarded;
    }
    getTimer() {
        return this.timer;
    }

    // Set methods
    setWindowId(window_id) {
        this.window_id = window_id;
    }
    setTab(tab) {
        this.tab = tab;
    }
    setUrl(url) {
        this.url = url;
    }
    setActive(active) {
        this.active = active;
    }
    setAudible(audible) {
        this.audible = audible;
    }
    setDiscarded(discarded) {
        this.discarded = discarded;
    }
    setTimer(timer) {
        this.timer = timer;
    }
}

I'm trying to build an extension that makes a score for usage for each tab and then removes the ones with low score. Don't mind the logic I just can't get score.js to work in background.js

Any help is apreciated.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
CodeSlayer55
  • 141
  • 1
  • 1
  • 4

2 Answers2

18

An update to @wOxxOm's answer, starting with Manifest v3, you cannot use background.page, but you can load the script as a module directly.

manifest.json

"background": {
    "service_worker": "background.js",
    "type": "module"
}

background.js

import Score from './score.js';

score.js

export default class Score
Trevin Avery
  • 2,751
  • 2
  • 20
  • 31
  • 1
    now it is showing `Service worker registration failed` – Sunil Garg Apr 25 '22 at 12:42
  • Looks like that happens if the background script throws an error during installation: https://stackoverflow.com/a/66115801/2463800 – Trevin Avery Apr 26 '22 at 14:06
  • @TrevinAvery what about `content.js` file? Can I import functions in it? – Volatil3 Jul 05 '22 at 13:31
  • I don't know what `content.js` is, but you can probably load it as a module, either through the background as shown above or through a script tag as shown in @wOxxOm's answer. If you do, anything you export will be accessible. So simply export the functions you want. – Trevin Avery Jul 05 '22 at 19:41
  • 4
    If someone is stuck on `Service worker registration failed` since last =one hour, the solution is to do `import Score from './score.js';` and not `import Score from './score';`. Just putting it out here . – nu_popli Aug 24 '22 at 16:38
6

ManifestV3

There are several methods:
https://stackoverflow.com/a/66408379

ManifestV2

Remove require.js and use the built-in ES modules import.

manifest.json:

"background": {
  "page": "background.html"
}

background.html, the entire file is just one line:

<script src="background.js" type="module"></script>

background.js, insert at the beginning of the file:

import Score from './score.js';

The imported script score.js, change the first line:

export default class Score

Remember that if you don't use a bundler/compiler like WebPack the file name in import must include the path (./ means "same directory") and the file extension, otherwise it won't work. A typical file extension for a module is .mjs.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • 1
    Thanks so much. I was having so much trouble importing files I thought js was just not for me. This is actually for a school project I'm doing and it's due soon. This helped me a ton and enabled me to keep coding. – CodeSlayer55 May 13 '21 at 07:08
  • (manifest V3) I get this Extension Error: Uncaught SyntaxError: Unexpected token 'export' – Alex 75 Oct 02 '22 at 11:33
  • @Alex75, this answer is for ManifestV2. See [chrome extension mv3 - Modularize service worker js file](https://stackoverflow.com/a/66408379) – wOxxOm Oct 02 '22 at 12:08